Merge "cameraservice: Migrate all internal String8/String16s to std::string" into udc-qpr-dev-plus-aosp
diff --git a/AconfigFlags.bp b/AconfigFlags.bp
new file mode 100644
index 0000000..16907b3
--- /dev/null
+++ b/AconfigFlags.bp
@@ -0,0 +1,43 @@
+// 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.
+
+// Aconfig declarations and libraries for the core framework
+java_defaults {
+    name: "framework-minus-apex-aconfig-libraries",
+
+    // Add java_aconfig_libraries to here to add them to the core framework
+    srcs: [
+        ":com.android.hardware.camera2-aconfig-java{.generated_srcjars}",
+    ],
+}
+
+// Default flags for java_aconfig_libraries that go into framework-minus-apex
+// These libraries will not work standalone
+java_defaults {
+    name: "framework-minus-apex-aconfig-java-defaults",
+    sdk_version: "core_platform",
+    libs: ["fake_device_config"],
+}
+
+aconfig_declarations {
+    name: "com.android.hardware.camera2-aconfig",
+    package: "com.android.hardware.camera2",
+    srcs: ["core/java/android/hardware/camera2/camera_platform.aconfig"],
+}
+
+java_aconfig_library {
+    name: "com.android.hardware.camera2-aconfig-java",
+    aconfig_declarations: "com.android.hardware.camera2-aconfig",
+    defaults: ["framework-minus-apex-aconfig-java-defaults"],
+}
diff --git a/Android.bp b/Android.bp
index 773528c..ccff26f 100644
--- a/Android.bp
+++ b/Android.bp
@@ -269,6 +269,7 @@
     defaults: [
         "framework-aidl-export-defaults",
         "latest_android_hardware_soundtrigger3_java_static",
+        "framework-minus-apex-aconfig-libraries",
     ],
     srcs: [
         ":framework-non-updatable-sources",
@@ -689,6 +690,7 @@
 }
 
 build = [
+    "AconfigFlags.bp",
     "ProtoLibraries.bp",
     "TestProtoLibraries.bp",
 ]
diff --git a/OWNERS b/OWNERS
index 8ee488d..6c25324 100644
--- a/OWNERS
+++ b/OWNERS
@@ -16,8 +16,6 @@
 ogunwale@google.com #{LAST_RESORT_SUGGESTION}
 roosa@google.com #{LAST_RESORT_SUGGESTION}
 smoreland@google.com #{LAST_RESORT_SUGGESTION}
-svetoslavganov@android.com #{LAST_RESORT_SUGGESTION}
-svetoslavganov@google.com #{LAST_RESORT_SUGGESTION}
 yamasani@google.com #{LAST_RESORT_SUGGESTION}
 
 # API changes are already covered by API-Review+1 (http://mdb/android-api-council)
@@ -30,7 +28,7 @@
 # Support bulk translation updates
 per-file */res*/values*/*.xml = byi@google.com, delphij@google.com
 
-per-file **.bp,**.mk = hansson@google.com
+per-file **.bp,**.mk = hansson@google.com, joeo@google.com
 per-file TestProtoLibraries.bp = file:platform/platform_testing:/libraries/health/OWNERS
 per-file TestProtoLibraries.bp = file:platform/tools/tradefederation:/OWNERS
 
diff --git a/apex/jobscheduler/framework/java/android/app/job/JobInfo.java b/apex/jobscheduler/framework/java/android/app/job/JobInfo.java
index 526e63c..8c47767 100644
--- a/apex/jobscheduler/framework/java/android/app/job/JobInfo.java
+++ b/apex/jobscheduler/framework/java/android/app/job/JobInfo.java
@@ -371,7 +371,7 @@
 
     /**
      * Allows this job to run despite doze restrictions as long as the app is in the foreground
-     * or on the temporary whitelist
+     * or on the temporary allowlist
      * @hide
      */
     public static final int FLAG_IMPORTANT_WHILE_FOREGROUND = 1 << 1;
@@ -2042,13 +2042,13 @@
 
         /**
          * Setting this to true indicates that this job is important while the scheduling app
-         * is in the foreground or on the temporary whitelist for background restrictions.
+         * is in the foreground or on the temporary allowlist for background restrictions.
          * This means that the system will relax doze restrictions on this job during this time.
          *
          * Apps should use this flag only for short jobs that are essential for the app to function
          * properly in the foreground.
          *
-         * Note that once the scheduling app is no longer whitelisted from background restrictions
+         * Note that once the scheduling app is no longer allowlisted from background restrictions
          * and in the background, or the job failed due to unsatisfied constraints,
          * this job should be expected to behave like other jobs without this flag.
          *
diff --git a/apex/jobscheduler/framework/java/android/os/PowerWhitelistManager.java b/apex/jobscheduler/framework/java/android/os/PowerWhitelistManager.java
index 4ce31e9..20da171 100644
--- a/apex/jobscheduler/framework/java/android/os/PowerWhitelistManager.java
+++ b/apex/jobscheduler/framework/java/android/os/PowerWhitelistManager.java
@@ -29,10 +29,10 @@
 import java.util.List;
 
 /**
- * Interface to access and modify the permanent and temporary power save whitelist. The two lists
- * are kept separately. Apps placed on the permanent whitelist are only removed via an explicit
- * removeFromWhitelist call. Apps whitelisted by default by the system cannot be removed. Apps
- * placed on the temporary whitelist are removed from that whitelist after a predetermined amount of
+ * Interface to access and modify the permanent and temporary power save allowlist. The two lists
+ * are kept separately. Apps placed on the permanent allowlist are only removed via an explicit
+ * removeFromAllowlist call. Apps whitelisted by default by the system cannot be removed. Apps
+ * placed on the temporary allowlist are removed from that allowlist after a predetermined amount of
  * time.
  *
  * @deprecated Use {@link PowerExemptionManager} instead
@@ -50,18 +50,18 @@
     private final PowerExemptionManager mPowerExemptionManager;
 
     /**
-     * Indicates that an unforeseen event has occurred and the app should be whitelisted to handle
+     * Indicates that an unforeseen event has occurred and the app should be allowlisted to handle
      * it.
      */
     public static final int EVENT_UNSPECIFIED = PowerExemptionManager.EVENT_UNSPECIFIED;
 
     /**
-     * Indicates that an SMS event has occurred and the app should be whitelisted to handle it.
+     * Indicates that an SMS event has occurred and the app should be allowlisted to handle it.
      */
     public static final int EVENT_SMS = PowerExemptionManager.EVENT_SMS;
 
     /**
-     * Indicates that an MMS event has occurred and the app should be whitelisted to handle it.
+     * Indicates that an MMS event has occurred and the app should be allowlisted to handle it.
      */
     public static final int EVENT_MMS = PowerExemptionManager.EVENT_MMS;
 
@@ -381,7 +381,7 @@
     }
 
     /**
-     * Add the specified package to the permanent power save whitelist.
+     * Add the specified package to the permanent power save allowlist.
      *
      * @deprecated Use {@link PowerExemptionManager#addToPermanentAllowList(String)} instead
      */
@@ -392,7 +392,7 @@
     }
 
     /**
-     * Add the specified packages to the permanent power save whitelist.
+     * Add the specified packages to the permanent power save allowlist.
      *
      * @deprecated Use {@link PowerExemptionManager#addToPermanentAllowList(List)} instead
      */
@@ -403,10 +403,10 @@
     }
 
     /**
-     * Get a list of app IDs of app that are whitelisted. This does not include temporarily
-     * whitelisted apps.
+     * Get a list of app IDs of app that are allowlisted. This does not include temporarily
+     * allowlisted apps.
      *
-     * @param includingIdle Set to true if the app should be whitelisted from device idle as well
+     * @param includingIdle Set to true if the app should be allowlisted from device idle as well
      *                      as other power save restrictions
      * @deprecated Use {@link PowerExemptionManager#getAllowListedAppIds(boolean)} instead
      * @hide
@@ -418,10 +418,10 @@
     }
 
     /**
-     * Returns true if the app is whitelisted from power save restrictions. This does not include
-     * temporarily whitelisted apps.
+     * Returns true if the app is allowlisted from power save restrictions. This does not include
+     * temporarily allowlisted apps.
      *
-     * @param includingIdle Set to true if the app should be whitelisted from device
+     * @param includingIdle Set to true if the app should be allowlisted from device
      *                      idle as well as other power save restrictions
      * @deprecated Use {@link PowerExemptionManager#isAllowListed(String, boolean)} instead
      * @hide
@@ -432,11 +432,11 @@
     }
 
     /**
-     * Remove an app from the permanent power save whitelist. Only apps that were added via
+     * Remove an app from the permanent power save allowlist. Only apps that were added via
      * {@link #addToWhitelist(String)} or {@link #addToWhitelist(List)} will be removed. Apps
-     * whitelisted by default by the system cannot be removed.
+     * allowlisted by default by the system cannot be removed.
      *
-     * @param packageName The app to remove from the whitelist
+     * @param packageName The app to remove from the allowlist
      * @deprecated Use {@link PowerExemptionManager#removeFromPermanentAllowList(String)} instead
      */
     @Deprecated
@@ -446,10 +446,10 @@
     }
 
     /**
-     * Add an app to the temporary whitelist for a short amount of time.
+     * Add an app to the temporary allowlist for a short amount of time.
      *
-     * @param packageName The package to add to the temp whitelist
-     * @param durationMs  How long to keep the app on the temp whitelist for (in milliseconds)
+     * @param packageName The package to add to the temp allowlist
+     * @param durationMs  How long to keep the app on the temp allowlist for (in milliseconds)
      * @param reasonCode one of {@link ReasonCode}, use {@link #REASON_UNKNOWN} if not sure.
      * @param reason a optional human readable reason string, could be null or empty string.
      * @deprecated Use {@link PowerExemptionManager#addToTemporaryAllowList(
@@ -463,10 +463,10 @@
     }
 
     /**
-     * Add an app to the temporary whitelist for a short amount of time.
+     * Add an app to the temporary allowlist for a short amount of time.
      *
-     * @param packageName The package to add to the temp whitelist
-     * @param durationMs  How long to keep the app on the temp whitelist for (in milliseconds)
+     * @param packageName The package to add to the temp allowlist
+     * @param durationMs  How long to keep the app on the temp allowlist for (in milliseconds)
      * @deprecated Use {@link PowerExemptionManager#addToTemporaryAllowList(
      *             String, int, String, long)} instead
      */
@@ -478,15 +478,15 @@
     }
 
     /**
-     * Add an app to the temporary whitelist for a short amount of time for a specific reason. The
-     * temporary whitelist is kept separately from the permanent whitelist and apps are
-     * automatically removed from the temporary whitelist after a predetermined amount of time.
+     * Add an app to the temporary allowlist for a short amount of time for a specific reason. The
+     * temporary allowlist is kept separately from the permanent allowlist and apps are
+     * automatically removed from the temporary allowlist after a predetermined amount of time.
      *
-     * @param packageName The package to add to the temp whitelist
-     * @param event       The reason to add the app to the temp whitelist
-     * @param reason      A human-readable reason explaining why the app is temp whitelisted. Only
+     * @param packageName The package to add to the temp allowlist
+     * @param event       The reason to add the app to the temp allowlist
+     * @param reason      A human-readable reason explaining why the app is temp allowlisted. Only
      *                    used for logging purposes. Could be null or empty string.
-     * @return The duration (in milliseconds) that the app is whitelisted for
+     * @return The duration (in milliseconds) that the app is allowlisted for
      * @deprecated Use {@link PowerExemptionManager#addToTemporaryAllowListForEvent(
      *             String, int, String, int)} instead
      */
@@ -499,16 +499,16 @@
     }
 
     /**
-     * Add an app to the temporary whitelist for a short amount of time for a specific reason. The
-     * temporary whitelist is kept separately from the permanent whitelist and apps are
-     * automatically removed from the temporary whitelist after a predetermined amount of time.
+     * Add an app to the temporary allowlist for a short amount of time for a specific reason. The
+     * temporary allowlist is kept separately from the permanent allowlist and apps are
+     * automatically removed from the temporary allowlist after a predetermined amount of time.
      *
-     * @param packageName The package to add to the temp whitelist
-     * @param event       The reason to add the app to the temp whitelist
+     * @param packageName The package to add to the temp allowlist
+     * @param event       The reason to add the app to the temp allowlist
      * @param reasonCode  one of {@link ReasonCode}, use {@link #REASON_UNKNOWN} if not sure.
-     * @param reason      A human-readable reason explaining why the app is temp whitelisted. Only
+     * @param reason      A human-readable reason explaining why the app is temp allowlisted. Only
      *                    used for logging purposes. Could be null or empty string.
-     * @return The duration (in milliseconds) that the app is whitelisted for
+     * @return The duration (in milliseconds) that the app is allowlisted for
      * @deprecated Use {@link PowerExemptionManager#addToTemporaryAllowListForEvent(
      *             String, int, String, int)} instead
      */
diff --git a/cmds/bootanimation/BootAnimation.cpp b/cmds/bootanimation/BootAnimation.cpp
index a8b6c0b..782351c 100644
--- a/cmds/bootanimation/BootAnimation.cpp
+++ b/cmds/bootanimation/BootAnimation.cpp
@@ -1523,6 +1523,7 @@
     for (size_t i=0 ; i<pcount ; i++) {
         const Animation::Part& part(animation.parts[i]);
         const size_t fcount = part.frames.size();
+        glBindTexture(GL_TEXTURE_2D, 0);
 
         // Handle animation package
         if (part.animation != nullptr) {
@@ -1599,8 +1600,10 @@
                 if (r > 0) {
                     glBindTexture(GL_TEXTURE_2D, frame.tid);
                 } else {
-                    glGenTextures(1, &frame.tid);
-                    glBindTexture(GL_TEXTURE_2D, frame.tid);
+                    if (part.count != 1) {
+                        glGenTextures(1, &frame.tid);
+                        glBindTexture(GL_TEXTURE_2D, frame.tid);
+                    }
                     int w, h;
                     // Set decoding option to alpha unpremultiplied so that the R, G, B channels
                     // of transparent pixels are preserved.
diff --git a/cmds/idmap2/libidmap2/XmlParser.cpp b/cmds/idmap2/libidmap2/XmlParser.cpp
index 70822c8..f71e6b9 100644
--- a/cmds/idmap2/libidmap2/XmlParser.cpp
+++ b/cmds/idmap2/libidmap2/XmlParser.cpp
@@ -111,7 +111,7 @@
   switch (value.dataType) {
     case Res_value::TYPE_STRING: {
       if (auto str = parser.getStrings().string8ObjectAt(value.data); str.ok()) {
-        return std::string(str->string());
+        return std::string(str->c_str());
       }
       break;
     }
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 9a5247a..ced3554 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -2892,11 +2892,6 @@
                 }
             }
 
-            final Person person = extras.getParcelable(EXTRA_MESSAGING_PERSON, Person.class);
-            if (person != null) {
-                person.visitUris(visitor);
-            }
-
             final RemoteInputHistoryItem[] history = extras.getParcelableArray(
                     Notification.EXTRA_REMOTE_INPUT_HISTORY_ITEMS,
                     RemoteInputHistoryItem.class);
@@ -2908,9 +2903,14 @@
                     }
                 }
             }
-        }
 
-        if (isStyle(MessagingStyle.class) && extras != null) {
+            // Extras for MessagingStyle. We visit them even if not isStyle(MessagingStyle), since
+            // Notification Listeners might use directly (without the isStyle check).
+            final Person person = extras.getParcelable(EXTRA_MESSAGING_PERSON, Person.class);
+            if (person != null) {
+                person.visitUris(visitor);
+            }
+
             final Parcelable[] messages = extras.getParcelableArray(EXTRA_MESSAGES,
                     Parcelable.class);
             if (!ArrayUtils.isEmpty(messages)) {
@@ -2930,9 +2930,8 @@
             }
 
             visitIconUri(visitor, extras.getParcelable(EXTRA_CONVERSATION_ICON, Icon.class));
-        }
 
-        if (isStyle(CallStyle.class) & extras != null) {
+            // Extras for CallStyle (same reason for visiting without checking isStyle).
             Person callPerson = extras.getParcelable(EXTRA_CALL_PERSON, Person.class);
             if (callPerson != null) {
                 callPerson.visitUris(visitor);
diff --git a/core/java/android/app/search/SearchSession.java b/core/java/android/app/search/SearchSession.java
index 0dbd81e..99b64a0 100644
--- a/core/java/android/app/search/SearchSession.java
+++ b/core/java/android/app/search/SearchSession.java
@@ -104,7 +104,7 @@
         mInterface = android.app.search.ISearchUiManager.Stub.asInterface(b);
         mSessionId = new SearchSessionId(
                 context.getPackageName() + ":" + UUID.randomUUID().toString(), context.getUserId());
-        // b/175527717 whitelist possible clients of this API
+        // b/175527717 allowlist possible clients of this API
         searchContext.setPackageName(context.getPackageName());
         try {
             mInterface.createSearchSession(searchContext, mSessionId, mToken);
diff --git a/core/java/android/credentials/CredentialManager.java b/core/java/android/credentials/CredentialManager.java
index c2a0062..eedb25b 100644
--- a/core/java/android/credentials/CredentialManager.java
+++ b/core/java/android/credentials/CredentialManager.java
@@ -123,7 +123,7 @@
      * credential, display a picker when multiple credentials exist, etc.
      * Callers (e.g. browsers) may optionally set origin in {@link GetCredentialRequest} for an
      * app different from their own, to be able to get credentials on behalf of that app. They would
-     * need additional permission {@link CREDENTIAL_MANAGER_SET_ORIGIN}
+     * need additional permission {@code CREDENTIAL_MANAGER_SET_ORIGIN}
      * to use this functionality
      *
      * @param context the context used to launch any UI needed; use an activity context to make sure
@@ -209,9 +209,9 @@
      *
      * <p>This API doesn't invoke any UI. It only performs the preparation work so that you can
      * later launch the remaining get-credential operation (involves UIs) through the {@link
-     * #getCredential(PrepareGetCredentialResponse.PendingGetCredentialHandle, Context,
+     * #getCredential(Context, PrepareGetCredentialResponse.PendingGetCredentialHandle,
      * CancellationSignal, Executor, OutcomeReceiver)} API which incurs less latency compared to
-     * the {@link #getCredential(GetCredentialRequest, Context, CancellationSignal, Executor,
+     * the {@link #getCredential(Context, GetCredentialRequest, CancellationSignal, Executor,
      * OutcomeReceiver)} API that executes the whole operation in one call.
      *
      * @param request            the request specifying type(s) of credentials to get from the user
@@ -261,7 +261,7 @@
      * storing the new credential, etc.
      * Callers (e.g. browsers) may optionally set origin in {@link CreateCredentialRequest} for an
      * app different from their own, to be able to get credentials on behalf of that app. They would
-     * need additional permission {@link CREDENTIAL_MANAGER_SET_ORIGIN}
+     * need additional permission {@code CREDENTIAL_MANAGER_SET_ORIGIN}
      * to use this functionality
      *
      * @param context the context used to launch any UI needed; use an activity context to make sure
diff --git a/core/java/android/hardware/camera2/CameraExtensionCharacteristics.java b/core/java/android/hardware/camera2/CameraExtensionCharacteristics.java
index 6baf91d7..ea951a5 100644
--- a/core/java/android/hardware/camera2/CameraExtensionCharacteristics.java
+++ b/core/java/android/hardware/camera2/CameraExtensionCharacteristics.java
@@ -236,9 +236,10 @@
         private static final CameraExtensionManagerGlobal GLOBAL_CAMERA_MANAGER =
                 new CameraExtensionManagerGlobal();
         private final Object mLock = new Object();
-        private final int PROXY_SERVICE_DELAY_MS = 1000;
+        private final int PROXY_SERVICE_DELAY_MS = 2000;
         private InitializerFuture mInitFuture = null;
         private ServiceConnection mConnection = null;
+        private int mConnectionCount = 0;
         private ICameraExtensionsProxyService mProxy = null;
         private boolean mSupportsAdvancedExtensions = false;
 
@@ -249,6 +250,15 @@
             return GLOBAL_CAMERA_MANAGER;
         }
 
+        private void releaseProxyConnectionLocked(Context ctx) {
+            if (mConnection != null ) {
+                ctx.unbindService(mConnection);
+                mConnection = null;
+                mProxy = null;
+                mConnectionCount = 0;
+            }
+        }
+
         private void connectToProxyLocked(Context ctx) {
             if (mConnection == null) {
                 Intent intent = new Intent();
@@ -270,7 +280,6 @@
                 mConnection = new ServiceConnection() {
                     @Override
                     public void onServiceDisconnected(ComponentName component) {
-                        mInitFuture.setStatus(false);
                         mConnection = null;
                         mProxy = null;
                     }
@@ -348,23 +357,32 @@
 
         public boolean registerClient(Context ctx, IBinder token) {
             synchronized (mLock) {
+                boolean ret = false;
                 connectToProxyLocked(ctx);
                 if (mProxy == null) {
                     return false;
                 }
+                mConnectionCount++;
 
                 try {
-                    return mProxy.registerClient(token);
+                    ret = mProxy.registerClient(token);
                 } catch (RemoteException e) {
                     Log.e(TAG, "Failed to initialize extension! Extension service does "
                             + " not respond!");
                 }
+                if (!ret) {
+                    mConnectionCount--;
+                }
 
-                return false;
+                if (mConnectionCount <= 0) {
+                    releaseProxyConnectionLocked(ctx);
+                }
+
+                return ret;
             }
         }
 
-        public void unregisterClient(IBinder token) {
+        public void unregisterClient(Context ctx, IBinder token) {
             synchronized (mLock) {
                 if (mProxy != null) {
                     try {
@@ -372,6 +390,11 @@
                     } catch (RemoteException e) {
                         Log.e(TAG, "Failed to de-initialize extension! Extension service does"
                                 + " not respond!");
+                    } finally {
+                        mConnectionCount--;
+                        if (mConnectionCount <= 0) {
+                            releaseProxyConnectionLocked(ctx);
+                        }
                     }
                 }
             }
@@ -446,8 +469,8 @@
     /**
      * @hide
      */
-    public static void unregisterClient(IBinder token) {
-        CameraExtensionManagerGlobal.get().unregisterClient(token);
+    public static void unregisterClient(Context ctx, IBinder token) {
+        CameraExtensionManagerGlobal.get().unregisterClient(ctx, token);
     }
 
     /**
@@ -578,7 +601,7 @@
                 }
             }
         } finally {
-            unregisterClient(token);
+            unregisterClient(mContext, token);
         }
 
         return Collections.unmodifiableList(ret);
@@ -626,7 +649,7 @@
             Log.e(TAG, "Failed to query the extension for postview availability! Extension "
                     + "service does not respond!");
         } finally {
-            unregisterClient(token);
+            unregisterClient(mContext, token);
         }
 
         return false;
@@ -722,7 +745,7 @@
                     + "service does not respond!");
             return Collections.emptyList();
         } finally {
-            unregisterClient(token);
+            unregisterClient(mContext, token);
         }
     }
 
@@ -791,7 +814,7 @@
                     + " not respond!");
             return new ArrayList<>();
         } finally {
-            unregisterClient(token);
+            unregisterClient(mContext, token);
         }
     }
 
@@ -872,7 +895,7 @@
                     }
                 }
             } finally {
-                unregisterClient(token);
+                unregisterClient(mContext, token);
             }
         } catch (RemoteException e) {
             Log.e(TAG, "Failed to query the extension supported sizes! Extension service does"
@@ -957,7 +980,7 @@
             Log.e(TAG, "Failed to query the extension capture latency! Extension service does"
                     + " not respond!");
         } finally {
-            unregisterClient(token);
+            unregisterClient(mContext, token);
         }
 
         return null;
@@ -998,7 +1021,7 @@
             Log.e(TAG, "Failed to query the extension progress callbacks! Extension service does"
                     + " not respond!");
         } finally {
-            unregisterClient(token);
+            unregisterClient(mContext, token);
         }
 
         return false;
@@ -1075,7 +1098,7 @@
         } catch (RemoteException e) {
             throw new IllegalStateException("Failed to query the available capture request keys!");
         } finally {
-            unregisterClient(token);
+            unregisterClient(mContext, token);
         }
 
         return Collections.unmodifiableSet(ret);
@@ -1155,7 +1178,7 @@
         } catch (RemoteException e) {
             throw new IllegalStateException("Failed to query the available capture result keys!");
         } finally {
-            unregisterClient(token);
+            unregisterClient(mContext, token);
         }
 
         return Collections.unmodifiableSet(ret);
diff --git a/core/java/android/hardware/camera2/camera_platform.aconfig b/core/java/android/hardware/camera2/camera_platform.aconfig
new file mode 100644
index 0000000..67f6300
--- /dev/null
+++ b/core/java/android/hardware/camera2/camera_platform.aconfig
@@ -0,0 +1,8 @@
+package: "com.android.hardware.camera2"
+
+flag {
+     namespace: "camera_platform"
+     name: "initial_test_flag"
+     description: "Flag infrastructure test flag"
+     bug: "292631208"
+}
diff --git a/core/java/android/hardware/camera2/impl/CameraAdvancedExtensionSessionImpl.java b/core/java/android/hardware/camera2/impl/CameraAdvancedExtensionSessionImpl.java
index e06699b..c7e74c0 100644
--- a/core/java/android/hardware/camera2/impl/CameraAdvancedExtensionSessionImpl.java
+++ b/core/java/android/hardware/camera2/impl/CameraAdvancedExtensionSessionImpl.java
@@ -90,7 +90,7 @@
     private final HashMap<Integer, ImageReader> mReaderMap = new HashMap<>();
     private RequestProcessor mRequestProcessor = new RequestProcessor();
     private final int mSessionId;
-    private final IBinder mToken;
+    private IBinder mToken = null;
 
     private Surface mClientRepeatingRequestSurface;
     private Surface mClientCaptureSurface;
@@ -103,6 +103,8 @@
     private boolean mInitialized;
     private boolean mSessionClosed;
 
+    private final Context mContext;
+
     // Lock to synchronize cross-thread access to device public interface
     final Object mInterfaceLock;
 
@@ -113,14 +115,9 @@
     public static CameraAdvancedExtensionSessionImpl createCameraAdvancedExtensionSession(
             @NonNull android.hardware.camera2.impl.CameraDeviceImpl cameraDevice,
             @NonNull Map<String, CameraCharacteristics> characteristicsMap,
-            @NonNull Context ctx, @NonNull ExtensionSessionConfiguration config, int sessionId)
+            @NonNull Context ctx, @NonNull ExtensionSessionConfiguration config, int sessionId,
+            @NonNull IBinder token)
             throws CameraAccessException, RemoteException {
-        final IBinder token = new Binder(TAG + " : " + sessionId);
-        boolean success = CameraExtensionCharacteristics.registerClient(ctx, token);
-        if (!success) {
-            throw new UnsupportedOperationException("Unsupported extension!");
-        }
-
         String cameraId = cameraDevice.getId();
         CameraExtensionCharacteristics extensionChars = new CameraExtensionCharacteristics(ctx,
                 cameraId, characteristicsMap);
@@ -204,8 +201,9 @@
         IAdvancedExtenderImpl extender = CameraExtensionCharacteristics.initializeAdvancedExtension(
                 config.getExtension());
         extender.init(cameraId, characteristicsMapNative);
-        CameraAdvancedExtensionSessionImpl ret = new CameraAdvancedExtensionSessionImpl(extender,
-                cameraDevice, characteristicsMapNative, repeatingRequestSurface,
+
+        CameraAdvancedExtensionSessionImpl ret = new CameraAdvancedExtensionSessionImpl(ctx,
+                extender, cameraDevice, characteristicsMapNative, repeatingRequestSurface,
                 burstCaptureSurface, postviewSurface, config.getStateCallback(),
                 config.getExecutor(), sessionId, token);
 
@@ -217,13 +215,16 @@
         return ret;
     }
 
-    private CameraAdvancedExtensionSessionImpl(@NonNull IAdvancedExtenderImpl extender,
+    private CameraAdvancedExtensionSessionImpl(Context ctx,
+            @NonNull IAdvancedExtenderImpl extender,
             @NonNull CameraDeviceImpl cameraDevice,
             Map<String, CameraMetadataNative> characteristicsMap,
             @Nullable Surface repeatingRequestSurface, @Nullable Surface burstCaptureSurface,
             @Nullable Surface postviewSurface,
             @NonNull StateCallback callback, @NonNull Executor executor,
-            int sessionId, @NonNull IBinder token) {
+            int sessionId,
+            @NonNull IBinder token) {
+        mContext = ctx;
         mAdvancedExtender = extender;
         mCameraDevice = cameraDevice;
         mCharacteristicsMap = characteristicsMap;
@@ -578,12 +579,16 @@
                 mSessionProcessor = null;
             }
 
-            CameraExtensionCharacteristics.unregisterClient(mToken);
-            if (mInitialized || (mCaptureSession != null)) {
-                notifyClose = true;
-                CameraExtensionCharacteristics.releaseSession();
+
+            if (mToken != null) {
+                if (mInitialized || (mCaptureSession != null)) {
+                    notifyClose = true;
+                    CameraExtensionCharacteristics.releaseSession();
+                }
+                CameraExtensionCharacteristics.unregisterClient(mContext, mToken);
             }
             mInitialized = false;
+            mToken = null;
 
             for (ImageReader reader : mReaderMap.values()) {
                 reader.close();
diff --git a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
index d3bde4b..181ab2c 100644
--- a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
+++ b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
@@ -2550,19 +2550,32 @@
         HashMap<String, CameraCharacteristics> characteristicsMap = new HashMap<>(
                 mPhysicalIdsToChars);
         characteristicsMap.put(mCameraId, mCharacteristics);
+        boolean initializationFailed = true;
+        IBinder token = new Binder(TAG + " : " + mNextSessionId++);
         try {
+            boolean ret = CameraExtensionCharacteristics.registerClient(mContext, token);
+            if (!ret) {
+                token = null;
+                throw new UnsupportedOperationException("Unsupported extension!");
+            }
+
             if (CameraExtensionCharacteristics.areAdvancedExtensionsSupported()) {
                 mCurrentAdvancedExtensionSession =
                         CameraAdvancedExtensionSessionImpl.createCameraAdvancedExtensionSession(
                                 this, characteristicsMap, mContext, extensionConfiguration,
-                                mNextSessionId++);
+                                mNextSessionId, token);
             } else {
                 mCurrentExtensionSession = CameraExtensionSessionImpl.createCameraExtensionSession(
                         this, characteristicsMap, mContext, extensionConfiguration,
-                        mNextSessionId++);
+                        mNextSessionId, token);
             }
+            initializationFailed = false;
         } catch (RemoteException e) {
             throw new CameraAccessException(CameraAccessException.CAMERA_ERROR);
+        } finally {
+            if (initializationFailed && (token != null)) {
+                CameraExtensionCharacteristics.unregisterClient(mContext, token);
+            }
         }
     }
 }
diff --git a/core/java/android/hardware/camera2/impl/CameraExtensionSessionImpl.java b/core/java/android/hardware/camera2/impl/CameraExtensionSessionImpl.java
index 5d25681..bf77681 100644
--- a/core/java/android/hardware/camera2/impl/CameraExtensionSessionImpl.java
+++ b/core/java/android/hardware/camera2/impl/CameraExtensionSessionImpl.java
@@ -91,7 +91,7 @@
     private final Set<CaptureRequest.Key> mSupportedRequestKeys;
     private final Set<CaptureResult.Key> mSupportedResultKeys;
     private final ExtensionSessionStatsAggregator mStatsAggregator;
-    private final IBinder mToken;
+    private IBinder mToken = null;
     private boolean mCaptureResultsSupported;
 
     private CameraCaptureSession mCaptureSession = null;
@@ -119,6 +119,8 @@
     // will do so internally.
     private boolean mInternalRepeatingRequestEnabled = true;
 
+    private final Context mContext;
+
     // Lock to synchronize cross-thread access to device public interface
     final Object mInterfaceLock;
 
@@ -135,14 +137,9 @@
             @NonNull Map<String, CameraCharacteristics> characteristicsMap,
             @NonNull Context ctx,
             @NonNull ExtensionSessionConfiguration config,
-            int sessionId)
+            int sessionId,
+            @NonNull IBinder token)
             throws CameraAccessException, RemoteException {
-        final IBinder token = new Binder(TAG + " : " + sessionId);
-        boolean success = CameraExtensionCharacteristics.registerClient(ctx, token);
-        if (!success) {
-            throw new UnsupportedOperationException("Unsupported extension!");
-        }
-
         String cameraId = cameraDevice.getId();
         CameraExtensionCharacteristics extensionChars = new CameraExtensionCharacteristics(ctx,
                 cameraId, characteristicsMap);
@@ -234,6 +231,7 @@
                 characteristicsMap.get(cameraId).getNativeMetadata());
 
         CameraExtensionSessionImpl session = new CameraExtensionSessionImpl(
+                ctx,
                 extenders.second,
                 extenders.first,
                 supportedPreviewSizes,
@@ -256,7 +254,7 @@
         return session;
     }
 
-    public CameraExtensionSessionImpl(@NonNull IImageCaptureExtenderImpl imageExtender,
+    public CameraExtensionSessionImpl(Context ctx, @NonNull IImageCaptureExtenderImpl imageExtender,
             @NonNull IPreviewExtenderImpl previewExtender,
             @NonNull List<Size> previewSizes,
             @NonNull android.hardware.camera2.impl.CameraDeviceImpl cameraDevice,
@@ -269,6 +267,7 @@
             @NonNull IBinder token,
             @NonNull Set<CaptureRequest.Key> requestKeys,
             @Nullable Set<CaptureResult.Key> resultKeys) {
+        mContext = ctx;
         mImageExtender = imageExtender;
         mPreviewExtender = previewExtender;
         mCameraDevice = cameraDevice;
@@ -878,12 +877,15 @@
                         + " respond!");
             }
 
-            CameraExtensionCharacteristics.unregisterClient(mToken);
-            if (mInitialized || (mCaptureSession != null)) {
-                notifyClose = true;
-                CameraExtensionCharacteristics.releaseSession();
+            if (mToken != null) {
+                if (mInitialized || (mCaptureSession != null)) {
+                    notifyClose = true;
+                    CameraExtensionCharacteristics.releaseSession();
+                }
+                CameraExtensionCharacteristics.unregisterClient(mContext, mToken);
             }
             mInitialized = false;
+            mToken = null;
 
             if (mRepeatingRequestImageCallback != null) {
                 mRepeatingRequestImageCallback.close();
diff --git a/core/java/android/hardware/display/DisplayManagerInternal.java b/core/java/android/hardware/display/DisplayManagerInternal.java
index 94bff89..4700720 100644
--- a/core/java/android/hardware/display/DisplayManagerInternal.java
+++ b/core/java/android/hardware/display/DisplayManagerInternal.java
@@ -370,8 +370,9 @@
 
     /**
      * Returns the default size of the surface associated with the display, or null if the surface
-     * is not provided for layer mirroring by SurfaceFlinger.
-     * Only used for mirroring started from MediaProjection.
+     * is not provided for layer mirroring by SurfaceFlinger. Size is rotated to reflect the current
+     * display device orientation.
+     * Used for mirroring from MediaProjection, or a physical display based on display flags.
      */
     public abstract Point getDisplaySurfaceDefaultSize(int displayId);
 
diff --git a/core/java/android/os/Build.java b/core/java/android/os/Build.java
index eb471705..509c3b8 100755
--- a/core/java/android/os/Build.java
+++ b/core/java/android/os/Build.java
@@ -1560,7 +1560,7 @@
         String attestProp = getString(
                 TextUtils.formatSimple("ro.product.%s_for_attestation", property));
         return attestProp.equals(UNKNOWN)
-                ? getString(TextUtils.formatSimple("ro.product.vendor.%s", property)) : UNKNOWN;
+                ? getString(TextUtils.formatSimple("ro.product.vendor.%s", property)) : attestProp;
     }
 
     private static String[] getStringList(String property, String separator) {
diff --git a/core/java/android/os/DropBoxManager.java b/core/java/android/os/DropBoxManager.java
index 403f55c..cf35460 100644
--- a/core/java/android/os/DropBoxManager.java
+++ b/core/java/android/os/DropBoxManager.java
@@ -364,7 +364,7 @@
     }
 
     /**
-     * Checks any blacklists (set in system settings) to see whether a certain
+     * Checks any denylists (set in system settings) to see whether a certain
      * tag is allowed.  Entries with disabled tags will be dropped immediately,
      * so you can save the work of actually constructing and sending the data.
      *
diff --git a/core/java/android/os/OWNERS b/core/java/android/os/OWNERS
index be7f276..d9a9266 100644
--- a/core/java/android/os/OWNERS
+++ b/core/java/android/os/OWNERS
@@ -10,6 +10,7 @@
 # BatteryStats
 per-file *BatteryConsumer* = file:/BATTERY_STATS_OWNERS
 per-file BatteryManager* = file:/BATTERY_STATS_OWNERS
+per-file PowerMonitor* = file:/BATTERY_STATS_OWNERS
 per-file PowerComponents.java = file:/BATTERY_STATS_OWNERS
 per-file *Stats* = file:/BATTERY_STATS_OWNERS
 
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 99b0800..3e5f40c6 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -1437,7 +1437,7 @@
 
     /**
      * Activity Action: Ask the user to allow an app to ignore battery optimizations (that is,
-     * put them on the whitelist of apps shown by
+     * put them on the allowlist of apps shown by
      * {@link #ACTION_IGNORE_BATTERY_OPTIMIZATION_SETTINGS}).  For an app to use this, it also
      * must hold the {@link android.Manifest.permission#REQUEST_IGNORE_BATTERY_OPTIMIZATIONS}
      * permission.
@@ -10498,6 +10498,14 @@
                 "assist_long_press_home_enabled";
 
         /**
+         * Whether press and hold on nav handle can trigger search.
+         *
+         * @hide
+         */
+        public static final String SEARCH_PRESS_HOLD_NAV_HANDLE_ENABLED =
+                "search_press_hold_nav_handle_enabled";
+
+        /**
          * Control whether Trust Agents are in active unlock or extend unlock mode.
          * @hide
          */
@@ -12195,7 +12203,7 @@
         public static final String BUGREPORT_IN_POWER_MENU = "bugreport_in_power_menu";
 
         /**
-         * The package name for the custom bugreport handler app. This app must be whitelisted.
+         * The package name for the custom bugreport handler app. This app must be allowlisted.
          * This is currently used only by Power Menu short press.
          * @deprecated Use {@link android.provider.Settings.Secure#CUSTOM_BUGREPORT_HANDLER_APP}
          * instead
@@ -12611,7 +12619,7 @@
                 "location_background_throttle_proximity_alert_interval_ms";
 
         /**
-         * Packages that are whitelisted for background throttling (throttling will not be applied).
+         * Packages that are allowlisted for background throttling (throttling will not be applied).
          * @hide
          */
         @Readable
@@ -12619,7 +12627,7 @@
             "location_background_throttle_package_whitelist";
 
         /**
-         * Packages that are whitelisted for ignoring location settings (may retrieve location even
+         * Packages that are allowlisted for ignoring location settings (may retrieve location even
          * when user location settings are off), for emergency purposes.
          * @deprecated No longer used from Android 12+
          * @hide
@@ -13203,7 +13211,7 @@
 
         /**
          * List of certificate (hex string representation of the application's certificate - SHA-1
-         * or SHA-256) and carrier app package pairs which are whitelisted to prompt the user for
+         * or SHA-256) and carrier app package pairs which are allowlisted to prompt the user for
          * install when a sim card with matching UICC carrier privilege rules is inserted.  The
          * certificate is used as a key, so the certificate encoding here must be the same as the
          * certificate encoding used on the SIM.
@@ -16604,7 +16612,7 @@
                 "enable_adb_incremental_install_default";
 
         /**
-         * The packages whitelisted to be run in autofill compatibility mode. The list
+         * The packages allowlisted to be run in autofill compatibility mode. The list
          * of packages is {@code ":"} colon delimited, and each entry has the name of the
          * package and an optional list of url bar resource ids (the list is delimited by
          * brackets&mdash{@code [} and {@code ]}&mdash and is also comma delimited).
@@ -16664,7 +16672,7 @@
         public static final String STYLUS_EVER_USED = "stylus_ever_used";
 
         /**
-         * Exemptions to the hidden API blacklist.
+         * Exemptions to the hidden API denylist.
          *
          * @hide
          */
diff --git a/core/java/android/service/notification/NotificationRankingUpdate.java b/core/java/android/service/notification/NotificationRankingUpdate.java
index 75640bd..f3b4c6d 100644
--- a/core/java/android/service/notification/NotificationRankingUpdate.java
+++ b/core/java/android/service/notification/NotificationRankingUpdate.java
@@ -92,6 +92,7 @@
                 mapParcel.recycle();
                 if (buffer != null) {
                     mRankingMapFd.unmap(buffer);
+                    mRankingMapFd.close();
                 }
             }
         } else {
diff --git a/core/java/android/service/voice/AlwaysOnHotwordDetector.java b/core/java/android/service/voice/AlwaysOnHotwordDetector.java
index 708ebdf..a4989af 100644
--- a/core/java/android/service/voice/AlwaysOnHotwordDetector.java
+++ b/core/java/android/service/voice/AlwaysOnHotwordDetector.java
@@ -67,6 +67,7 @@
 import com.android.internal.app.IHotwordRecognitionStatusCallback;
 import com.android.internal.app.IVoiceInteractionManagerService;
 import com.android.internal.app.IVoiceInteractionSoundTriggerSession;
+import com.android.internal.infra.AndroidFuture;
 
 import java.io.PrintWriter;
 import java.lang.annotation.Retention;
@@ -1702,6 +1703,11 @@
             Slog.i(TAG, "onProcessRestarted");
             mHandler.sendEmptyMessage(MSG_PROCESS_RESTARTED);
         }
+
+        @Override
+        public void onOpenFile(String filename, AndroidFuture future) throws RemoteException {
+            throw new UnsupportedOperationException("Hotword cannot access files from the disk.");
+        }
     }
 
     void onDetectorRemoteException() {
diff --git a/core/java/android/service/voice/HotwordDetectionService.java b/core/java/android/service/voice/HotwordDetectionService.java
index d9ee859..ccf8b67 100644
--- a/core/java/android/service/voice/HotwordDetectionService.java
+++ b/core/java/android/service/voice/HotwordDetectionService.java
@@ -227,6 +227,12 @@
         public void stopDetection() {
             HotwordDetectionService.this.onStopDetection();
         }
+
+        @Override
+        public void registerRemoteStorageService(IDetectorSessionStorageService
+                detectorSessionStorageService) {
+            throw new UnsupportedOperationException("Hotword cannot access files from the disk.");
+        }
     };
 
     @Override
diff --git a/core/java/android/service/voice/IDetectorSessionStorageService.aidl b/core/java/android/service/voice/IDetectorSessionStorageService.aidl
new file mode 100644
index 0000000..592373e
--- /dev/null
+++ b/core/java/android/service/voice/IDetectorSessionStorageService.aidl
@@ -0,0 +1,30 @@
+/*
+ * 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.service.voice;
+
+import com.android.internal.infra.AndroidFuture;
+
+/**
+ * @hide
+ */
+oneway interface IDetectorSessionStorageService {
+    /**
+     * Called when a file open request is sent. Only files with the given names under the internal
+     * app storage, i.e., {@link Context#getFilesDir()} can be opened.
+     */
+    void openFile(in String filename, in AndroidFuture future);
+}
diff --git a/core/java/android/service/voice/ISandboxedDetectionService.aidl b/core/java/android/service/voice/ISandboxedDetectionService.aidl
index 098536d..c76ac28 100644
--- a/core/java/android/service/voice/ISandboxedDetectionService.aidl
+++ b/core/java/android/service/voice/ISandboxedDetectionService.aidl
@@ -24,6 +24,7 @@
 import android.os.ParcelFileDescriptor;
 import android.os.PersistableBundle;
 import android.os.SharedMemory;
+import android.service.voice.IDetectorSessionStorageService;
 import android.service.voice.IDetectorSessionVisualQueryDetectionCallback;
 import android.service.voice.IDspHotwordDetectionCallback;
 import android.view.contentcapture.IContentCaptureManager;
@@ -71,4 +72,10 @@
     void ping(in IRemoteCallback callback);
 
     void stopDetection();
+
+    /**
+     * Registers the interface stub to talk to the voice interaction service for initialization/
+     * detection unrelated functionalities.
+     */
+    void registerRemoteStorageService(in IDetectorSessionStorageService detectorSessionStorageService);
 }
diff --git a/core/java/android/service/voice/SoftwareHotwordDetector.java b/core/java/android/service/voice/SoftwareHotwordDetector.java
index 7ab4faf..88c2111 100644
--- a/core/java/android/service/voice/SoftwareHotwordDetector.java
+++ b/core/java/android/service/voice/SoftwareHotwordDetector.java
@@ -36,6 +36,7 @@
 
 import com.android.internal.app.IHotwordRecognitionStatusCallback;
 import com.android.internal.app.IVoiceInteractionManagerService;
+import com.android.internal.infra.AndroidFuture;
 
 import java.io.PrintWriter;
 import java.util.concurrent.Executor;
@@ -299,6 +300,11 @@
             Binder.withCleanCallingIdentity(() -> mExecutor.execute(
                     () -> mCallback.onHotwordDetectionServiceRestarted()));
         }
+
+        @Override
+        public void onOpenFile(String filename, AndroidFuture future) throws RemoteException {
+            throw new UnsupportedOperationException("Hotword cannot access files from the disk.");
+        }
     }
 
     /** @hide */
diff --git a/core/java/android/service/voice/VisualQueryDetectionService.java b/core/java/android/service/voice/VisualQueryDetectionService.java
index cbe7666..d184b1e 100644
--- a/core/java/android/service/voice/VisualQueryDetectionService.java
+++ b/core/java/android/service/voice/VisualQueryDetectionService.java
@@ -40,7 +40,12 @@
 import android.view.contentcapture.ContentCaptureManager;
 import android.view.contentcapture.IContentCaptureManager;
 
+import com.android.internal.infra.AndroidFuture;
+
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
 import java.util.Objects;
+import java.util.concurrent.ExecutionException;
 import java.util.function.IntConsumer;
 
 /**
@@ -86,6 +91,8 @@
     private ContentCaptureManager mContentCaptureManager;
     @Nullable
     private IRecognitionServiceManager mIRecognitionServiceManager;
+    @Nullable
+    private IDetectorSessionStorageService mDetectorSessionStorageService;
 
 
     private final ISandboxedDetectionService mInterface = new ISandboxedDetectionService.Stub() {
@@ -154,6 +161,12 @@
         public void updateRecognitionServiceManager(IRecognitionServiceManager manager) {
             mIRecognitionServiceManager = manager;
         }
+
+        @Override
+        public void registerRemoteStorageService(IDetectorSessionStorageService
+                detectorSessionStorageService) {
+            mDetectorSessionStorageService = detectorSessionStorageService;
+        }
     };
 
     @Override
@@ -323,4 +336,23 @@
         }
     }
 
+    /**
+     * Overrides {@link Context#openFileInput} to read files with the given file names under the
+     * internal app storage of the {@link VoiceInteractionService}, i.e., only files stored in
+     * {@link Context#getFilesDir()} can be opened.
+     */
+    @Override
+    public @Nullable FileInputStream openFileInput(@NonNull String filename) throws
+            FileNotFoundException {
+        try {
+            AndroidFuture<ParcelFileDescriptor> future = new AndroidFuture<>();
+            mDetectorSessionStorageService.openFile(filename, future);
+            ParcelFileDescriptor pfd = future.get();
+            return new FileInputStream(pfd.getFileDescriptor());
+        } catch (RemoteException | ExecutionException | InterruptedException e) {
+            Log.w(TAG, "Cannot open file due to remote service failure");
+            throw new FileNotFoundException(e.getMessage());
+        }
+    }
+
 }
diff --git a/core/java/android/service/voice/VisualQueryDetector.java b/core/java/android/service/voice/VisualQueryDetector.java
index 93b7964..5d7f478 100644
--- a/core/java/android/service/voice/VisualQueryDetector.java
+++ b/core/java/android/service/voice/VisualQueryDetector.java
@@ -25,6 +25,7 @@
 import android.annotation.RequiresPermission;
 import android.annotation.SuppressLint;
 import android.annotation.SystemApi;
+import android.content.Context;
 import android.hardware.soundtrigger.SoundTrigger;
 import android.media.AudioFormat;
 import android.os.Binder;
@@ -37,7 +38,10 @@
 
 import com.android.internal.app.IHotwordRecognitionStatusCallback;
 import com.android.internal.app.IVoiceInteractionManagerService;
+import com.android.internal.infra.AndroidFuture;
 
+import java.io.File;
+import java.io.FileNotFoundException;
 import java.io.PrintWriter;
 import java.util.concurrent.Executor;
 import java.util.function.Consumer;
@@ -58,17 +62,18 @@
 
     private final Callback mCallback;
     private final Executor mExecutor;
+    private final Context mContext;
     private final IVoiceInteractionManagerService mManagerService;
     private final VisualQueryDetectorInitializationDelegate mInitializationDelegate;
 
     VisualQueryDetector(
             IVoiceInteractionManagerService managerService,
-            @NonNull @CallbackExecutor Executor executor,
-            Callback callback) {
+            @NonNull @CallbackExecutor Executor executor, Callback callback, Context context) {
         mManagerService = managerService;
         mCallback = callback;
         mExecutor = executor;
         mInitializationDelegate = new VisualQueryDetectorInitializationDelegate();
+        mContext = context;
     }
 
     /**
@@ -245,7 +250,7 @@
         @Override
         void initialize(@Nullable PersistableBundle options, @Nullable SharedMemory sharedMemory) {
             initAndVerifyDetector(options, sharedMemory,
-                    new InitializationStateListener(mExecutor, mCallback),
+                    new InitializationStateListener(mExecutor, mCallback, mContext),
                     DETECTOR_TYPE_VISUAL_QUERY_DETECTOR);
         }
 
@@ -330,9 +335,12 @@
         private final Executor mExecutor;
         private final Callback mCallback;
 
-        InitializationStateListener(Executor executor, Callback callback) {
+        private final Context mContext;
+
+        InitializationStateListener(Executor executor, Callback callback, Context context) {
             this.mExecutor = executor;
             this.mCallback = callback;
+            this.mContext = context;
         }
 
         @Override
@@ -426,5 +434,22 @@
                         !TextUtils.isEmpty(errorMessage) ? errorMessage : "Error data is null");
             }));
         }
+        @Override
+        public void onOpenFile(String filename, AndroidFuture future) throws RemoteException {
+            Slog.v(TAG, "BinderCallback#onOpenFile " + filename);
+            Binder.withCleanCallingIdentity(() -> mExecutor.execute(() -> {
+                Slog.v(TAG, "onOpenFile: " + filename);
+                File f = new File(mContext.getFilesDir(), filename);
+                ParcelFileDescriptor pfd = null;
+                try {
+                    Slog.d(TAG, "opened a file with ParcelFileDescriptor.");
+                    pfd = ParcelFileDescriptor.open(f, ParcelFileDescriptor.MODE_READ_ONLY);
+                } catch (FileNotFoundException e) {
+                    Slog.e(TAG, "Cannot open file. No ParcelFileDescriptor returned.");
+                } finally {
+                    future.complete(pfd);
+                }
+            }));
+        }
     }
 }
diff --git a/core/java/android/service/voice/VoiceInteractionService.java b/core/java/android/service/voice/VoiceInteractionService.java
index ab9ae0a..de2a99b 100644
--- a/core/java/android/service/voice/VoiceInteractionService.java
+++ b/core/java/android/service/voice/VoiceInteractionService.java
@@ -965,7 +965,7 @@
             }
 
             VisualQueryDetector visualQueryDetector =
-                    new VisualQueryDetector(mSystemService, executor, callback);
+                    new VisualQueryDetector(mSystemService, executor, callback, this);
             HotwordDetector visualQueryDetectorInitializationDelegate =
                     visualQueryDetector.getInitializationDelegate();
             mActiveDetectors.add(visualQueryDetectorInitializationDelegate);
diff --git a/core/java/android/speech/RecognitionService.java b/core/java/android/speech/RecognitionService.java
index 9656f36..7f313c1 100644
--- a/core/java/android/speech/RecognitionService.java
+++ b/core/java/android/speech/RecognitionService.java
@@ -38,6 +38,7 @@
 import android.os.RemoteException;
 import android.util.Log;
 
+import com.android.internal.annotations.GuardedBy;
 import com.android.internal.util.function.pooled.PooledLambda;
 
 import java.lang.ref.WeakReference;
@@ -232,39 +233,68 @@
                     intent,
                     attributionSource,
                     new ModelDownloadListener() {
+
+                        private final Object mLock = new Object();
+
+                        @GuardedBy("mLock")
+                        private boolean mIsTerminated = false;
+
                         @Override
                         public void onProgress(int completedPercent) {
-                            try {
-                                listener.onProgress(completedPercent);
-                            } catch (RemoteException e) {
-                                throw e.rethrowFromSystemServer();
+                            synchronized (mLock) {
+                                if (mIsTerminated) {
+                                    return;
+                                }
+                                try {
+                                    listener.onProgress(completedPercent);
+                                } catch (RemoteException e) {
+                                    throw e.rethrowFromSystemServer();
+                                }
                             }
                         }
 
                         @Override
                         public void onSuccess() {
-                            try {
-                                listener.onSuccess();
-                            } catch (RemoteException e) {
-                                throw e.rethrowFromSystemServer();
+                            synchronized (mLock) {
+                                if (mIsTerminated) {
+                                    return;
+                                }
+                                mIsTerminated = true;
+                                try {
+                                    listener.onSuccess();
+                                } catch (RemoteException e) {
+                                    throw e.rethrowFromSystemServer();
+                                }
                             }
                         }
 
                         @Override
                         public void onScheduled() {
-                            try {
-                                listener.onScheduled();
-                            } catch (RemoteException e) {
-                                throw e.rethrowFromSystemServer();
+                            synchronized (mLock) {
+                                if (mIsTerminated) {
+                                    return;
+                                }
+                                mIsTerminated = true;
+                                try {
+                                    listener.onScheduled();
+                                } catch (RemoteException e) {
+                                    throw e.rethrowFromSystemServer();
+                                }
                             }
                         }
 
                         @Override
                         public void onError(int error) {
-                            try {
-                                listener.onError(error);
-                            } catch (RemoteException e) {
-                                throw e.rethrowFromSystemServer();
+                            synchronized (mLock) {
+                                if (mIsTerminated) {
+                                    return;
+                                }
+                                mIsTerminated = true;
+                                try {
+                                    listener.onError(error);
+                                } catch (RemoteException e) {
+                                    throw e.rethrowFromSystemServer();
+                                }
                             }
                         }
                     });
diff --git a/core/java/android/view/Display.java b/core/java/android/view/Display.java
index 4b96d74..0b2b6ce 100644
--- a/core/java/android/view/Display.java
+++ b/core/java/android/view/Display.java
@@ -375,6 +375,14 @@
     public static final int FLAG_REAR = 1 << 13;
 
     /**
+     * Display flag: Indicates that the orientation of this display is not fixed and is coupled to
+     * the orientation of its content.
+     *
+     * @hide
+     */
+    public static final int FLAG_ROTATES_WITH_CONTENT = 1 << 14;
+
+    /**
      * Display flag: Indicates that the contents of the display should not be scaled
      * to fit the physical screen dimensions.  Used for development only to emulate
      * devices with smaller physicals screens while preserving density.
diff --git a/core/java/android/view/HandwritingInitiator.java b/core/java/android/view/HandwritingInitiator.java
index 4cfec99..9b34007 100644
--- a/core/java/android/view/HandwritingInitiator.java
+++ b/core/java/android/view/HandwritingInitiator.java
@@ -19,7 +19,10 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.content.Context;
+import android.graphics.Matrix;
 import android.graphics.Rect;
+import android.graphics.RectF;
+import android.graphics.Region;
 import android.view.inputmethod.InputMethodManager;
 import android.widget.TextView;
 
@@ -78,11 +81,17 @@
     private int mConnectionCount = 0;
     private final InputMethodManager mImm;
 
+    private final RectF mTempRectF = new RectF();
+
+    private final Region mTempRegion = new Region();
+
+    private final Matrix mTempMatrix = new Matrix();
+
     /**
      * The handwrite-able View that is currently the target of a hovering stylus pointer. This is
      * used to help determine whether the handwriting PointerIcon should be shown in
      * {@link #onResolvePointerIcon(Context, MotionEvent)} so that we can reduce the number of calls
-     * to {@link #findBestCandidateView(float, float)}.
+     * to {@link #findBestCandidateView(float, float, boolean)}.
      */
     @Nullable
     private WeakReference<View> mCachedHoverTarget = null;
@@ -189,8 +198,8 @@
                 final float y = motionEvent.getY(pointerIndex);
                 if (largerThanTouchSlop(x, y, mState.mStylusDownX, mState.mStylusDownY)) {
                     mState.mExceedHandwritingSlop = true;
-                    View candidateView =
-                            findBestCandidateView(mState.mStylusDownX, mState.mStylusDownY);
+                    View candidateView = findBestCandidateView(mState.mStylusDownX,
+                            mState.mStylusDownY, /* isHover */ false);
                     if (candidateView != null) {
                         if (candidateView == getConnectedView()) {
                             if (!candidateView.hasFocus()) {
@@ -398,13 +407,14 @@
             final View cachedHoverTarget = getCachedHoverTarget();
             if (cachedHoverTarget != null) {
                 final Rect handwritingArea = getViewHandwritingArea(cachedHoverTarget);
-                if (isInHandwritingArea(handwritingArea, hoverX, hoverY, cachedHoverTarget)
+                if (isInHandwritingArea(handwritingArea, hoverX, hoverY, cachedHoverTarget,
+                        /* isHover */ true)
                         && shouldTriggerStylusHandwritingForView(cachedHoverTarget)) {
                     return cachedHoverTarget;
                 }
             }
 
-            final View candidateView = findBestCandidateView(hoverX, hoverY);
+            final View candidateView = findBestCandidateView(hoverX, hoverY, /* isHover */ true);
 
             if (candidateView != null) {
                 mCachedHoverTarget = new WeakReference<>(candidateView);
@@ -434,14 +444,14 @@
      * @param y the y coordinates of the stylus event, in the coordinates of the window.
      */
     @Nullable
-    private View findBestCandidateView(float x, float y) {
+    private View findBestCandidateView(float x, float y, boolean isHover) {
         // If the connectedView is not null and do not set any handwriting area, it will check
         // whether the connectedView's boundary contains the initial stylus position. If true,
         // directly return the connectedView.
         final View connectedView = getConnectedView();
         if (connectedView != null) {
             Rect handwritingArea = getViewHandwritingArea(connectedView);
-            if (isInHandwritingArea(handwritingArea, x, y, connectedView)
+            if (isInHandwritingArea(handwritingArea, x, y, connectedView, isHover)
                     && shouldTriggerStylusHandwritingForView(connectedView)) {
                 return connectedView;
             }
@@ -455,7 +465,7 @@
         for (HandwritableViewInfo viewInfo : handwritableViewInfos) {
             final View view = viewInfo.getView();
             final Rect handwritingArea = viewInfo.getHandwritingArea();
-            if (!isInHandwritingArea(handwritingArea, x, y, view)
+            if (!isInHandwritingArea(handwritingArea, x, y, view, isHover)
                     || !shouldTriggerStylusHandwritingForView(view)) {
                 continue;
             }
@@ -551,15 +561,48 @@
      * Return true if the (x, y) is inside by the given {@link Rect} with the View's
      * handwriting bounds with offsets applied.
      */
-    private static boolean isInHandwritingArea(@Nullable Rect handwritingArea,
-            float x, float y, View view) {
+    private boolean isInHandwritingArea(@Nullable Rect handwritingArea,
+            float x, float y, View view, boolean isHover) {
         if (handwritingArea == null) return false;
 
-        return contains(handwritingArea, x, y,
+        if (!contains(handwritingArea, x, y,
                 view.getHandwritingBoundsOffsetLeft(),
                 view.getHandwritingBoundsOffsetTop(),
                 view.getHandwritingBoundsOffsetRight(),
-                view.getHandwritingBoundsOffsetBottom());
+                view.getHandwritingBoundsOffsetBottom())) {
+            return false;
+        }
+
+        // The returned handwritingArea computed by ViewParent#getChildVisibleRect didn't consider
+        // the case where a view is stacking on top of the editor. (e.g. DrawerLayout, popup)
+        // We must check the hit region of the editor again, and avoid the case where another
+        // view on top of the editor is handling MotionEvents.
+        ViewParent parent = view.getParent();
+        if (parent == null) {
+            return true;
+        }
+
+        Region region = mTempRegion;
+        mTempRegion.set(0, 0, view.getWidth(), view.getHeight());
+        Matrix matrix = mTempMatrix;
+        matrix.reset();
+        if (!parent.getChildLocalHitRegion(view, region, matrix, isHover)) {
+            return false;
+        }
+
+        // It's not easy to extend the region by the given handwritingBoundsOffset. Instead, we
+        // create a rectangle surrounding the motion event location and check if this rectangle
+        // overlaps with the hit region of the editor.
+        float left = x - view.getHandwritingBoundsOffsetRight();
+        float top = y - view.getHandwritingBoundsOffsetBottom();
+        float right = Math.max(x + view.getHandwritingBoundsOffsetLeft(), left + 1);
+        float bottom =  Math.max(y + view.getHandwritingBoundsOffsetTop(), top + 1);
+        RectF rectF = mTempRectF;
+        rectF.set(left, top, right, bottom);
+        matrix.mapRect(rectF);
+
+        return region.op(Math.round(rectF.left), Math.round(rectF.top),
+                Math.round(rectF.right), Math.round(rectF.bottom), Region.Op.INTERSECT);
     }
 
     /**
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index 1b1098d..7bdff8c 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -7361,6 +7361,90 @@
         }
     }
 
+    /**
+     * @hide
+     */
+    @Override
+    public boolean getChildLocalHitRegion(@NonNull View child, @NonNull Region region,
+            @NonNull Matrix matrix, boolean isHover) {
+        if (!child.hasIdentityMatrix()) {
+            matrix.preConcat(child.getInverseMatrix());
+        }
+
+        final int dx = child.mLeft - mScrollX;
+        final int dy = child.mTop - mScrollY;
+        matrix.preTranslate(-dx, -dy);
+
+        final int width = mRight - mLeft;
+        final int height = mBottom - mTop;
+
+        // Map the bounds of this view into the region's coordinates and clip the region.
+        final RectF rect = mAttachInfo != null ? mAttachInfo.mTmpTransformRect : new RectF();
+        rect.set(0, 0, width, height);
+        matrix.mapRect(rect);
+
+        boolean notEmpty = region.op(Math.round(rect.left), Math.round(rect.top),
+                Math.round(rect.right), Math.round(rect.bottom), Region.Op.INTERSECT);
+
+        if (isHover) {
+            HoverTarget target = mFirstHoverTarget;
+            boolean childIsHit = false;
+            while (target != null) {
+                final HoverTarget next = target.next;
+                if (target.child == child) {
+                    childIsHit = true;
+                    break;
+                }
+                target = next;
+            }
+            if (!childIsHit) {
+                target = mFirstHoverTarget;
+                while (notEmpty && target != null) {
+                    final HoverTarget next = target.next;
+                    final View hoveredView = target.child;
+
+                    rect.set(hoveredView.mLeft, hoveredView.mTop, hoveredView.mRight,
+                            hoveredView.mBottom);
+                    matrix.mapRect(rect);
+                    notEmpty = region.op(Math.round(rect.left), Math.round(rect.top),
+                            Math.round(rect.right), Math.round(rect.bottom), Region.Op.DIFFERENCE);
+                    target = next;
+                }
+            }
+        } else {
+            TouchTarget target = mFirstTouchTarget;
+            boolean childIsHit = false;
+            while (target != null) {
+                final TouchTarget next = target.next;
+                if (target.child == child) {
+                    childIsHit = true;
+                    break;
+                }
+                target = next;
+            }
+            if (!childIsHit) {
+                target = mFirstTouchTarget;
+                while (notEmpty && target != null) {
+                    final TouchTarget next = target.next;
+                    final View touchedView = target.child;
+
+                    rect.set(touchedView.mLeft, touchedView.mTop, touchedView.mRight,
+                            touchedView.mBottom);
+                    matrix.mapRect(rect);
+                    notEmpty = region.op(Math.round(rect.left), Math.round(rect.top),
+                            Math.round(rect.right), Math.round(rect.bottom), Region.Op.DIFFERENCE);
+                    target = next;
+                }
+            }
+        }
+
+        if (notEmpty && mParent != null) {
+            notEmpty = mParent.getChildLocalHitRegion(this, region, matrix, isHover);
+        }
+        return notEmpty;
+    }
+
+
     private static void applyOpToRegionByBounds(Region region, View view, Region.Op op) {
         final int[] locationInWindow = new int[2];
         view.getLocationInWindow(locationInWindow);
diff --git a/core/java/android/view/ViewParent.java b/core/java/android/view/ViewParent.java
index 1020d2e..54bc348 100644
--- a/core/java/android/view/ViewParent.java
+++ b/core/java/android/view/ViewParent.java
@@ -18,6 +18,7 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.graphics.Matrix;
 import android.graphics.Rect;
 import android.graphics.Region;
 import android.os.Bundle;
@@ -686,6 +687,36 @@
     }
 
     /**
+     * Compute the region where the child can receive the {@link MotionEvent}s from the root view.
+     *
+     * <p> Given region where the child will accept {@link MotionEvent}s.
+     * Modify the region to the unblocked region where the child can receive the
+     * {@link MotionEvent}s from the view root.
+     * </p>
+     *
+     * <p> The given region is always clipped by the bounds of the parent views. When there are
+     * on-going {@link MotionEvent}s, this method also makes use of the event dispatching results to
+     * determine whether a sibling view will also block the child's hit region.
+     * </p>
+     *
+     * @param child a child View, whose hit region we want to compute.
+     * @param region the initial hit region where the child view will handle {@link MotionEvent}s,
+     *              defined in the child coordinates. Will be overwritten to the result hit region.
+     * @param matrix the matrix that maps the given child view's coordinates to the region
+     *               coordinates. It will be modified to a matrix that maps window coordinates to
+     *               the result region's coordinates.
+     * @param isHover if true it will return the hover events' hit region, otherwise it will
+     *               return the touch events' hit region.
+     * @return true if the returned region is not empty.
+     * @hide
+     */
+    default boolean getChildLocalHitRegion(@NonNull View child, @NonNull Region region,
+            @NonNull Matrix matrix, boolean isHover) {
+        region.setEmpty();
+        return false;
+    }
+
+    /**
      * Unbuffered dispatch has been requested by a child of this view parent.
      * This method is called by the View hierarchy to signal ancestors that a View needs to
      * request unbuffered dispatch.
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 6edf0e2..c1ce5e0 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -127,6 +127,7 @@
 import android.graphics.PorterDuff;
 import android.graphics.RecordingCanvas;
 import android.graphics.Rect;
+import android.graphics.RectF;
 import android.graphics.Region;
 import android.graphics.RenderNode;
 import android.graphics.drawable.Drawable;
@@ -2393,6 +2394,22 @@
     }
 
     @Override
+    public boolean getChildLocalHitRegion(@NonNull View child, @NonNull Region region,
+            @NonNull Matrix matrix, boolean isHover) {
+        if (child != mView) {
+            throw new IllegalArgumentException("child " + child + " is not the root view "
+                    + mView + " managed by this ViewRootImpl");
+        }
+
+        RectF rectF = new RectF(0, 0, mWidth, mHeight);
+        matrix.mapRect(rectF);
+        // Note: don't apply scroll offset, because we want to know its
+        // visibility in the virtual canvas being given to the view hierarchy.
+        return region.op(Math.round(rectF.left), Math.round(rectF.top),
+                Math.round(rectF.right), Math.round(rectF.bottom), Region.Op.INTERSECT);
+    }
+
+    @Override
     public void bringChildToFront(View child) {
     }
 
diff --git a/core/java/com/android/internal/app/IHotwordRecognitionStatusCallback.aidl b/core/java/com/android/internal/app/IHotwordRecognitionStatusCallback.aidl
index 3801188..ba87caa 100644
--- a/core/java/com/android/internal/app/IHotwordRecognitionStatusCallback.aidl
+++ b/core/java/com/android/internal/app/IHotwordRecognitionStatusCallback.aidl
@@ -22,6 +22,7 @@
 import android.service.voice.HotwordRejectedResult;
 import android.service.voice.SoundTriggerFailure;
 import android.service.voice.VisualQueryDetectionServiceFailure;
+import com.android.internal.infra.AndroidFuture;
 
 /**
  * @hide
@@ -113,4 +114,9 @@
 
     /** Called when the hotword detection process is restarted */
     void onProcessRestarted();
+
+    /**
+     * Called when a file open request is sent.
+     */
+   void onOpenFile(in String filename, in AndroidFuture future);
 }
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index e5d5676..d90d5f8 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -352,7 +352,7 @@
     JNIEnv* env;
     jmethodID methodId;
 
-    ALOGD("Calling main entry %s", className.string());
+    ALOGD("Calling main entry %s", className.c_str());
 
     env = getJNIEnv();
     if (clazz == NULL || env == NULL) {
@@ -361,7 +361,7 @@
 
     methodId = env->GetStaticMethodID(clazz, "main", "([Ljava/lang/String;)V");
     if (methodId == NULL) {
-        ALOGE("ERROR: could not find method %s.main(String[])\n", className.string());
+        ALOGE("ERROR: could not find method %s.main(String[])\n", className.c_str());
         return UNKNOWN_ERROR;
     }
 
@@ -377,7 +377,7 @@
     strArray = env->NewObjectArray(numArgs, stringClass, NULL);
 
     for (size_t i = 0; i < numArgs; i++) {
-        jstring argStr = env->NewStringUTF(args[i].string());
+        jstring argStr = env->NewStringUTF(args[i].c_str());
         env->SetObjectArrayElement(strArray, i, argStr);
     }
 
@@ -1268,7 +1268,7 @@
     env->SetObjectArrayElement(strArray, 0, classNameStr);
 
     for (size_t i = 0; i < options.size(); ++i) {
-        jstring optionsStr = env->NewStringUTF(options.itemAt(i).string());
+        jstring optionsStr = env->NewStringUTF(options.itemAt(i).c_str());
         assert(optionsStr != NULL);
         env->SetObjectArrayElement(strArray, i + 1, optionsStr);
     }
diff --git a/core/jni/android_content_res_ObbScanner.cpp b/core/jni/android_content_res_ObbScanner.cpp
index de429a0..760037f 100644
--- a/core/jni/android_content_res_ObbScanner.cpp
+++ b/core/jni/android_content_res_ObbScanner.cpp
@@ -52,7 +52,7 @@
 
     env->ReleaseStringUTFChars(file, filePath);
 
-    const char* packageNameStr = obb->getPackageName().string();
+    const char* packageNameStr = obb->getPackageName().c_str();
 
     jstring packageName = env->NewStringUTF(packageNameStr);
     if (packageName == NULL) {
diff --git a/core/jni/android_hardware_SensorManager.cpp b/core/jni/android_hardware_SensorManager.cpp
index 9c6a534..deb138f 100644
--- a/core/jni/android_hardware_SensorManager.cpp
+++ b/core/jni/android_hardware_SensorManager.cpp
@@ -150,7 +150,7 @@
         return gStringOffsets.emptyString;
     }
 
-    ScopedLocalRef<jstring> javaString(env, env->NewStringUTF(string.string()));
+    ScopedLocalRef<jstring> javaString(env, env->NewStringUTF(string.c_str()));
     jstring internedString = (jstring)
             env->CallObjectMethod(javaString.get(), gStringOffsets.intern);
     return internedString;
diff --git a/core/jni/android_util_AssetManager.cpp b/core/jni/android_util_AssetManager.cpp
index a2205eb..c9a5fa6 100644
--- a/core/jni/android_util_AssetManager.cpp
+++ b/core/jni/android_util_AssetManager.cpp
@@ -273,7 +273,7 @@
   if (alloc.length() <= 0) {
     return nullptr;
   }
-  return env->NewStringUTF(alloc.string());
+  return env->NewStringUTF(alloc.c_str());
 }
 
 static jint NativeGetGlobalAssetManagerCount(JNIEnv* /*env*/, jobject /*clazz*/) {
@@ -429,7 +429,7 @@
   }
 
   for (size_t i = 0; i < file_count; i++) {
-    jstring java_string = env->NewStringUTF(asset_dir->getFileName(i).string());
+    jstring java_string = env->NewStringUTF(asset_dir->getFileName(i).c_str());
 
     // Check for errors creating the strings (if malformed or no memory).
     if (env->ExceptionCheck()) {
diff --git a/core/jni/android_view_DisplayEventReceiver.cpp b/core/jni/android_view_DisplayEventReceiver.cpp
index 624bd5f..69fc515 100644
--- a/core/jni/android_view_DisplayEventReceiver.cpp
+++ b/core/jni/android_view_DisplayEventReceiver.cpp
@@ -292,7 +292,7 @@
     if (status) {
         String8 message;
         message.appendFormat("Failed to initialize display event receiver.  status=%d", status);
-        jniThrowRuntimeException(env, message.string());
+        jniThrowRuntimeException(env, message.c_str());
         return 0;
     }
 
@@ -316,7 +316,7 @@
     if (status) {
         String8 message;
         message.appendFormat("Failed to schedule next vertical sync pulse.  status=%d", status);
-        jniThrowRuntimeException(env, message.string());
+        jniThrowRuntimeException(env, message.c_str());
     }
 }
 
diff --git a/core/jni/android_view_InputEventSender.cpp b/core/jni/android_view_InputEventSender.cpp
index 15270ef..8d39ddf 100644
--- a/core/jni/android_view_InputEventSender.cpp
+++ b/core/jni/android_view_InputEventSender.cpp
@@ -334,7 +334,7 @@
     if (status) {
         String8 message;
         message.appendFormat("Failed to initialize input event sender.  status=%d", status);
-        jniThrowRuntimeException(env, message.string());
+        jniThrowRuntimeException(env, message.c_str());
         return 0;
     }
 
diff --git a/core/proto/android/providers/settings/secure.proto b/core/proto/android/providers/settings/secure.proto
index a5d287c..481a2fb 100644
--- a/core/proto/android/providers/settings/secure.proto
+++ b/core/proto/android/providers/settings/secure.proto
@@ -137,6 +137,7 @@
         optional SettingProto gesture_setup_complete = 9 [ (android.privacy).dest = DEST_AUTOMATIC ];
         optional SettingProto touch_gesture_enabled = 10 [ (android.privacy).dest = DEST_AUTOMATIC ];
         optional SettingProto long_press_home_enabled = 11 [ (android.privacy).dest = DEST_AUTOMATIC ];
+        optional SettingProto search_press_hold_nav_handle_enabled = 12 [ (android.privacy).dest = DEST_AUTOMATIC ];
     }
     optional Assist assist = 7;
 
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 5a9a415..48ac601 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -7772,8 +7772,9 @@
                 android:process=":ui">
         </activity>
         <activity android:name="com.android.internal.app.PlatLogoActivity"
-                android:theme="@style/Theme.Wallpaper.NoTitleBar.Fullscreen"
+                android:theme="@style/Theme.NoTitleBar.Fullscreen"
                 android:configChanges="orientation|screenSize|screenLayout|keyboardHidden"
+                android:enableOnBackInvokedCallback="true"
                 android:icon="@drawable/platlogo"
                 android:process=":ui">
         </activity>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index eeaa4c7..57ca210 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -6088,6 +6088,9 @@
     <!-- Default value for Settings.ASSIST_TOUCH_GESTURE_ENABLED -->
     <bool name="config_assistTouchGestureEnabledDefault">true</bool>
 
+    <!-- Default value for Settings.SEARCH_PRESS_HOLD_NAV_HANDLE_ENABLED -->
+    <bool name="config_searchPressHoldNavHandleEnabledDefault">true</bool>
+
     <!-- The maximum byte size of the information contained in the bundle of
     HotwordDetectedResult. -->
     <integer translatable="false" name="config_hotwordDetectedResultMaxBundleSize">0</integer>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 9672ffc..85ba663 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -4865,6 +4865,8 @@
   <java-symbol type="bool" name="config_assistLongPressHomeEnabledDefault" />
   <java-symbol type="bool" name="config_assistTouchGestureEnabledDefault" />
 
+  <java-symbol type="bool" name="config_searchPressHoldNavHandleEnabledDefault" />
+
   <java-symbol type="integer" name="config_hotwordDetectedResultMaxBundleSize" />
 
   <java-symbol type="dimen" name="config_wallpaperDimAmount" />
diff --git a/core/tests/coretests/AndroidManifest.xml b/core/tests/coretests/AndroidManifest.xml
index 31755ef..a358c4f 100644
--- a/core/tests/coretests/AndroidManifest.xml
+++ b/core/tests/coretests/AndroidManifest.xml
@@ -1749,6 +1749,15 @@
                 <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
             </intent-filter>
         </activity>
+
+        <activity android:name="android.view.ViewGroupTestActivity"
+                  android:label="ViewGroup Test"
+                  android:exported="true">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+            </intent-filter>
+        </activity>
     </application>
 
     <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
diff --git a/core/tests/coretests/res/layout/viewgroup_test.xml b/core/tests/coretests/res/layout/viewgroup_test.xml
new file mode 100644
index 0000000..04f4f52
--- /dev/null
+++ b/core/tests/coretests/res/layout/viewgroup_test.xml
@@ -0,0 +1,77 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2023 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<!-- Demonstrates adding/removing views from ViewGroup. See corresponding Java code. -->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+              android:id="@+id/linear_layout"
+              android:layout_width="match_parent"
+              android:layout_height="match_parent"
+              android:orientation="vertical">
+    <EditText
+        android:id="@+id/view"
+        android:layout_width="20dp"
+        android:layout_height="10dp"
+        android:text="Hello World!"
+        android:background="#2F00FF00" />
+    <EditText
+        android:id="@+id/view_scale"
+        android:layout_width="20dp"
+        android:layout_height="10dp"
+        android:scaleX="0.5"
+        android:scaleY="2"
+        android:transformPivotX="0dp"
+        android:transformPivotY="0dp"
+        android:text="Hello World!"
+        android:background="#2F00FF00" />
+    <EditText
+        android:id="@+id/view_translate"
+        android:layout_width="20dp"
+        android:layout_height="10dp"
+        android:translationX="10dp"
+        android:translationY="20dp"
+        android:text="Hello World!"
+        android:background="#2F00FF00" />
+    <FrameLayout
+        android:layout_width="20dp"
+        android:layout_height="10dp">
+        <EditText
+            android:id="@+id/view_overlap_bottom"
+            android:layout_width="20dp"
+            android:layout_height="10dp"
+            android:text="Hello World!"/>
+        <Button
+            android:id="@+id/view_overlap_top"
+            android:layout_width="10dp"
+            android:layout_height="10dp"/>
+    </FrameLayout>
+
+    <FrameLayout
+        android:layout_width="20dp"
+        android:layout_height="10dp">
+        <EditText
+            android:id="@+id/view_cover_bottom"
+            android:layout_width="10dp"
+            android:layout_height="10dp"
+            android:text="Hello World!"/>
+        <Button
+            android:id="@+id/view_cover_top"
+            android:layout_width="10dp"
+            android:layout_height="10dp"/>
+    </FrameLayout>
+
+</LinearLayout>
diff --git a/core/tests/coretests/src/android/service/notification/NotificationRankingUpdateTest.java b/core/tests/coretests/src/android/service/notification/NotificationRankingUpdateTest.java
index a84ac55..55ded9c 100644
--- a/core/tests/coretests/src/android/service/notification/NotificationRankingUpdateTest.java
+++ b/core/tests/coretests/src/android/service/notification/NotificationRankingUpdateTest.java
@@ -136,7 +136,11 @@
         NotificationListenerService.RankingMap retrievedRankings =
                 retrievedRankingUpdate.getRankingMap();
         assertNotNull(retrievedRankings);
-        assertTrue(retrievedRankingUpdate.isFdNotNullAndClosed());
+        // The rankingUpdate file descriptor is only non-null in the new path.
+        if (SystemUiSystemPropertiesFlags.getResolver().isEnabled(
+                SystemUiSystemPropertiesFlags.NotificationFlags.RANKING_UPDATE_ASHMEM)) {
+            assertTrue(retrievedRankingUpdate.isFdNotNullAndClosed());
+        }
         NotificationListenerService.Ranking retrievedRanking =
                 new NotificationListenerService.Ranking();
         assertTrue(retrievedRankings.getRanking(TEST_KEY, retrievedRanking));
diff --git a/core/tests/coretests/src/android/view/ViewGroupGetChildLocalHitRegionTest.java b/core/tests/coretests/src/android/view/ViewGroupGetChildLocalHitRegionTest.java
new file mode 100644
index 0000000..60a0a2a
--- /dev/null
+++ b/core/tests/coretests/src/android/view/ViewGroupGetChildLocalHitRegionTest.java
@@ -0,0 +1,216 @@
+/*
+ * 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.view;
+
+import static com.google.common.truth.Truth.assertThat;
+
+
+import android.graphics.Matrix;
+import android.graphics.Region;
+import android.platform.test.annotations.Presubmit;
+import android.widget.LinearLayout;
+
+import androidx.test.ext.junit.rules.ActivityScenarioRule;
+import androidx.test.filters.SmallTest;
+
+import com.android.frameworks.coretests.R;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+
+/**
+ * Test basic functions of ViewGroup.
+ *
+ * Build/Install/Run:
+ *     atest FrameworksCoreTests:ViewGroupTest
+ */
+@Presubmit
+@SmallTest
+public class ViewGroupGetChildLocalHitRegionTest {
+    @Rule
+    public ActivityScenarioRule<ViewGroupTestActivity> mScenarioRule =
+            new ActivityScenarioRule<>(ViewGroupTestActivity.class);
+
+    private LinearLayout mRoot;
+    private final int[] mRootLocation = new int[2];
+
+    @Before
+    public void setup() {
+        mScenarioRule.getScenario().onActivity(activity -> {
+            mRoot = activity.findViewById(R.id.linear_layout);
+            mRoot.getLocationInWindow(mRootLocation);
+        });
+    }
+
+    @Test
+    public void testGetChildLocalHitRegion() {
+        assertGetChildLocalHitRegion(R.id.view);
+    }
+
+    @Test
+    public void testGetChildLocalHitRegion_withScale() {
+        assertGetChildLocalHitRegion(R.id.view_scale);
+    }
+
+    @Test
+    public void testGetChildLocalHitRegion_withTranslate() {
+        assertGetChildLocalHitRegion(R.id.view_translate);
+    }
+
+    @Test
+    public void testGetChildLocalHitRegion_overlap_noMotionEvent() {
+        assertGetChildLocalHitRegion(R.id.view_overlap_bottom);
+    }
+    @Test
+    public void testGetChildLocalHitRegion_overlap_withMotionEvent() {
+        // In this case, view_cover_bottom is partially covered by the view_cover_top.
+        // The returned region is the bounds of the bottom view subtract the bounds of the top view.
+        assertGetChildLocalHitRegion(R.id.view_overlap_top, R.id.view_overlap_bottom);
+    }
+
+    @Test
+    public void testGetChildLocalHitRegion_cover_withMotionEvent() {
+        // In this case, view_cover_bottom is completely covered by the view_cover_top.
+        // The returned region is expected to be empty.
+        assertGetChildLocalHitRegionEmpty(R.id.view_cover_top, R.id.view_cover_bottom);
+    }
+
+    private void injectMotionEvent(View view, boolean isHover) {
+        int[] location = new int[2];
+        view.getLocationInWindow(location);
+
+        float x = location[0] + view.getWidth() / 2f;
+        float y = location[1] + view.getHeight() / 2f;
+
+        int action = isHover ? MotionEvent.ACTION_HOVER_ENTER : MotionEvent.ACTION_DOWN;
+        MotionEvent motionEvent = MotionEvent.obtain(/* downtime= */ 0, /* eventTime= */ 0, action,
+                x, y, /* pressure= */ 0, /* size= */ 0, /* metaState= */ 0,
+                /* xPrecision= */ 1, /* yPrecision= */ 1, /* deviceId= */0, /* edgeFlags= */0);
+
+        View rootView = view.getRootView();
+        rootView.dispatchPointerEvent(motionEvent);
+    }
+
+    private void assertGetChildLocalHitRegion(int viewId) {
+        assertGetChildLocalHitRegion(viewId, /* isHover= */ true);
+        assertGetChildLocalHitRegion(viewId, /* isHover= */ false);
+    }
+
+    /**
+     * Assert ViewParent#getChildLocalHitRegion for a single view.
+     * @param viewId the viewId of the tested view.
+     * @param isHover if true, check the hit region of the hover events. Otherwise, check the hit
+     *                region of the touch events.
+     */
+    private void assertGetChildLocalHitRegion(int viewId, boolean isHover) {
+        mScenarioRule.getScenario().onActivity(activity -> {
+            View view = activity.findViewById(viewId);
+
+            Matrix actualMatrix = new Matrix();
+            Region actualRegion = new Region(0, 0, view.getWidth(), view.getHeight());
+            boolean actualNotEmpty = view.getParent()
+                    .getChildLocalHitRegion(view, actualRegion, actualMatrix, isHover);
+
+            int[] windowLocation = new int[2];
+            view.getLocationInWindow(windowLocation);
+            Matrix expectMatrix = new Matrix();
+            expectMatrix.preScale(1 / view.getScaleX(), 1 / view.getScaleY());
+            expectMatrix.preTranslate(-windowLocation[0], -windowLocation[1]);
+
+            Region expectRegion = new Region(0, 0, view.getWidth(), view.getHeight());
+
+            assertThat(actualNotEmpty).isTrue();
+            assertThat(actualMatrix).isEqualTo(expectMatrix);
+            assertThat(actualRegion).isEqualTo(expectRegion);
+        });
+    }
+
+    private void assertGetChildLocalHitRegion(int viewIdTop, int viewIdBottom) {
+        assertGetChildLocalHitRegion(viewIdTop, viewIdBottom, /* isHover= */ true);
+        assertGetChildLocalHitRegion(viewIdTop, viewIdBottom, /* isHover= */ false);
+    }
+
+    /**
+     * Assert ViewParent#getChildLocalHitRegion of a view that is covered by another view. It will
+     * inject {@link MotionEvent}s to the view on top first and then get the hit region of the
+     * bottom view.
+     *
+     * @param viewIdTop the view id of the test view on top.
+     * @param viewIdBottom the view id of the test view at the bottom.
+     * @param isHover if true, check the hit region of the hover events. Otherwise, check the hit
+     *                region of the touch events.
+     */
+    private void assertGetChildLocalHitRegion(int viewIdTop, int viewIdBottom, boolean isHover) {
+        mScenarioRule.getScenario().onActivity(activity -> {
+            View viewTop = activity.findViewById(viewIdTop);
+            View viewBottom = activity.findViewById(viewIdBottom);
+
+            injectMotionEvent(viewTop, isHover);
+
+            Matrix actualMatrix = new Matrix();
+            Region actualRegion = new Region(0, 0, viewBottom.getWidth(), viewBottom.getHeight());
+            boolean actualNotEmpty = viewBottom.getParent()
+                    .getChildLocalHitRegion(viewBottom, actualRegion, actualMatrix, isHover);
+
+            int[] windowLocation = new int[2];
+            viewBottom.getLocationInWindow(windowLocation);
+            Matrix expectMatrix = new Matrix();
+            expectMatrix.preTranslate(-windowLocation[0], -windowLocation[1]);
+
+            Region expectRegion = new Region(0, 0, viewBottom.getWidth(), viewBottom.getHeight());
+            expectRegion.op(0, 0, viewTop.getWidth(), viewTop.getHeight(), Region.Op.DIFFERENCE);
+
+            assertThat(actualNotEmpty).isTrue();
+            assertThat(actualMatrix).isEqualTo(expectMatrix);
+            assertThat(actualRegion).isEqualTo(expectRegion);
+        });
+    }
+
+    private void assertGetChildLocalHitRegionEmpty(int viewIdTop, int viewIdBottom) {
+        assertGetChildLocalHitRegionEmpty(viewIdTop, viewIdBottom, /* isHover= */ true);
+        assertGetChildLocalHitRegionEmpty(viewIdTop, viewIdBottom, /* isHover= */ false);
+    }
+
+    /**
+     * Assert ViewParent#getChildLocalHitRegion returns an empty region for a view that is
+     * completely covered by another view. It will inject {@link MotionEvent}s to the view on top
+     * first and then get the hit region of the
+     * bottom view.
+     *
+     * @param viewIdTop the view id of the test view on top.
+     * @param viewIdBottom the view id of the test view at the bottom.
+     * @param isHover if true, check the hit region of the hover events. Otherwise, check the hit
+     *                region of the touch events.
+     */
+    private void assertGetChildLocalHitRegionEmpty(int viewIdTop, int viewIdBottom,
+            boolean isHover) {
+        mScenarioRule.getScenario().onActivity(activity -> {
+            View viewTop = activity.findViewById(viewIdTop);
+            View viewBottom = activity.findViewById(viewIdBottom);
+
+            injectMotionEvent(viewTop, isHover);
+
+            Region actualRegion = new Region(0, 0, viewBottom.getWidth(), viewBottom.getHeight());
+            boolean actualNotEmpty = viewBottom.getParent()
+                    .getChildLocalHitRegion(viewBottom, actualRegion, new Matrix(), isHover);
+
+            assertThat(actualNotEmpty).isFalse();
+            assertThat(actualRegion.isEmpty()).isTrue();
+        });
+    }
+}
diff --git a/core/tests/coretests/src/android/view/ViewGroupTestActivity.java b/core/tests/coretests/src/android/view/ViewGroupTestActivity.java
new file mode 100644
index 0000000..b94bda5
--- /dev/null
+++ b/core/tests/coretests/src/android/view/ViewGroupTestActivity.java
@@ -0,0 +1,31 @@
+/*
+ * 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.view;
+
+import android.annotation.Nullable;
+import android.app.Activity;
+import android.os.Bundle;
+
+import com.android.frameworks.coretests.R;
+
+public class ViewGroupTestActivity extends Activity {
+    @Override
+    protected void onCreate(@Nullable Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.viewgroup_test);
+    }
+}
diff --git a/core/tests/coretests/src/android/view/stylus/HandwritingTestUtil.java b/core/tests/coretests/src/android/view/stylus/HandwritingTestUtil.java
index 388a996..b4c72ca 100644
--- a/core/tests/coretests/src/android/view/stylus/HandwritingTestUtil.java
+++ b/core/tests/coretests/src/android/view/stylus/HandwritingTestUtil.java
@@ -21,7 +21,9 @@
 
 import android.app.Instrumentation;
 import android.content.Context;
+import android.graphics.Matrix;
 import android.graphics.Rect;
+import android.graphics.Region;
 import android.view.View;
 import android.view.ViewGroup;
 
@@ -45,7 +47,7 @@
             float handwritingBoundsOffsetRight, float handwritingBoundsOffsetBottom) {
         final Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation();
         final Context context = instrumentation.getTargetContext();
-        // mock a parent so that HandwritingInitiator can get
+        // mock a parent so that HandwritingInitiator can get visible rect and hit region.
         final ViewGroup parent = new ViewGroup(context) {
             @Override
             protected void onLayout(boolean changed, int l, int t, int r, int b) {
@@ -56,6 +58,14 @@
                 r.set(handwritingArea);
                 return true;
             }
+
+            @Override
+            public boolean getChildLocalHitRegion(View child, Region region, Matrix matrix,
+                    boolean isHover) {
+                matrix.reset();
+                region.set(handwritingArea);
+                return true;
+            }
         };
 
         View view = spy(new View(context));
diff --git a/libs/WindowManager/Shell/res/layout/bubble_bar_manage_education.xml b/libs/WindowManager/Shell/res/layout/bubble_bar_manage_education.xml
new file mode 100644
index 0000000..a0a06f1
--- /dev/null
+++ b/libs/WindowManager/Shell/res/layout/bubble_bar_manage_education.xml
@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2023 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+  -->
+<com.android.wm.shell.common.bubbles.BubblePopupView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="wrap_content"
+    android:layout_height="wrap_content"
+    android:layout_gravity="center_horizontal"
+    android:layout_marginHorizontal="@dimen/bubble_popup_margin_horizontal"
+    android:layout_marginTop="@dimen/bubble_popup_margin_top"
+    android:elevation="@dimen/bubble_manage_menu_elevation"
+    android:gravity="center_horizontal"
+    android:orientation="vertical">
+
+    <ImageView
+        android:layout_width="32dp"
+        android:layout_height="32dp"
+        android:tint="?android:attr/colorAccent"
+        android:contentDescription="@null"
+        android:src="@drawable/pip_ic_settings"/>
+
+    <TextView
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginTop="16dp"
+        android:maxWidth="@dimen/bubble_popup_content_max_width"
+        android:maxLines="1"
+        android:ellipsize="end"
+        android:textAppearance="@android:style/TextAppearance.DeviceDefault.Headline"
+        android:textColor="?android:attr/textColorPrimary"
+        android:text="@string/bubble_bar_education_manage_title"/>
+
+    <TextView
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginTop="16dp"
+        android:maxWidth="@dimen/bubble_popup_content_max_width"
+        android:textAppearance="@android:style/TextAppearance.DeviceDefault"
+        android:textColor="?android:attr/textColorSecondary"
+        android:textAlignment="center"
+        android:text="@string/bubble_bar_education_manage_text"/>
+
+</com.android.wm.shell.common.bubbles.BubblePopupView>
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/res/values/dimen.xml b/libs/WindowManager/Shell/res/values/dimen.xml
index 0502a99..63a9723 100644
--- a/libs/WindowManager/Shell/res/values/dimen.xml
+++ b/libs/WindowManager/Shell/res/values/dimen.xml
@@ -226,6 +226,20 @@
     <dimen name="bubble_user_education_padding_end">58dp</dimen>
     <!-- Padding between the bubble and the user education text. -->
     <dimen name="bubble_user_education_stack_padding">16dp</dimen>
+    <!-- Max width for the bubble popup view. -->
+    <dimen name="bubble_popup_content_max_width">300dp</dimen>
+    <!-- Horizontal margin for the bubble popup view. -->
+    <dimen name="bubble_popup_margin_horizontal">32dp</dimen>
+    <!-- Top margin for the bubble popup view. -->
+    <dimen name="bubble_popup_margin_top">16dp</dimen>
+    <!-- Width for the bubble popup view arrow. -->
+    <dimen name="bubble_popup_arrow_width">12dp</dimen>
+    <!-- Height for the bubble popup view arrow. -->
+    <dimen name="bubble_popup_arrow_height">10dp</dimen>
+    <!-- Corner radius for the bubble popup view arrow. -->
+    <dimen name="bubble_popup_arrow_corner_radius">2dp</dimen>
+    <!-- Padding for the bubble popup view contents. -->
+    <dimen name="bubble_popup_padding">24dp</dimen>
     <!-- The size of the caption bar inset at the top of bubble bar expanded view. -->
     <dimen name="bubble_bar_expanded_view_caption_height">32dp</dimen>
     <!-- The height of the dots shown for the caption menu in the bubble bar expanded view.. -->
diff --git a/libs/WindowManager/Shell/res/values/strings.xml b/libs/WindowManager/Shell/res/values/strings.xml
index 8cbc3d0..00c63d7 100644
--- a/libs/WindowManager/Shell/res/values/strings.xml
+++ b/libs/WindowManager/Shell/res/values/strings.xml
@@ -163,6 +163,11 @@
     <!-- [CHAR LIMIT=NONE] Empty overflow subtitle -->
     <string name="bubble_overflow_empty_subtitle">Recent bubbles and dismissed bubbles will appear here</string>
 
+    <!-- Title text for the bubble bar "manage" button tool tip highlighting where users can go to control bubble settings. [CHAR LIMIT=60]-->
+    <string name="bubble_bar_education_manage_title">Control bubbles anytime</string>
+    <!-- Descriptive text for the bubble bar "manage" button tool tip highlighting where users can go to control bubble settings. [CHAR LIMIT=80]-->
+    <string name="bubble_bar_education_manage_text">Tap here to manage which apps and conversations can bubble</string>
+
     <!-- [CHAR LIMIT=100] Notification Importance title -->
     <string name="notification_bubble_title">Bubble</string>
 
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubble.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubble.java
index 7e09c98..ff67110 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubble.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubble.java
@@ -60,7 +60,6 @@
 /**
  * Encapsulates the data and UI elements of a bubble.
  */
-@VisibleForTesting
 public class Bubble implements BubbleViewProvider {
     private static final String TAG = "Bubble";
 
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleEducationController.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleEducationController.kt
new file mode 100644
index 0000000..e57f02c
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleEducationController.kt
@@ -0,0 +1,74 @@
+/*
+ * 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.wm.shell.bubbles
+
+import android.content.Context
+import android.util.Log
+import androidx.core.content.edit
+import com.android.wm.shell.bubbles.BubbleDebugConfig.DEBUG_USER_EDUCATION
+import com.android.wm.shell.bubbles.BubbleDebugConfig.TAG_BUBBLES
+import com.android.wm.shell.bubbles.BubbleDebugConfig.TAG_WITH_CLASS_NAME
+
+/** Manages bubble education flags. Provides convenience methods to check the education state */
+class BubbleEducationController(private val context: Context) {
+    private val prefs = context.getSharedPreferences(context.packageName, Context.MODE_PRIVATE)
+
+    /** Whether the user has seen the stack education */
+    @get:JvmName(name = "hasSeenStackEducation")
+    var hasSeenStackEducation: Boolean
+        get() = prefs.getBoolean(PREF_STACK_EDUCATION, false)
+        set(value) = prefs.edit { putBoolean(PREF_STACK_EDUCATION, value) }
+
+    /** Whether the user has seen the expanded view "manage" menu education */
+    @get:JvmName(name = "hasSeenManageEducation")
+    var hasSeenManageEducation: Boolean
+        get() = prefs.getBoolean(PREF_MANAGED_EDUCATION, false)
+        set(value) = prefs.edit { putBoolean(PREF_MANAGED_EDUCATION, value) }
+
+    /** Whether education view should show for the collapsed stack. */
+    fun shouldShowStackEducation(bubble: BubbleViewProvider?): Boolean {
+        val shouldShow = bubble != null &&
+                bubble.isConversationBubble && // show education for conversation bubbles only
+                (!hasSeenStackEducation || BubbleDebugConfig.forceShowUserEducation(context))
+        logDebug("Show stack edu: $shouldShow")
+        return shouldShow
+    }
+
+    /** Whether the educational view should show for the expanded view "manage" menu. */
+    fun shouldShowManageEducation(bubble: BubbleViewProvider?): Boolean {
+        val shouldShow = bubble != null &&
+                bubble.isConversationBubble && // show education for conversation bubbles only
+                (!hasSeenManageEducation || BubbleDebugConfig.forceShowUserEducation(context))
+        logDebug("Show manage edu: $shouldShow")
+        return shouldShow
+    }
+
+    private fun logDebug(message: String) {
+        if (DEBUG_USER_EDUCATION) {
+            Log.d(TAG, message)
+        }
+    }
+
+    companion object {
+        private val TAG = if (TAG_WITH_CLASS_NAME) "BubbleEducationController" else TAG_BUBBLES
+        const val PREF_STACK_EDUCATION: String = "HasSeenBubblesOnboarding"
+        const val PREF_MANAGED_EDUCATION: String = "HasSeenBubblesManageOnboarding"
+    }
+}
+
+/** Convenience extension method to check if the bubble is a conversation bubble */
+private val BubbleViewProvider.isConversationBubble: Boolean
+    get() = if (this is Bubble) isConversation else false
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePopupViewExt.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePopupViewExt.kt
new file mode 100644
index 0000000..bdb09e1
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePopupViewExt.kt
@@ -0,0 +1,47 @@
+/*
+ * 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.wm.shell.bubbles
+
+import android.graphics.Color
+import com.android.wm.shell.R
+import com.android.wm.shell.common.bubbles.BubblePopupDrawable
+import com.android.wm.shell.common.bubbles.BubblePopupView
+
+/**
+ * A convenience method to setup the [BubblePopupView] with the correct config using local resources
+ */
+fun BubblePopupView.setup() {
+    val attrs =
+        context.obtainStyledAttributes(
+            intArrayOf(
+                com.android.internal.R.attr.materialColorSurface,
+                android.R.attr.dialogCornerRadius
+            )
+        )
+
+    val res = context.resources
+    val config =
+        BubblePopupDrawable.Config(
+            color = attrs.getColor(0, Color.WHITE),
+            cornerRadius = attrs.getDimension(1, 0f),
+            contentPadding = res.getDimensionPixelSize(R.dimen.bubble_popup_padding),
+            arrowWidth = res.getDimension(R.dimen.bubble_popup_arrow_width),
+            arrowHeight = res.getDimension(R.dimen.bubble_popup_arrow_height),
+            arrowRadius = res.getDimension(R.dimen.bubble_popup_arrow_corner_radius)
+        )
+    attrs.recycle()
+    setupBackground(config)
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java
index da5974f..8ae12c7 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java
@@ -46,7 +46,6 @@
 import android.graphics.RectF;
 import android.graphics.drawable.ColorDrawable;
 import android.os.Bundle;
-import android.os.SystemProperties;
 import android.provider.Settings;
 import android.util.Log;
 import android.view.Choreographer;
@@ -108,12 +107,6 @@
  */
 public class BubbleStackView extends FrameLayout
         implements ViewTreeObserver.OnComputeInternalInsetsListener {
-
-    // LINT.IfChange
-    public static final boolean ENABLE_FLING_TO_DISMISS_BUBBLE =
-            SystemProperties.getBoolean("persist.wm.debug.fling_to_dismiss_bubble", true);
-    // LINT.ThenChange(com/android/launcher3/taskbar/bubbles/BubbleDismissController.java)
-
     private static final String TAG = TAG_WITH_CLASS_NAME ? "BubbleStackView" : TAG_BUBBLES;
 
     /** How far the flyout needs to be dragged before it's dismissed regardless of velocity. */
@@ -138,7 +131,7 @@
 
     private static final int EXPANDED_VIEW_ALPHA_ANIMATION_DURATION = 150;
 
-    private static final float SCRIM_ALPHA = 0.6f;
+    private static final float SCRIM_ALPHA = 0.32f;
 
     /** Minimum alpha value for scrim when alpha is being changed via drag */
     private static final float MIN_SCRIM_ALPHA_FOR_DRAG = 0.2f;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/ExpandedAnimationController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/ExpandedAnimationController.java
index 33629f9..c20733a 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/ExpandedAnimationController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/ExpandedAnimationController.java
@@ -19,7 +19,6 @@
 import static android.view.View.LAYOUT_DIRECTION_RTL;
 
 import static com.android.wm.shell.bubbles.BubblePositioner.NUM_VISIBLE_WHEN_RESTING;
-import static com.android.wm.shell.bubbles.BubbleStackView.ENABLE_FLING_TO_DISMISS_BUBBLE;
 
 import android.content.res.Resources;
 import android.graphics.Path;
@@ -355,7 +354,6 @@
         mMagnetizedBubbleDraggingOut.setMagnetListener(listener);
         mMagnetizedBubbleDraggingOut.setHapticsEnabled(true);
         mMagnetizedBubbleDraggingOut.setFlingToTargetMinVelocity(FLING_TO_DISMISS_MIN_VELOCITY);
-        mMagnetizedBubbleDraggingOut.setFlingToTargetEnabled(ENABLE_FLING_TO_DISMISS_BUBBLE);
     }
 
     private void springBubbleTo(View bubble, float x, float y) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/StackAnimationController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/StackAnimationController.java
index 5533842..4bb1ab4 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/StackAnimationController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/StackAnimationController.java
@@ -17,7 +17,6 @@
 package com.android.wm.shell.bubbles.animation;
 
 import static com.android.wm.shell.bubbles.BubblePositioner.NUM_VISIBLE_WHEN_RESTING;
-import static com.android.wm.shell.bubbles.BubbleStackView.ENABLE_FLING_TO_DISMISS_BUBBLE;
 
 import android.content.ContentResolver;
 import android.content.res.Resources;
@@ -1026,7 +1025,6 @@
             };
             mMagnetizedStack.setHapticsEnabled(true);
             mMagnetizedStack.setFlingToTargetMinVelocity(FLING_TO_DISMISS_MIN_VELOCITY);
-            mMagnetizedStack.setFlingToTargetEnabled(ENABLE_FLING_TO_DISMISS_BUBBLE);
         }
 
         final ContentResolver contentResolver = mLayout.getContext().getContentResolver();
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarExpandedView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarExpandedView.java
index 6b6d6ba..79f188a 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarExpandedView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarExpandedView.java
@@ -39,7 +39,6 @@
 import com.android.wm.shell.bubbles.Bubbles;
 import com.android.wm.shell.taskview.TaskView;
 
-import java.util.function.Consumer;
 import java.util.function.Supplier;
 
 /**
@@ -48,6 +47,18 @@
  * {@link BubbleController#isShowingAsBubbleBar()}
  */
 public class BubbleBarExpandedView extends FrameLayout implements BubbleTaskViewHelper.Listener {
+    /**
+     * The expanded view listener notifying the {@link BubbleBarLayerView} about the internal
+     * actions and events
+     */
+    public interface Listener {
+        /** Called when the task view task is first created. */
+        void onTaskCreated();
+        /** Called when expanded view needs to un-bubble the given conversation */
+        void onUnBubbleConversation(String bubbleKey);
+        /** Called when expanded view task view back button pressed */
+        void onBackPressed();
+    }
 
     private static final String TAG = BubbleBarExpandedView.class.getSimpleName();
     private static final int INVALID_TASK_ID = -1;
@@ -57,7 +68,7 @@
     private BubbleTaskViewHelper mBubbleTaskViewHelper;
     private BubbleBarMenuViewController mMenuViewController;
     private @Nullable Supplier<Rect> mLayerBoundsSupplier;
-    private @Nullable Consumer<String> mUnBubbleConversationCallback;
+    private @Nullable Listener mListener;
 
     private BubbleBarHandleView mHandleView = new BubbleBarHandleView(getContext());
     private @Nullable TaskView mTaskView;
@@ -145,15 +156,13 @@
         mMenuViewController.setListener(new BubbleBarMenuViewController.Listener() {
             @Override
             public void onMenuVisibilityChanged(boolean visible) {
-                if (mTaskView == null || mLayerBoundsSupplier == null) return;
-                // Updates the obscured touchable region for the task surface.
-                mTaskView.setObscuredTouchRect(visible ? mLayerBoundsSupplier.get() : null);
+                setObscured(visible);
             }
 
             @Override
             public void onUnBubbleConversation(Bubble bubble) {
-                if (mUnBubbleConversationCallback != null) {
-                    mUnBubbleConversationCallback.accept(bubble.getKey());
+                if (mListener != null) {
+                    mListener.onUnBubbleConversation(bubble.getKey());
                 }
             }
 
@@ -231,6 +240,9 @@
     public void onTaskCreated() {
         setContentVisibility(true);
         updateHandleColor(false /* animated */);
+        if (mListener != null) {
+            mListener.onTaskCreated();
+        }
     }
 
     @Override
@@ -240,7 +252,8 @@
 
     @Override
     public void onBackPressed() {
-        mController.collapseStack();
+        if (mListener == null) return;
+        mListener.onBackPressed();
     }
 
     /** Cleans up task view, should be called when the bubble is no longer active. */
@@ -254,6 +267,18 @@
         mMenuViewController.hideMenu(false /* animated */);
     }
 
+    /**
+     * Hides the current modal menu view or collapses the bubble stack.
+     * Called from {@link BubbleBarLayerView}
+     */
+    public void hideMenuOrCollapse() {
+        if (mMenuViewController.isMenuVisible()) {
+            mMenuViewController.hideMenu(/* animated = */ true);
+        } else {
+            mController.collapseStack();
+        }
+    }
+
     /** Updates the bubble shown in the expanded view. */
     public void update(Bubble bubble) {
         mBubbleTaskViewHelper.update(bubble);
@@ -270,10 +295,16 @@
         mLayerBoundsSupplier = supplier;
     }
 
-    /** Sets the function to call to un-bubble the given conversation. */
-    public void setUnBubbleConversationCallback(
-            @Nullable Consumer<String> unBubbleConversationCallback) {
-        mUnBubbleConversationCallback = unBubbleConversationCallback;
+    /** Sets expanded view listener */
+    void setListener(@Nullable Listener listener) {
+        mListener = listener;
+    }
+
+    /** Sets whether the view is obscured by some modal view */
+    void setObscured(boolean obscured) {
+        if (mTaskView == null || mLayerBoundsSupplier == null) return;
+        // Updates the obscured touchable region for the task surface.
+        mTaskView.setObscuredTouchRect(obscured ? mLayerBoundsSupplier.get() : null);
     }
 
     /**
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarLayerView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarLayerView.java
index bc04bfc..8f11253 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarLayerView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarLayerView.java
@@ -52,6 +52,7 @@
     private final BubbleController mBubbleController;
     private final BubblePositioner mPositioner;
     private final BubbleBarAnimationHelper mAnimationHelper;
+    private final BubbleEducationViewController mEducationViewController;
     private final View mScrimView;
 
     @Nullable
@@ -80,6 +81,10 @@
 
         mAnimationHelper = new BubbleBarAnimationHelper(context,
                 this, mPositioner);
+        mEducationViewController = new BubbleEducationViewController(context, (boolean visible) -> {
+            if (mExpandedView == null) return;
+            mExpandedView.setObscured(visible);
+        });
 
         mScrimView = new View(getContext());
         mScrimView.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO);
@@ -90,9 +95,7 @@
         mScrimView.setBackgroundDrawable(new ColorDrawable(
                 getResources().getColor(android.R.color.system_neutral1_1000)));
 
-        setOnClickListener(view -> {
-            mBubbleController.collapseStack();
-        });
+        setOnClickListener(view -> hideMenuOrCollapse());
     }
 
     @Override
@@ -108,6 +111,7 @@
         getViewTreeObserver().removeOnComputeInternalInsetsListener(this);
 
         if (mExpandedView != null) {
+            mEducationViewController.hideManageEducation(/* animated = */ false);
             removeView(mExpandedView);
             mExpandedView = null;
         }
@@ -162,14 +166,27 @@
             final int width = mPositioner.getExpandedViewWidthForBubbleBar(isOverflowExpanded);
             final int height = mPositioner.getExpandedViewHeightForBubbleBar(isOverflowExpanded);
             mExpandedView.setVisibility(GONE);
-            mExpandedView.setUnBubbleConversationCallback(mUnBubbleConversationCallback);
+            mExpandedView.setY(mPositioner.getExpandedViewBottomForBubbleBar() - height);
             mExpandedView.setLayerBoundsSupplier(() -> new Rect(0, 0, getWidth(), getHeight()));
-            mExpandedView.setUnBubbleConversationCallback(bubbleKey -> {
-                if (mUnBubbleConversationCallback != null) {
-                    mUnBubbleConversationCallback.accept(bubbleKey);
+            mExpandedView.setListener(new BubbleBarExpandedView.Listener() {
+                @Override
+                public void onTaskCreated() {
+                    mEducationViewController.maybeShowManageEducation(b, mExpandedView);
+                }
+
+                @Override
+                public void onUnBubbleConversation(String bubbleKey) {
+                    if (mUnBubbleConversationCallback != null) {
+                        mUnBubbleConversationCallback.accept(bubbleKey);
+                    }
+                }
+
+                @Override
+                public void onBackPressed() {
+                    hideMenuOrCollapse();
                 }
             });
-            mExpandedView.setY(mPositioner.getExpandedViewBottomForBubbleBar() - height);
+
             addView(mExpandedView, new FrameLayout.LayoutParams(width, height));
         }
 
@@ -193,6 +210,7 @@
     public void collapse() {
         mIsExpanded = false;
         final BubbleBarExpandedView viewToRemove = mExpandedView;
+        mEducationViewController.hideManageEducation(/* animated = */ true);
         mAnimationHelper.animateCollapse(() -> removeView(viewToRemove));
         mBubbleController.getSysuiProxy().onStackExpandChanged(false);
         mExpandedView = null;
@@ -206,6 +224,17 @@
         mUnBubbleConversationCallback = unBubbleConversationCallback;
     }
 
+    /** Hides the current modal education/menu view, expanded view or collapses the bubble stack */
+    private void hideMenuOrCollapse() {
+        if (mEducationViewController.isManageEducationVisible()) {
+            mEducationViewController.hideManageEducation(/* animated = */ true);
+        } else if (isExpanded() && mExpandedView != null) {
+            mExpandedView.hideMenuOrCollapse();
+        } else {
+            mBubbleController.collapseStack();
+        }
+    }
+
     /** Updates the expanded view size and position. */
     private void updateExpandedView() {
         if (mExpandedView == null) return;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarMenuViewController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarMenuViewController.java
index 8be140c..81e7582 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarMenuViewController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarMenuViewController.java
@@ -56,6 +56,11 @@
                 SpringForce.STIFFNESS_MEDIUM, SpringForce.DAMPING_RATIO_LOW_BOUNCY);
     }
 
+    /** Tells if the menu is visible or being animated */
+    boolean isMenuVisible() {
+        return mMenuView != null && mMenuView.getVisibility() == View.VISIBLE;
+    }
+
     /** Sets menu actions listener */
     void setListener(@Nullable Listener listener) {
         mListener = listener;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleEducationViewController.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleEducationViewController.kt
new file mode 100644
index 0000000..7b39c6f
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleEducationViewController.kt
@@ -0,0 +1,148 @@
+/*
+ * 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.wm.shell.bubbles.bar
+
+import android.content.Context
+import android.view.LayoutInflater
+import android.view.ViewGroup
+import androidx.core.view.doOnLayout
+import androidx.dynamicanimation.animation.DynamicAnimation
+import androidx.dynamicanimation.animation.SpringForce
+import com.android.wm.shell.R
+import com.android.wm.shell.animation.PhysicsAnimator
+import com.android.wm.shell.bubbles.BubbleEducationController
+import com.android.wm.shell.bubbles.BubbleViewProvider
+import com.android.wm.shell.bubbles.setup
+import com.android.wm.shell.common.bubbles.BubblePopupView
+
+/** Manages bubble education presentation and animation */
+class BubbleEducationViewController(private val context: Context, private val listener: Listener) {
+    interface Listener {
+        fun onManageEducationVisibilityChanged(isVisible: Boolean)
+    }
+
+    private var rootView: ViewGroup? = null
+    private var educationView: BubblePopupView? = null
+    private var animator: PhysicsAnimator<BubblePopupView>? = null
+
+    private val springConfig by lazy {
+        PhysicsAnimator.SpringConfig(
+            SpringForce.STIFFNESS_MEDIUM,
+            SpringForce.DAMPING_RATIO_LOW_BOUNCY
+        )
+    }
+
+    private val controller by lazy { BubbleEducationController(context) }
+
+    /** Whether the education view is visible or being animated */
+    val isManageEducationVisible: Boolean
+        get() = educationView != null && rootView != null
+
+    /**
+     * Show manage bubble education if hasn't been shown before
+     *
+     * @param bubble the bubble used for the manage education check
+     * @param root the view to show manage education in
+     */
+    fun maybeShowManageEducation(bubble: BubbleViewProvider, root: ViewGroup) {
+        if (!controller.shouldShowManageEducation(bubble)) return
+        showManageEducation(root)
+    }
+
+    /**
+     * Hide the manage education view if visible
+     *
+     * @param animated whether should hide with animation
+     */
+    fun hideManageEducation(animated: Boolean) {
+        rootView?.let {
+            fun cleanUp() {
+                it.removeView(educationView)
+                rootView = null
+                listener.onManageEducationVisibilityChanged(isVisible = false)
+            }
+
+            if (animated) {
+                animateTransition(show = false, ::cleanUp)
+            } else {
+                cleanUp()
+            }
+        }
+    }
+
+    /**
+     * Show manage education with animation
+     *
+     * @param root the view to show manage education in
+     */
+    private fun showManageEducation(root: ViewGroup) {
+        hideManageEducation(animated = false)
+        if (educationView == null) {
+            val eduView = createEducationView(root)
+            educationView = eduView
+            animator = createAnimation(eduView)
+        }
+        root.addView(educationView)
+        rootView = root
+        animateTransition(show = true) {
+            controller.hasSeenManageEducation = true
+            listener.onManageEducationVisibilityChanged(isVisible = true)
+        }
+    }
+
+    /**
+     * Animate show/hide transition for the education view
+     *
+     * @param show whether to show or hide the view
+     * @param endActions a closure to be called when the animation completes
+     */
+    private fun animateTransition(show: Boolean, endActions: () -> Unit) {
+        animator?.let { animator ->
+            animator
+                .spring(DynamicAnimation.ALPHA, if (show) 1f else 0f)
+                .spring(DynamicAnimation.SCALE_X, if (show) 1f else EDU_SCALE_HIDDEN)
+                .spring(DynamicAnimation.SCALE_Y, if (show) 1f else EDU_SCALE_HIDDEN)
+                .withEndActions(endActions)
+                .start()
+        } ?: endActions()
+    }
+
+    private fun createEducationView(root: ViewGroup): BubblePopupView {
+        val view =
+            LayoutInflater.from(context).inflate(R.layout.bubble_bar_manage_education, root, false)
+                as BubblePopupView
+
+        return view.apply {
+            setup()
+            alpha = 0f
+            pivotY = 0f
+            scaleX = EDU_SCALE_HIDDEN
+            scaleY = EDU_SCALE_HIDDEN
+            doOnLayout { it.pivotX = it.width / 2f }
+            setOnClickListener { hideManageEducation(animated = true) }
+        }
+    }
+
+    private fun createAnimation(view: BubblePopupView): PhysicsAnimator<BubblePopupView> {
+        val animator = PhysicsAnimator.getInstance(view)
+        animator.setDefaultSpringConfig(springConfig)
+        return animator
+    }
+
+    companion object {
+        private const val EDU_SCALE_HIDDEN = 0.5f
+    }
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/bubbles/BubblePopupDrawable.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/common/bubbles/BubblePopupDrawable.kt
new file mode 100644
index 0000000..8b5283d
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/bubbles/BubblePopupDrawable.kt
@@ -0,0 +1,232 @@
+/*
+ * 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.wm.shell.common.bubbles
+
+import android.annotation.ColorInt
+import android.graphics.Canvas
+import android.graphics.ColorFilter
+import android.graphics.Matrix
+import android.graphics.Outline
+import android.graphics.Paint
+import android.graphics.Path
+import android.graphics.Rect
+import android.graphics.RectF
+import android.graphics.drawable.Drawable
+import kotlin.math.atan
+import kotlin.math.cos
+import kotlin.math.sin
+import kotlin.properties.Delegates
+
+/** A drawable for the [BubblePopupView] that draws a popup background with a directional arrow */
+class BubblePopupDrawable(private val config: Config) : Drawable() {
+    /** The direction of the arrow in the popup drawable */
+    enum class ArrowDirection {
+        UP,
+        DOWN
+    }
+
+    /** The arrow position on the side of the popup bubble */
+    sealed class ArrowPosition {
+        object Start : ArrowPosition()
+        object Center : ArrowPosition()
+        object End : ArrowPosition()
+        class Custom(val value: Float) : ArrowPosition()
+    }
+
+    /** The configuration for drawable features */
+    data class Config(
+        @ColorInt val color: Int,
+        val cornerRadius: Float,
+        val contentPadding: Int,
+        val arrowWidth: Float,
+        val arrowHeight: Float,
+        val arrowRadius: Float
+    )
+
+    /**
+     * The direction of the arrow in the popup drawable. It affects the content padding and requires
+     * it to be updated in the view.
+     */
+    var arrowDirection: ArrowDirection by
+        Delegates.observable(ArrowDirection.UP) { _, _, _ -> requestPathUpdate() }
+
+    /**
+     * Arrow position along the X axis and its direction. The position is adjusted to the content
+     * corner radius when applied so it doesn't go into rounded corner area
+     */
+    var arrowPosition: ArrowPosition by
+        Delegates.observable(ArrowPosition.Center) { _, _, _ -> requestPathUpdate() }
+
+    private val path = Path()
+    private val paint = Paint()
+    private var shouldUpdatePath = true
+
+    init {
+        paint.color = config.color
+        paint.style = Paint.Style.FILL
+        paint.isAntiAlias = true
+    }
+
+    override fun draw(canvas: Canvas) {
+        updatePathIfNeeded()
+        canvas.drawPath(path, paint)
+    }
+
+    override fun onBoundsChange(bounds: Rect?) {
+        requestPathUpdate()
+    }
+
+    /** Should be applied to the view padding if arrow direction changes */
+    override fun getPadding(padding: Rect): Boolean {
+        padding.set(
+            config.contentPadding,
+            config.contentPadding,
+            config.contentPadding,
+            config.contentPadding
+        )
+        when (arrowDirection) {
+            ArrowDirection.UP -> padding.top += config.arrowHeight.toInt()
+            ArrowDirection.DOWN -> padding.bottom += config.arrowHeight.toInt()
+        }
+        return true
+    }
+
+    override fun getOutline(outline: Outline) {
+        updatePathIfNeeded()
+        outline.setPath(path)
+    }
+
+    override fun getOpacity(): Int {
+        return paint.alpha
+    }
+
+    override fun setAlpha(alpha: Int) {
+        paint.alpha = alpha
+    }
+
+    override fun setColorFilter(colorFilter: ColorFilter?) {
+        paint.colorFilter = colorFilter
+    }
+
+    /** Schedules path update for the next redraw */
+    private fun requestPathUpdate() {
+        shouldUpdatePath = true
+    }
+
+    /** Updates the path if required, when bounds or arrow direction/position changes */
+    private fun updatePathIfNeeded() {
+        if (shouldUpdatePath) {
+            updatePath()
+            shouldUpdatePath = false
+        }
+    }
+
+    /** Updates the path value using the current bounds, config, arrow direction and position */
+    private fun updatePath() {
+        if (bounds.isEmpty) return
+        // Reset the path state
+        path.reset()
+        // The content rect where the filled rounded rect will be drawn
+        val contentRect = RectF(bounds)
+        when (arrowDirection) {
+            ArrowDirection.UP -> {
+                // Add rounded arrow pointing up to the path
+                addRoundedArrowPositioned(path, arrowPosition)
+                // Inset content rect by the arrow size from the top
+                contentRect.top += config.arrowHeight
+            }
+            ArrowDirection.DOWN -> {
+                val matrix = Matrix()
+                // Flip the path with the matrix to draw arrow pointing down
+                matrix.setScale(1f, -1f, bounds.width() / 2f, bounds.height() / 2f)
+                path.transform(matrix)
+                // Add rounded arrow with the flipped matrix applied, will point down
+                addRoundedArrowPositioned(path, arrowPosition)
+                // Restore the path matrix to the original state with inverted matrix
+                matrix.invert(matrix)
+                path.transform(matrix)
+                // Inset content rect by the arrow size from the bottom
+                contentRect.bottom -= config.arrowHeight
+            }
+        }
+        // Add the content area rounded rect
+        path.addRoundRect(contentRect, config.cornerRadius, config.cornerRadius, Path.Direction.CW)
+    }
+
+    /** Add a rounded arrow pointing up in the horizontal position on the canvas */
+    private fun addRoundedArrowPositioned(path: Path, position: ArrowPosition) {
+        val matrix = Matrix()
+        var translationX = positionValue(position) - config.arrowWidth / 2
+        // Offset to position between rounded corners of the content view
+        translationX = translationX.coerceIn(config.cornerRadius,
+                bounds.width() - config.cornerRadius - config.arrowWidth)
+        // Translate to add the arrow in the center horizontally
+        matrix.setTranslate(-translationX, 0f)
+        path.transform(matrix)
+        // Add rounded arrow
+        addRoundedArrow(path)
+        // Restore the path matrix to the original state with inverted matrix
+        matrix.invert(matrix)
+        path.transform(matrix)
+    }
+
+    /** Adds a rounded arrow pointing up to the path, can be flipped if needed */
+    private fun addRoundedArrow(path: Path) {
+        // Theta is half of the angle inside the triangle tip
+        val thetaTan = config.arrowWidth / (config.arrowHeight * 2f)
+        val theta = atan(thetaTan)
+        val thetaDeg = Math.toDegrees(theta.toDouble()).toFloat()
+        // The center Y value of the circle for the triangle tip
+        val tipCircleCenterY = config.arrowRadius / sin(theta)
+        // The length from triangle tip to intersection point with the circle
+        val tipIntersectionSideLength = config.arrowRadius / thetaTan
+        // The offset from the top to the point of intersection
+        val intersectionTopOffset = tipIntersectionSideLength * cos(theta)
+        // The offset from the center to the point of intersection
+        val intersectionCenterOffset = tipIntersectionSideLength * sin(theta)
+        // The center X of the triangle
+        val arrowCenterX = config.arrowWidth / 2f
+
+        // Set initial position in bottom left of the arrow
+        path.moveTo(0f, config.arrowHeight)
+        // Add the left side of the triangle
+        path.lineTo(arrowCenterX - intersectionCenterOffset, intersectionTopOffset)
+        // Add the arc from the left to the right side of the triangle
+        path.arcTo(
+            /* left = */ arrowCenterX - config.arrowRadius,
+            /* top = */ tipCircleCenterY - config.arrowRadius,
+            /* right = */ arrowCenterX + config.arrowRadius,
+            /* bottom = */ tipCircleCenterY + config.arrowRadius,
+            /* startAngle = */ 180 + thetaDeg,
+            /* sweepAngle = */ 180 - (2 * thetaDeg),
+            /* forceMoveTo = */ false
+        )
+        // Add the right side of the triangle
+        path.lineTo(config.arrowWidth, config.arrowHeight)
+        // Close the path
+        path.close()
+    }
+
+    /** The value of the arrow position provided the position and current bounds */
+    private fun positionValue(position: ArrowPosition): Float {
+        return when (position) {
+            is ArrowPosition.Start -> 0f
+            is ArrowPosition.Center -> bounds.width().toFloat() / 2f
+            is ArrowPosition.End -> bounds.width().toFloat()
+            is ArrowPosition.Custom -> position.value
+        }
+    }
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/bubbles/BubblePopupView.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/common/bubbles/BubblePopupView.kt
new file mode 100644
index 0000000..f8a4946
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/bubbles/BubblePopupView.kt
@@ -0,0 +1,65 @@
+/*
+ * 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.wm.shell.common.bubbles
+
+import android.content.Context
+import android.graphics.Rect
+import android.util.AttributeSet
+import android.widget.LinearLayout
+
+/** A popup container view that uses [BubblePopupDrawable] as a background */
+open class BubblePopupView
+@JvmOverloads
+constructor(
+    context: Context,
+    attrs: AttributeSet? = null,
+    defStyleAttr: Int = 0,
+    defStyleRes: Int = 0
+) : LinearLayout(context, attrs, defStyleAttr, defStyleRes) {
+    private var popupDrawable: BubblePopupDrawable? = null
+
+    /**
+     * Sets up the popup drawable with the config provided. Required to remove dependency on local
+     * resources
+     */
+    fun setupBackground(config: BubblePopupDrawable.Config) {
+        popupDrawable = BubblePopupDrawable(config)
+        background = popupDrawable
+        forceLayout()
+    }
+
+    /**
+     * Sets the arrow direction for the background drawable and updates the padding to fit the
+     * content inside of the popup drawable
+     */
+    fun setArrowDirection(direction: BubblePopupDrawable.ArrowDirection) {
+        popupDrawable?.let {
+            it.arrowDirection = direction
+            val padding = Rect()
+            if (it.getPadding(padding)) {
+                setPadding(padding.left, padding.top, padding.right, padding.bottom)
+            }
+        }
+    }
+
+    /** Sets the arrow position for the background drawable and triggers redraw */
+    fun setArrowPosition(position: BubblePopupDrawable.ArrowPosition) {
+        popupDrawable?.let {
+            it.arrowPosition = position
+            invalidate()
+        }
+    }
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/pip/PipMediaController.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/common/pip/PipMediaController.kt
new file mode 100644
index 0000000..2719cd2
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/pip/PipMediaController.kt
@@ -0,0 +1,365 @@
+/*
+ * 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.wm.shell.common.pip
+
+import android.annotation.DrawableRes
+import android.annotation.StringRes
+import android.app.PendingIntent
+import android.app.RemoteAction
+import android.content.BroadcastReceiver
+import android.content.Context
+import android.content.Intent
+import android.content.IntentFilter
+import android.graphics.drawable.Icon
+import android.media.MediaMetadata
+import android.media.session.MediaController
+import android.media.session.MediaSession
+import android.media.session.MediaSessionManager
+import android.media.session.PlaybackState
+import android.os.Handler
+import android.os.HandlerExecutor
+import android.os.UserHandle
+import com.android.wm.shell.R
+import com.android.wm.shell.pip.PipUtils
+import java.util.function.Consumer
+
+/**
+ * Interfaces with the [MediaSessionManager] to compose the right set of actions to show (only
+ * if there are no actions from the PiP activity itself). The active media controller is only set
+ * when there is a media session from the top PiP activity.
+ */
+class PipMediaController(private val mContext: Context, private val mMainHandler: Handler) {
+    /**
+     * A listener interface to receive notification on changes to the media actions.
+     */
+    interface ActionListener {
+        /**
+         * Called when the media actions changed.
+         */
+        fun onMediaActionsChanged(actions: List<RemoteAction?>?)
+    }
+
+    /**
+     * A listener interface to receive notification on changes to the media metadata.
+     */
+    interface MetadataListener {
+        /**
+         * Called when the media metadata changed.
+         */
+        fun onMediaMetadataChanged(metadata: MediaMetadata?)
+    }
+
+    /**
+     * A listener interface to receive notification on changes to the media session token.
+     */
+    interface TokenListener {
+        /**
+         * Called when the media session token changed.
+         */
+        fun onMediaSessionTokenChanged(token: MediaSession.Token?)
+    }
+
+    private val mHandlerExecutor: HandlerExecutor = HandlerExecutor(mMainHandler)
+    private val mMediaSessionManager: MediaSessionManager?
+    private var mMediaController: MediaController? = null
+    private val mPauseAction: RemoteAction
+    private val mPlayAction: RemoteAction
+    private val mNextAction: RemoteAction
+    private val mPrevAction: RemoteAction
+    private val mMediaActionReceiver: BroadcastReceiver = object : BroadcastReceiver() {
+        override fun onReceive(context: Context, intent: Intent) {
+            if (mMediaController == null) {
+                // no active media session, bail early.
+                return
+            }
+            when (intent.action) {
+                ACTION_PLAY -> mMediaController!!.transportControls.play()
+                ACTION_PAUSE -> mMediaController!!.transportControls.pause()
+                ACTION_NEXT -> mMediaController!!.transportControls.skipToNext()
+                ACTION_PREV -> mMediaController!!.transportControls.skipToPrevious()
+            }
+        }
+    }
+    private val mPlaybackChangedListener: MediaController.Callback =
+        object : MediaController.Callback() {
+            override fun onPlaybackStateChanged(state: PlaybackState?) {
+                notifyActionsChanged()
+            }
+
+            override fun onMetadataChanged(metadata: MediaMetadata?) {
+                notifyMetadataChanged(metadata)
+            }
+        }
+    private val mSessionsChangedListener =
+        MediaSessionManager.OnActiveSessionsChangedListener { controllers: List<MediaController>? ->
+            resolveActiveMediaController(controllers)
+        }
+    private val mActionListeners = ArrayList<ActionListener>()
+    private val mMetadataListeners = ArrayList<MetadataListener>()
+    private val mTokenListeners = ArrayList<TokenListener>()
+
+    init {
+        val mediaControlFilter = IntentFilter()
+        mediaControlFilter.addAction(ACTION_PLAY)
+        mediaControlFilter.addAction(ACTION_PAUSE)
+        mediaControlFilter.addAction(ACTION_NEXT)
+        mediaControlFilter.addAction(ACTION_PREV)
+        mContext.registerReceiverForAllUsers(
+            mMediaActionReceiver, mediaControlFilter,
+            SYSTEMUI_PERMISSION, mMainHandler, Context.RECEIVER_EXPORTED
+        )
+
+        // Creates the standard media buttons that we may show.
+        mPauseAction = getDefaultRemoteAction(
+            R.string.pip_pause,
+            R.drawable.pip_ic_pause_white, ACTION_PAUSE
+        )
+        mPlayAction = getDefaultRemoteAction(
+            R.string.pip_play,
+            R.drawable.pip_ic_play_arrow_white, ACTION_PLAY
+        )
+        mNextAction = getDefaultRemoteAction(
+            R.string.pip_skip_to_next,
+            R.drawable.pip_ic_skip_next_white, ACTION_NEXT
+        )
+        mPrevAction = getDefaultRemoteAction(
+            R.string.pip_skip_to_prev,
+            R.drawable.pip_ic_skip_previous_white, ACTION_PREV
+        )
+        mMediaSessionManager = mContext.getSystemService(
+            MediaSessionManager::class.java
+        )
+    }
+
+    /**
+     * Handles when an activity is pinned.
+     */
+    fun onActivityPinned() {
+        // Once we enter PiP, try to find the active media controller for the top most activity
+        resolveActiveMediaController(
+            mMediaSessionManager!!.getActiveSessionsForUser(
+                null,
+                UserHandle.CURRENT
+            )
+        )
+    }
+
+    /**
+     * Adds a new media action listener.
+     */
+    fun addActionListener(listener: ActionListener) {
+        if (!mActionListeners.contains(listener)) {
+            mActionListeners.add(listener)
+            listener.onMediaActionsChanged(mediaActions)
+        }
+    }
+
+    /**
+     * Removes a media action listener.
+     */
+    fun removeActionListener(listener: ActionListener) {
+        listener.onMediaActionsChanged(emptyList<RemoteAction>())
+        mActionListeners.remove(listener)
+    }
+
+    /**
+     * Adds a new media metadata listener.
+     */
+    fun addMetadataListener(listener: MetadataListener) {
+        if (!mMetadataListeners.contains(listener)) {
+            mMetadataListeners.add(listener)
+            listener.onMediaMetadataChanged(mediaMetadata)
+        }
+    }
+
+    /**
+     * Removes a media metadata listener.
+     */
+    fun removeMetadataListener(listener: MetadataListener) {
+        listener.onMediaMetadataChanged(null)
+        mMetadataListeners.remove(listener)
+    }
+
+    /**
+     * Adds a new token listener.
+     */
+    fun addTokenListener(listener: TokenListener) {
+        if (!mTokenListeners.contains(listener)) {
+            mTokenListeners.add(listener)
+            listener.onMediaSessionTokenChanged(token)
+        }
+    }
+
+    /**
+     * Removes a token listener.
+     */
+    fun removeTokenListener(listener: TokenListener) {
+        listener.onMediaSessionTokenChanged(null)
+        mTokenListeners.remove(listener)
+    }
+
+    private val token: MediaSession.Token?
+        get() = if (mMediaController == null) {
+            null
+        } else mMediaController!!.sessionToken
+    private val mediaMetadata: MediaMetadata?
+        get() = if (mMediaController != null) mMediaController!!.metadata else null
+
+    private val mediaActions: List<RemoteAction?>
+        /**
+         * Gets the set of media actions currently available.
+         */
+        get() {
+            if (mMediaController == null) {
+                return emptyList<RemoteAction>()
+            }
+            // Cache the PlaybackState since it's a Binder call.
+            // Safe because mMediaController is guaranteed non-null here.
+            val playbackState: PlaybackState = mMediaController!!.playbackState
+                ?: return emptyList<RemoteAction>()
+            val mediaActions = ArrayList<RemoteAction?>()
+            val isPlaying = playbackState.isActive
+            val actions = playbackState.actions
+
+            // Prev action
+            mPrevAction.isEnabled =
+                actions and PlaybackState.ACTION_SKIP_TO_PREVIOUS != 0L
+            mediaActions.add(mPrevAction)
+
+            // Play/pause action
+            if (!isPlaying && actions and PlaybackState.ACTION_PLAY != 0L) {
+                mediaActions.add(mPlayAction)
+            } else if (isPlaying && actions and PlaybackState.ACTION_PAUSE != 0L) {
+                mediaActions.add(mPauseAction)
+            }
+
+            // Next action
+            mNextAction.isEnabled =
+                actions and PlaybackState.ACTION_SKIP_TO_NEXT != 0L
+            mediaActions.add(mNextAction)
+            return mediaActions
+        }
+
+    /** @return Default [RemoteAction] sends broadcast back to SysUI.
+     */
+    private fun getDefaultRemoteAction(
+        @StringRes titleAndDescription: Int,
+        @DrawableRes icon: Int,
+        action: String
+    ): RemoteAction {
+        val titleAndDescriptionStr = mContext.getString(titleAndDescription)
+        val intent = Intent(action)
+        intent.setPackage(mContext.packageName)
+        return RemoteAction(
+            Icon.createWithResource(mContext, icon),
+            titleAndDescriptionStr, titleAndDescriptionStr,
+            PendingIntent.getBroadcast(
+                mContext, 0 /* requestCode */, intent,
+                PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
+            )
+        )
+    }
+
+    /**
+     * Re-registers the session listener for the current user.
+     */
+    fun registerSessionListenerForCurrentUser() {
+        mMediaSessionManager!!.removeOnActiveSessionsChangedListener(mSessionsChangedListener)
+        mMediaSessionManager.addOnActiveSessionsChangedListener(
+            null, UserHandle.CURRENT,
+            mHandlerExecutor, mSessionsChangedListener
+        )
+    }
+
+    /**
+     * Tries to find and set the active media controller for the top PiP activity.
+     */
+    private fun resolveActiveMediaController(controllers: List<MediaController>?) {
+        if (controllers != null) {
+            val topActivity = PipUtils.getTopPipActivity(mContext).first
+            if (topActivity != null) {
+                for (i in controllers.indices) {
+                    val controller = controllers[i]
+                    if (controller.packageName == topActivity.packageName) {
+                        setActiveMediaController(controller)
+                        return
+                    }
+                }
+            }
+        }
+        setActiveMediaController(null)
+    }
+
+    /**
+     * Sets the active media controller for the top PiP activity.
+     */
+    private fun setActiveMediaController(controller: MediaController?) {
+        if (controller != mMediaController) {
+            if (mMediaController != null) {
+                mMediaController!!.unregisterCallback(mPlaybackChangedListener)
+            }
+            mMediaController = controller
+            controller?.registerCallback(mPlaybackChangedListener, mMainHandler)
+            notifyActionsChanged()
+            notifyMetadataChanged(mediaMetadata)
+            notifyTokenChanged(token)
+
+            // TODO(winsonc): Consider if we want to close the PIP after a timeout (like on TV)
+        }
+    }
+
+    /**
+     * Notifies all listeners that the actions have changed.
+     */
+    private fun notifyActionsChanged() {
+        if (mActionListeners.isNotEmpty()) {
+            val actions = mediaActions
+            mActionListeners.forEach(
+                Consumer { l: ActionListener -> l.onMediaActionsChanged(actions) })
+        }
+    }
+
+    /**
+     * Notifies all listeners that the metadata have changed.
+     */
+    private fun notifyMetadataChanged(metadata: MediaMetadata?) {
+        if (mMetadataListeners.isNotEmpty()) {
+            mMetadataListeners.forEach(Consumer { l: MetadataListener ->
+                l.onMediaMetadataChanged(
+                    metadata
+                )
+            })
+        }
+    }
+
+    private fun notifyTokenChanged(token: MediaSession.Token?) {
+        if (mTokenListeners.isNotEmpty()) {
+            mTokenListeners.forEach(Consumer { l: TokenListener ->
+                l.onMediaSessionTokenChanged(
+                    token
+                )
+            })
+        }
+    }
+
+    companion object {
+        private const val SYSTEMUI_PERMISSION = "com.android.systemui.permission.SELF"
+        private const val ACTION_PLAY = "com.android.wm.shell.pip.PLAY"
+        private const val ACTION_PAUSE = "com.android.wm.shell.pip.PAUSE"
+        private const val ACTION_NEXT = "com.android.wm.shell.pip.NEXT"
+        private const val ACTION_PREV = "com.android.wm.shell.pip.PREV"
+    }
+}
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/pip/PipUiEventLogger.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/common/pip/PipUiEventLogger.kt
new file mode 100644
index 0000000..642dacc
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/pip/PipUiEventLogger.kt
@@ -0,0 +1,125 @@
+/*
+ * 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.wm.shell.common.pip
+
+import android.app.TaskInfo
+import android.content.pm.PackageManager
+import com.android.internal.logging.UiEvent
+import com.android.internal.logging.UiEventLogger
+
+/**
+ * Helper class that ends PiP log to UiEvent, see also go/uievent
+ */
+class PipUiEventLogger(
+    private val mUiEventLogger: UiEventLogger,
+    private val mPackageManager: PackageManager
+) {
+    private var mPackageName: String? = null
+    private var mPackageUid = INVALID_PACKAGE_UID
+    fun setTaskInfo(taskInfo: TaskInfo?) {
+        if (taskInfo?.topActivity != null) {
+            // safe because topActivity is guaranteed non-null here
+            mPackageName = taskInfo.topActivity!!.packageName
+            mPackageUid = getUid(mPackageName!!, taskInfo.userId)
+        } else {
+            mPackageName = null
+            mPackageUid = INVALID_PACKAGE_UID
+        }
+    }
+
+    /**
+     * Sends log via UiEvent, reference go/uievent for how to debug locally
+     */
+    fun log(event: PipUiEventEnum?) {
+        if (mPackageName == null || mPackageUid == INVALID_PACKAGE_UID) {
+            return
+        }
+        mUiEventLogger.log(event!!, mPackageUid, mPackageName)
+    }
+
+    private fun getUid(packageName: String, userId: Int): Int {
+        var uid = INVALID_PACKAGE_UID
+        try {
+            uid = mPackageManager.getApplicationInfoAsUser(
+                packageName, 0 /* ApplicationInfoFlags */, userId
+            ).uid
+        } catch (e: PackageManager.NameNotFoundException) {
+            // do nothing.
+        }
+        return uid
+    }
+
+    /**
+     * Enums for logging the PiP events to UiEvent
+     */
+    enum class PipUiEventEnum(private val mId: Int) : UiEventLogger.UiEventEnum {
+        @UiEvent(doc = "Activity enters picture-in-picture mode")
+        PICTURE_IN_PICTURE_ENTER(603),
+
+        @UiEvent(doc = "Activity enters picture-in-picture mode with auto-enter-pip API")
+        PICTURE_IN_PICTURE_AUTO_ENTER(1313),
+
+        @UiEvent(doc = "Activity enters picture-in-picture mode from content-pip API")
+        PICTURE_IN_PICTURE_ENTER_CONTENT_PIP(1314),
+
+        @UiEvent(doc = "Expands from picture-in-picture to fullscreen")
+        PICTURE_IN_PICTURE_EXPAND_TO_FULLSCREEN(604),
+
+        @UiEvent(doc = "Removes picture-in-picture by tap close button")
+        PICTURE_IN_PICTURE_TAP_TO_REMOVE(605),
+
+        @UiEvent(doc = "Removes picture-in-picture by drag to dismiss area")
+        PICTURE_IN_PICTURE_DRAG_TO_REMOVE(606),
+
+        @UiEvent(doc = "Shows picture-in-picture menu")
+        PICTURE_IN_PICTURE_SHOW_MENU(607),
+
+        @UiEvent(doc = "Hides picture-in-picture menu")
+        PICTURE_IN_PICTURE_HIDE_MENU(608),
+
+        @UiEvent(
+            doc = "Changes the aspect ratio of picture-in-picture window. This is inherited" +
+                    " from previous Tron-based logging and currently not in use."
+        )
+        PICTURE_IN_PICTURE_CHANGE_ASPECT_RATIO(609),
+
+        @UiEvent(doc = "User resize of the picture-in-picture window")
+        PICTURE_IN_PICTURE_RESIZE(610),
+
+        @UiEvent(doc = "User unstashed picture-in-picture")
+        PICTURE_IN_PICTURE_STASH_UNSTASHED(709),
+
+        @UiEvent(doc = "User stashed picture-in-picture to the left side")
+        PICTURE_IN_PICTURE_STASH_LEFT(710),
+
+        @UiEvent(doc = "User stashed picture-in-picture to the right side")
+        PICTURE_IN_PICTURE_STASH_RIGHT(711),
+
+        @UiEvent(doc = "User taps on the settings button in PiP menu")
+        PICTURE_IN_PICTURE_SHOW_SETTINGS(933),
+
+        @UiEvent(doc = "Closes PiP with app-provided close action")
+        PICTURE_IN_PICTURE_CUSTOM_CLOSE(1058);
+
+        override fun getId(): Int {
+            return mId
+        }
+    }
+
+    companion object {
+        private const val INVALID_PACKAGE_UID = -1
+    }
+}
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitScreenConstants.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitScreenConstants.java
index ef93a33..be1b9b1 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitScreenConstants.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitScreenConstants.java
@@ -16,6 +16,7 @@
 package com.android.wm.shell.common.split;
 
 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_MULTI_WINDOW;
 import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
@@ -60,7 +61,8 @@
     public static final int[] CONTROLLED_WINDOWING_MODES =
             {WINDOWING_MODE_FULLSCREEN, WINDOWING_MODE_UNDEFINED};
     public static final int[] CONTROLLED_WINDOWING_MODES_WHEN_ACTIVE =
-            {WINDOWING_MODE_FULLSCREEN, WINDOWING_MODE_UNDEFINED, WINDOWING_MODE_MULTI_WINDOW};
+            {WINDOWING_MODE_FULLSCREEN, WINDOWING_MODE_UNDEFINED, WINDOWING_MODE_MULTI_WINDOW,
+            WINDOWING_MODE_FREEFORM};
 
     /** Flag applied to a transition change to identify it as a divider bar for animation. */
     public static final int FLAG_IS_DIVIDER_BAR = FLAG_FIRST_CUSTOM;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIController.java
index 54f8984..7bf0893 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIController.java
@@ -230,8 +230,10 @@
             // The user aspect ratio button should not be handled when a new TaskInfo is
             // sent because of a double tap or when in multi-window mode.
             if (taskInfo.getWindowingMode() != WINDOWING_MODE_FULLSCREEN) {
-                mUserAspectRatioSettingsLayout.release();
-                mUserAspectRatioSettingsLayout = null;
+                if (mUserAspectRatioSettingsLayout != null) {
+                    mUserAspectRatioSettingsLayout.release();
+                    mUserAspectRatioSettingsLayout = null;
+                }
                 return;
             }
             if (!taskInfo.isFromLetterboxDoubleTap) {
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 1a84f4b..aafd9fd 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
@@ -20,6 +20,7 @@
 
 import android.app.ActivityTaskManager;
 import android.content.Context;
+import android.content.pm.PackageManager;
 import android.os.Handler;
 import android.os.SystemProperties;
 import android.view.IWindowManager;
@@ -56,6 +57,8 @@
 import com.android.wm.shell.common.annotations.ShellBackgroundThread;
 import com.android.wm.shell.common.annotations.ShellMainThread;
 import com.android.wm.shell.common.annotations.ShellSplashscreenThread;
+import com.android.wm.shell.common.pip.PipMediaController;
+import com.android.wm.shell.common.pip.PipUiEventLogger;
 import com.android.wm.shell.compatui.CompatUIConfiguration;
 import com.android.wm.shell.compatui.CompatUIController;
 import com.android.wm.shell.compatui.CompatUIShellCommandHandler;
@@ -319,6 +322,24 @@
         return Optional.empty();
     }
 
+    //
+    // PiP (optional feature)
+    //
+
+    @WMSingleton
+    @Provides
+    static PipUiEventLogger providePipUiEventLogger(UiEventLogger uiEventLogger,
+            PackageManager packageManager) {
+        return new PipUiEventLogger(uiEventLogger, packageManager);
+    }
+
+    @WMSingleton
+    @Provides
+    static PipMediaController providePipMediaController(Context context,
+            @ShellMainThread Handler mainHandler) {
+        return new PipMediaController(context, mainHandler);
+    }
+
 
     //
     // Bubbles (optional feature)
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/pip/Pip1Module.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/pip/Pip1Module.java
index 9bf973f..24ef44a 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/pip/Pip1Module.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/pip/Pip1Module.java
@@ -32,6 +32,8 @@
 import com.android.wm.shell.common.annotations.ShellMainThread;
 import com.android.wm.shell.common.pip.PhoneSizeSpecSource;
 import com.android.wm.shell.common.pip.PipAppOpsListener;
+import com.android.wm.shell.common.pip.PipMediaController;
+import com.android.wm.shell.common.pip.PipUiEventLogger;
 import com.android.wm.shell.common.pip.SizeSpecSource;
 import com.android.wm.shell.dagger.WMShellBaseModule;
 import com.android.wm.shell.dagger.WMSingleton;
@@ -41,7 +43,6 @@
 import com.android.wm.shell.pip.PipBoundsAlgorithm;
 import com.android.wm.shell.pip.PipBoundsState;
 import com.android.wm.shell.pip.PipDisplayLayoutState;
-import com.android.wm.shell.pip.PipMediaController;
 import com.android.wm.shell.pip.PipParamsChangedForwarder;
 import com.android.wm.shell.pip.PipSnapAlgorithm;
 import com.android.wm.shell.pip.PipSurfaceTransactionHelper;
@@ -49,7 +50,6 @@
 import com.android.wm.shell.pip.PipTransition;
 import com.android.wm.shell.pip.PipTransitionController;
 import com.android.wm.shell.pip.PipTransitionState;
-import com.android.wm.shell.pip.PipUiEventLogger;
 import com.android.wm.shell.pip.PipUtils;
 import com.android.wm.shell.pip.phone.PhonePipKeepClearAlgorithm;
 import com.android.wm.shell.pip.phone.PhonePipMenuController;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/pip/Pip1SharedModule.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/pip/Pip1SharedModule.java
index e8fae24..c4ca501 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/pip/Pip1SharedModule.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/pip/Pip1SharedModule.java
@@ -17,15 +17,9 @@
 package com.android.wm.shell.dagger.pip;
 
 import android.content.Context;
-import android.content.pm.PackageManager;
-import android.os.Handler;
 
-import com.android.internal.logging.UiEventLogger;
-import com.android.wm.shell.common.annotations.ShellMainThread;
 import com.android.wm.shell.dagger.WMSingleton;
-import com.android.wm.shell.pip.PipMediaController;
 import com.android.wm.shell.pip.PipSurfaceTransactionHelper;
-import com.android.wm.shell.pip.PipUiEventLogger;
 
 import dagger.Module;
 import dagger.Provides;
@@ -36,24 +30,9 @@
  */
 @Module
 public abstract class Pip1SharedModule {
-    // Needs handler for registering broadcast receivers
-    @WMSingleton
-    @Provides
-    static PipMediaController providePipMediaController(Context context,
-            @ShellMainThread Handler mainHandler) {
-        return new PipMediaController(context, mainHandler);
-    }
-
     @WMSingleton
     @Provides
     static PipSurfaceTransactionHelper providePipSurfaceTransactionHelper(Context context) {
         return new PipSurfaceTransactionHelper(context);
     }
-
-    @WMSingleton
-    @Provides
-    static PipUiEventLogger providePipUiEventLogger(UiEventLogger uiEventLogger,
-            PackageManager packageManager) {
-        return new PipUiEventLogger(uiEventLogger, packageManager);
-    }
 }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/pip/Pip2Module.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/pip/Pip2Module.java
index c7c6e8a..8dec4ea 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/pip/Pip2Module.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/pip/Pip2Module.java
@@ -18,6 +18,7 @@
 
 import android.annotation.Nullable;
 
+import com.android.wm.shell.dagger.WMShellBaseModule;
 import com.android.wm.shell.dagger.WMSingleton;
 import com.android.wm.shell.pip2.PipTransition;
 
@@ -26,9 +27,9 @@
 
 /**
  * Provides dependencies from {@link com.android.wm.shell.pip2}, this implementation is meant to be
- * the successor of its sibling {@link Pip1SharedModule}.
+ * the successor of its sibling {@link Pip1Module}.
  */
-@Module
+@Module(includes = WMShellBaseModule.class)
 public abstract class Pip2Module {
     @WMSingleton
     @Provides
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/pip/TvPipModule.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/pip/TvPipModule.java
index 80ffbb0..a6ff9ec 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/pip/TvPipModule.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/pip/TvPipModule.java
@@ -30,20 +30,20 @@
 import com.android.wm.shell.common.annotations.ShellMainThread;
 import com.android.wm.shell.common.pip.LegacySizeSpecSource;
 import com.android.wm.shell.common.pip.PipAppOpsListener;
+import com.android.wm.shell.common.pip.PipMediaController;
+import com.android.wm.shell.common.pip.PipUiEventLogger;
 import com.android.wm.shell.common.pip.SizeSpecSource;
 import com.android.wm.shell.dagger.WMShellBaseModule;
 import com.android.wm.shell.dagger.WMSingleton;
 import com.android.wm.shell.pip.Pip;
 import com.android.wm.shell.pip.PipAnimationController;
 import com.android.wm.shell.pip.PipDisplayLayoutState;
-import com.android.wm.shell.pip.PipMediaController;
 import com.android.wm.shell.pip.PipParamsChangedForwarder;
 import com.android.wm.shell.pip.PipSnapAlgorithm;
 import com.android.wm.shell.pip.PipSurfaceTransactionHelper;
 import com.android.wm.shell.pip.PipTaskOrganizer;
 import com.android.wm.shell.pip.PipTransitionController;
 import com.android.wm.shell.pip.PipTransitionState;
-import com.android.wm.shell.pip.PipUiEventLogger;
 import com.android.wm.shell.pip.tv.TvPipBoundsAlgorithm;
 import com.android.wm.shell.pip.tv.TvPipBoundsController;
 import com.android.wm.shell.pip.tv.TvPipBoundsState;
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 1d46e75..633f627 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
@@ -18,6 +18,7 @@
 
 import android.R
 import android.app.ActivityManager.RunningTaskInfo
+import android.app.WindowConfiguration
 import android.app.WindowConfiguration.ACTIVITY_TYPE_HOME
 import android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD
 import android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM
@@ -301,6 +302,24 @@
         }
     }
 
+    /** Move a desktop app to split screen. */
+    fun moveToSplit(task: RunningTaskInfo) {
+        KtProtoLog.v(
+            WM_SHELL_DESKTOP_MODE,
+            "DesktopTasksController: moveToSplit taskId=%d",
+            task.taskId
+        )
+        val wct = WindowContainerTransaction()
+        wct.setWindowingMode(task.token, WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW)
+        wct.setBounds(task.token, null)
+        wct.setDensityDpi(task.token, getDefaultDensityDpi())
+        if (Transitions.ENABLE_SHELL_TRANSITIONS) {
+            transitions.startTransition(TRANSIT_CHANGE, wct, null /* handler */)
+        } else {
+            shellTaskOrganizer.applyTransaction(wct)
+        }
+    }
+
     /**
      * The second part of the animated move to desktop transition, called after
      * {@link startMoveToDesktop}. Move a task to fullscreen after being dragged from fullscreen
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipMediaController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipMediaController.java
deleted file mode 100644
index ddffb5b..0000000
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipMediaController.java
+++ /dev/null
@@ -1,369 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.wm.shell.pip;
-
-import static android.app.PendingIntent.FLAG_IMMUTABLE;
-import static android.app.PendingIntent.FLAG_UPDATE_CURRENT;
-
-import android.annotation.DrawableRes;
-import android.annotation.StringRes;
-import android.annotation.SuppressLint;
-import android.app.PendingIntent;
-import android.app.RemoteAction;
-import android.content.BroadcastReceiver;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.graphics.drawable.Icon;
-import android.media.MediaMetadata;
-import android.media.session.MediaController;
-import android.media.session.MediaSession;
-import android.media.session.MediaSessionManager;
-import android.media.session.PlaybackState;
-import android.os.Handler;
-import android.os.HandlerExecutor;
-import android.os.UserHandle;
-
-import androidx.annotation.Nullable;
-
-import com.android.wm.shell.R;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-
-/**
- * Interfaces with the {@link MediaSessionManager} to compose the right set of actions to show (only
- * if there are no actions from the PiP activity itself). The active media controller is only set
- * when there is a media session from the top PiP activity.
- */
-public class PipMediaController {
-    private static final String SYSTEMUI_PERMISSION = "com.android.systemui.permission.SELF";
-
-    private static final String ACTION_PLAY = "com.android.wm.shell.pip.PLAY";
-    private static final String ACTION_PAUSE = "com.android.wm.shell.pip.PAUSE";
-    private static final String ACTION_NEXT = "com.android.wm.shell.pip.NEXT";
-    private static final String ACTION_PREV = "com.android.wm.shell.pip.PREV";
-
-    /**
-     * A listener interface to receive notification on changes to the media actions.
-     */
-    public interface ActionListener {
-        /**
-         * Called when the media actions changed.
-         */
-        void onMediaActionsChanged(List<RemoteAction> actions);
-    }
-
-    /**
-     * A listener interface to receive notification on changes to the media metadata.
-     */
-    public interface MetadataListener {
-        /**
-         * Called when the media metadata changed.
-         */
-        void onMediaMetadataChanged(MediaMetadata metadata);
-    }
-
-    /**
-     * A listener interface to receive notification on changes to the media session token.
-     */
-    public interface TokenListener {
-        /**
-         * Called when the media session token changed.
-         */
-        void onMediaSessionTokenChanged(MediaSession.Token token);
-    }
-
-    private final Context mContext;
-    private final Handler mMainHandler;
-    private final HandlerExecutor mHandlerExecutor;
-
-    private final MediaSessionManager mMediaSessionManager;
-    private MediaController mMediaController;
-
-    private RemoteAction mPauseAction;
-    private RemoteAction mPlayAction;
-    private RemoteAction mNextAction;
-    private RemoteAction mPrevAction;
-
-    private final BroadcastReceiver mMediaActionReceiver = new BroadcastReceiver() {
-        @Override
-        public void onReceive(Context context, Intent intent) {
-            if (mMediaController == null || mMediaController.getTransportControls() == null) {
-                // no active media session, bail early.
-                return;
-            }
-            switch (intent.getAction()) {
-                case ACTION_PLAY:
-                    mMediaController.getTransportControls().play();
-                    break;
-                case ACTION_PAUSE:
-                    mMediaController.getTransportControls().pause();
-                    break;
-                case ACTION_NEXT:
-                    mMediaController.getTransportControls().skipToNext();
-                    break;
-                case ACTION_PREV:
-                    mMediaController.getTransportControls().skipToPrevious();
-                    break;
-            }
-        }
-    };
-
-    private final MediaController.Callback mPlaybackChangedListener =
-            new MediaController.Callback() {
-                @Override
-                public void onPlaybackStateChanged(PlaybackState state) {
-                    notifyActionsChanged();
-                }
-
-                @Override
-                public void onMetadataChanged(@Nullable MediaMetadata metadata) {
-                    notifyMetadataChanged(metadata);
-                }
-            };
-
-    private final MediaSessionManager.OnActiveSessionsChangedListener mSessionsChangedListener =
-            this::resolveActiveMediaController;
-
-    private final ArrayList<ActionListener> mActionListeners = new ArrayList<>();
-    private final ArrayList<MetadataListener> mMetadataListeners = new ArrayList<>();
-    private final ArrayList<TokenListener> mTokenListeners = new ArrayList<>();
-
-    public PipMediaController(Context context, Handler mainHandler) {
-        mContext = context;
-        mMainHandler = mainHandler;
-        mHandlerExecutor = new HandlerExecutor(mMainHandler);
-        if (!PipUtils.isPip2ExperimentEnabled()) {
-            IntentFilter mediaControlFilter = new IntentFilter();
-            mediaControlFilter.addAction(ACTION_PLAY);
-            mediaControlFilter.addAction(ACTION_PAUSE);
-            mediaControlFilter.addAction(ACTION_NEXT);
-            mediaControlFilter.addAction(ACTION_PREV);
-            mContext.registerReceiverForAllUsers(mMediaActionReceiver, mediaControlFilter,
-                    SYSTEMUI_PERMISSION, mainHandler, Context.RECEIVER_EXPORTED);
-        }
-
-        // Creates the standard media buttons that we may show.
-        mPauseAction = getDefaultRemoteAction(R.string.pip_pause,
-                R.drawable.pip_ic_pause_white, ACTION_PAUSE);
-        mPlayAction = getDefaultRemoteAction(R.string.pip_play,
-                R.drawable.pip_ic_play_arrow_white, ACTION_PLAY);
-        mNextAction = getDefaultRemoteAction(R.string.pip_skip_to_next,
-                R.drawable.pip_ic_skip_next_white, ACTION_NEXT);
-        mPrevAction = getDefaultRemoteAction(R.string.pip_skip_to_prev,
-                R.drawable.pip_ic_skip_previous_white, ACTION_PREV);
-
-        mMediaSessionManager = context.getSystemService(MediaSessionManager.class);
-    }
-
-    /**
-     * Handles when an activity is pinned.
-     */
-    public void onActivityPinned() {
-        // Once we enter PiP, try to find the active media controller for the top most activity
-        resolveActiveMediaController(mMediaSessionManager.getActiveSessionsForUser(null,
-                UserHandle.CURRENT));
-    }
-
-    /**
-     * Adds a new media action listener.
-     */
-    public void addActionListener(ActionListener listener) {
-        if (!mActionListeners.contains(listener)) {
-            mActionListeners.add(listener);
-            listener.onMediaActionsChanged(getMediaActions());
-        }
-    }
-
-    /**
-     * Removes a media action listener.
-     */
-    public void removeActionListener(ActionListener listener) {
-        listener.onMediaActionsChanged(Collections.emptyList());
-        mActionListeners.remove(listener);
-    }
-
-    /**
-     * Adds a new media metadata listener.
-     */
-    public void addMetadataListener(MetadataListener listener) {
-        if (!mMetadataListeners.contains(listener)) {
-            mMetadataListeners.add(listener);
-            listener.onMediaMetadataChanged(getMediaMetadata());
-        }
-    }
-
-    /**
-     * Removes a media metadata listener.
-     */
-    public void removeMetadataListener(MetadataListener listener) {
-        listener.onMediaMetadataChanged(null);
-        mMetadataListeners.remove(listener);
-    }
-
-    /**
-     * Adds a new token listener.
-     */
-    public void addTokenListener(TokenListener listener) {
-        if (!mTokenListeners.contains(listener)) {
-            mTokenListeners.add(listener);
-            listener.onMediaSessionTokenChanged(getToken());
-        }
-    }
-
-    /**
-     * Removes a token listener.
-     */
-    public void removeTokenListener(TokenListener listener) {
-        listener.onMediaSessionTokenChanged(null);
-        mTokenListeners.remove(listener);
-    }
-
-    private MediaSession.Token getToken() {
-        if (mMediaController == null) {
-            return null;
-        }
-        return mMediaController.getSessionToken();
-    }
-
-    private MediaMetadata getMediaMetadata() {
-        return mMediaController != null ? mMediaController.getMetadata() : null;
-    }
-
-    /**
-     * Gets the set of media actions currently available.
-     */
-    // This is due to using PlaybackState#isActive, which is added in API 31.
-    // It can be removed when min_sdk of the app is set to 31 or greater.
-    @SuppressLint("NewApi")
-    private List<RemoteAction> getMediaActions() {
-        // Cache the PlaybackState since it's a Binder call.
-        final PlaybackState playbackState;
-        if (mMediaController == null
-                || (playbackState = mMediaController.getPlaybackState()) == null) {
-            return Collections.emptyList();
-        }
-
-        ArrayList<RemoteAction> mediaActions = new ArrayList<>();
-        boolean isPlaying = playbackState.isActive();
-        long actions = playbackState.getActions();
-
-        // Prev action
-        mPrevAction.setEnabled((actions & PlaybackState.ACTION_SKIP_TO_PREVIOUS) != 0);
-        mediaActions.add(mPrevAction);
-
-        // Play/pause action
-        if (!isPlaying && ((actions & PlaybackState.ACTION_PLAY) != 0)) {
-            mediaActions.add(mPlayAction);
-        } else if (isPlaying && ((actions & PlaybackState.ACTION_PAUSE) != 0)) {
-            mediaActions.add(mPauseAction);
-        }
-
-        // Next action
-        mNextAction.setEnabled((actions & PlaybackState.ACTION_SKIP_TO_NEXT) != 0);
-        mediaActions.add(mNextAction);
-        return mediaActions;
-    }
-
-    /** @return Default {@link RemoteAction} sends broadcast back to SysUI. */
-    private RemoteAction getDefaultRemoteAction(@StringRes int titleAndDescription,
-            @DrawableRes int icon, String action) {
-        final String titleAndDescriptionStr = mContext.getString(titleAndDescription);
-        final Intent intent = new Intent(action);
-        intent.setPackage(mContext.getPackageName());
-        return new RemoteAction(Icon.createWithResource(mContext, icon),
-                titleAndDescriptionStr, titleAndDescriptionStr,
-                PendingIntent.getBroadcast(mContext, 0 /* requestCode */, intent,
-                        FLAG_UPDATE_CURRENT | FLAG_IMMUTABLE));
-    }
-
-    /**
-     * Re-registers the session listener for the current user.
-     */
-    public void registerSessionListenerForCurrentUser() {
-        mMediaSessionManager.removeOnActiveSessionsChangedListener(mSessionsChangedListener);
-        mMediaSessionManager.addOnActiveSessionsChangedListener(null, UserHandle.CURRENT,
-                mHandlerExecutor, mSessionsChangedListener);
-    }
-
-    /**
-     * Tries to find and set the active media controller for the top PiP activity.
-     */
-    private void resolveActiveMediaController(List<MediaController> controllers) {
-        if (controllers != null) {
-            final ComponentName topActivity = PipUtils.getTopPipActivity(mContext).first;
-            if (topActivity != null) {
-                for (int i = 0; i < controllers.size(); i++) {
-                    final MediaController controller = controllers.get(i);
-                    if (controller.getPackageName().equals(topActivity.getPackageName())) {
-                        setActiveMediaController(controller);
-                        return;
-                    }
-                }
-            }
-        }
-        setActiveMediaController(null);
-    }
-
-    /**
-     * Sets the active media controller for the top PiP activity.
-     */
-    private void setActiveMediaController(MediaController controller) {
-        if (controller != mMediaController) {
-            if (mMediaController != null) {
-                mMediaController.unregisterCallback(mPlaybackChangedListener);
-            }
-            mMediaController = controller;
-            if (controller != null) {
-                controller.registerCallback(mPlaybackChangedListener, mMainHandler);
-            }
-            notifyActionsChanged();
-            notifyMetadataChanged(getMediaMetadata());
-            notifyTokenChanged(getToken());
-
-            // TODO(winsonc): Consider if we want to close the PIP after a timeout (like on TV)
-        }
-    }
-
-    /**
-     * Notifies all listeners that the actions have changed.
-     */
-    private void notifyActionsChanged() {
-        if (!mActionListeners.isEmpty()) {
-            List<RemoteAction> actions = getMediaActions();
-            mActionListeners.forEach(l -> l.onMediaActionsChanged(actions));
-        }
-    }
-
-    /**
-     * Notifies all listeners that the metadata have changed.
-     */
-    private void notifyMetadataChanged(MediaMetadata metadata) {
-        if (!mMetadataListeners.isEmpty()) {
-            mMetadataListeners.forEach(l -> l.onMediaMetadataChanged(metadata));
-        }
-    }
-
-    private void notifyTokenChanged(MediaSession.Token token) {
-        if (!mTokenListeners.isEmpty()) {
-            mTokenListeners.forEach(l -> l.onMediaSessionTokenChanged(token));
-        }
-    }
-}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
index 19c60c2..296857b 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
@@ -82,6 +82,7 @@
 import com.android.wm.shell.common.ShellExecutor;
 import com.android.wm.shell.common.SyncTransactionQueue;
 import com.android.wm.shell.common.annotations.ShellMainThread;
+import com.android.wm.shell.common.pip.PipUiEventLogger;
 import com.android.wm.shell.pip.phone.PipMotionHelper;
 import com.android.wm.shell.protolog.ShellProtoLogGroup;
 import com.android.wm.shell.splitscreen.SplitScreenController;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipUiEventLogger.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipUiEventLogger.java
deleted file mode 100644
index 3e5a19b..0000000
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipUiEventLogger.java
+++ /dev/null
@@ -1,135 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.wm.shell.pip;
-
-import android.app.TaskInfo;
-import android.content.pm.PackageManager;
-
-import com.android.internal.logging.UiEvent;
-import com.android.internal.logging.UiEventLogger;
-
-/**
- * Helper class that ends PiP log to UiEvent, see also go/uievent
- */
-public class PipUiEventLogger {
-
-    private static final int INVALID_PACKAGE_UID = -1;
-
-    private final UiEventLogger mUiEventLogger;
-    private final PackageManager mPackageManager;
-
-    private String mPackageName;
-    private int mPackageUid = INVALID_PACKAGE_UID;
-
-    public PipUiEventLogger(UiEventLogger uiEventLogger, PackageManager packageManager) {
-        mUiEventLogger = uiEventLogger;
-        mPackageManager = packageManager;
-    }
-
-    public void setTaskInfo(TaskInfo taskInfo) {
-        if (taskInfo != null && taskInfo.topActivity != null) {
-            mPackageName = taskInfo.topActivity.getPackageName();
-            mPackageUid = getUid(mPackageName, taskInfo.userId);
-        } else {
-            mPackageName = null;
-            mPackageUid = INVALID_PACKAGE_UID;
-        }
-    }
-
-    /**
-     * Sends log via UiEvent, reference go/uievent for how to debug locally
-     */
-    public void log(PipUiEventEnum event) {
-        if (mPackageName == null || mPackageUid == INVALID_PACKAGE_UID) {
-            return;
-        }
-        mUiEventLogger.log(event, mPackageUid, mPackageName);
-    }
-
-    private int getUid(String packageName, int userId) {
-        int uid = INVALID_PACKAGE_UID;
-        try {
-            uid = mPackageManager.getApplicationInfoAsUser(
-                    packageName, 0 /* ApplicationInfoFlags */, userId).uid;
-        } catch (PackageManager.NameNotFoundException e) {
-            // do nothing.
-        }
-        return uid;
-    }
-
-    /**
-     * Enums for logging the PiP events to UiEvent
-     */
-    public enum PipUiEventEnum implements UiEventLogger.UiEventEnum {
-        @UiEvent(doc = "Activity enters picture-in-picture mode")
-        PICTURE_IN_PICTURE_ENTER(603),
-
-        @UiEvent(doc = "Activity enters picture-in-picture mode with auto-enter-pip API")
-        PICTURE_IN_PICTURE_AUTO_ENTER(1313),
-
-        @UiEvent(doc = "Activity enters picture-in-picture mode from content-pip API")
-        PICTURE_IN_PICTURE_ENTER_CONTENT_PIP(1314),
-
-        @UiEvent(doc = "Expands from picture-in-picture to fullscreen")
-        PICTURE_IN_PICTURE_EXPAND_TO_FULLSCREEN(604),
-
-        @UiEvent(doc = "Removes picture-in-picture by tap close button")
-        PICTURE_IN_PICTURE_TAP_TO_REMOVE(605),
-
-        @UiEvent(doc = "Removes picture-in-picture by drag to dismiss area")
-        PICTURE_IN_PICTURE_DRAG_TO_REMOVE(606),
-
-        @UiEvent(doc = "Shows picture-in-picture menu")
-        PICTURE_IN_PICTURE_SHOW_MENU(607),
-
-        @UiEvent(doc = "Hides picture-in-picture menu")
-        PICTURE_IN_PICTURE_HIDE_MENU(608),
-
-        @UiEvent(doc = "Changes the aspect ratio of picture-in-picture window. This is inherited"
-                + " from previous Tron-based logging and currently not in use.")
-        PICTURE_IN_PICTURE_CHANGE_ASPECT_RATIO(609),
-
-        @UiEvent(doc = "User resize of the picture-in-picture window")
-        PICTURE_IN_PICTURE_RESIZE(610),
-
-        @UiEvent(doc = "User unstashed picture-in-picture")
-        PICTURE_IN_PICTURE_STASH_UNSTASHED(709),
-
-        @UiEvent(doc = "User stashed picture-in-picture to the left side")
-        PICTURE_IN_PICTURE_STASH_LEFT(710),
-
-        @UiEvent(doc = "User stashed picture-in-picture to the right side")
-        PICTURE_IN_PICTURE_STASH_RIGHT(711),
-
-        @UiEvent(doc = "User taps on the settings button in PiP menu")
-        PICTURE_IN_PICTURE_SHOW_SETTINGS(933),
-
-        @UiEvent(doc = "Closes PiP with app-provided close action")
-        PICTURE_IN_PICTURE_CUSTOM_CLOSE(1058);
-
-        private final int mId;
-
-        PipUiEventEnum(int id) {
-            mId = id;
-        }
-
-        @Override
-        public int getId() {
-            return mId;
-        }
-    }
-}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PhonePipMenuController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PhonePipMenuController.java
index 5e1b6be..cc182ba 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PhonePipMenuController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PhonePipMenuController.java
@@ -38,12 +38,12 @@
 import com.android.internal.protolog.common.ProtoLog;
 import com.android.wm.shell.common.ShellExecutor;
 import com.android.wm.shell.common.SystemWindows;
+import com.android.wm.shell.common.pip.PipMediaController;
+import com.android.wm.shell.common.pip.PipMediaController.ActionListener;
+import com.android.wm.shell.common.pip.PipUiEventLogger;
 import com.android.wm.shell.pip.PipBoundsState;
-import com.android.wm.shell.pip.PipMediaController;
-import com.android.wm.shell.pip.PipMediaController.ActionListener;
 import com.android.wm.shell.pip.PipMenuController;
 import com.android.wm.shell.pip.PipSurfaceTransactionHelper;
-import com.android.wm.shell.pip.PipUiEventLogger;
 import com.android.wm.shell.protolog.ShellProtoLogGroup;
 import com.android.wm.shell.splitscreen.SplitScreenController;
 
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java
index b872267..5c65d78 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java
@@ -76,6 +76,7 @@
 import com.android.wm.shell.common.TaskStackListenerCallback;
 import com.android.wm.shell.common.TaskStackListenerImpl;
 import com.android.wm.shell.common.pip.PipAppOpsListener;
+import com.android.wm.shell.common.pip.PipMediaController;
 import com.android.wm.shell.onehanded.OneHandedController;
 import com.android.wm.shell.onehanded.OneHandedTransitionCallback;
 import com.android.wm.shell.pip.IPip;
@@ -87,7 +88,6 @@
 import com.android.wm.shell.pip.PipBoundsState;
 import com.android.wm.shell.pip.PipDisplayLayoutState;
 import com.android.wm.shell.pip.PipKeepClearAlgorithmInterface;
-import com.android.wm.shell.pip.PipMediaController;
 import com.android.wm.shell.pip.PipParamsChangedForwarder;
 import com.android.wm.shell.pip.PipSnapAlgorithm;
 import com.android.wm.shell.pip.PipTaskOrganizer;
@@ -123,14 +123,6 @@
     private static final long PIP_KEEP_CLEAR_AREAS_DELAY =
             SystemProperties.getLong("persist.wm.debug.pip_keep_clear_areas_delay", 200);
 
-    private boolean mEnablePipKeepClearAlgorithm =
-            SystemProperties.getBoolean("persist.wm.debug.enable_pip_keep_clear_algorithm", true);
-
-    @VisibleForTesting
-    void setEnablePipKeepClearAlgorithm(boolean value) {
-        mEnablePipKeepClearAlgorithm = value;
-    }
-
     private Context mContext;
     protected ShellExecutor mMainExecutor;
     private DisplayController mDisplayController;
@@ -166,10 +158,6 @@
             // early bail out if the change was caused by keyguard showing up
             return;
         }
-        if (!mEnablePipKeepClearAlgorithm) {
-            // early bail out if the keep clear areas feature is disabled
-            return;
-        }
         if (mPipBoundsState.isStashed()) {
             // don't move when stashed
             return;
@@ -187,10 +175,6 @@
     }
 
     private void updatePipPositionForKeepClearAreas() {
-        if (!mEnablePipKeepClearAlgorithm) {
-            // early bail out if the keep clear areas feature is disabled
-            return;
-        }
         if (mIsKeyguardShowingOrAnimating) {
             // early bail out if the change was caused by keyguard showing up
             return;
@@ -343,19 +327,17 @@
                 public void onKeepClearAreasChanged(int displayId, Set<Rect> restricted,
                         Set<Rect> unrestricted) {
                     if (mPipDisplayLayoutState.getDisplayId() == displayId) {
-                        if (mEnablePipKeepClearAlgorithm) {
-                            mPipBoundsState.setKeepClearAreas(restricted, unrestricted);
+                        mPipBoundsState.setKeepClearAreas(restricted, unrestricted);
 
-                            mMainExecutor.removeCallbacks(
-                                    mMovePipInResponseToKeepClearAreasChangeCallback);
-                            mMainExecutor.executeDelayed(
-                                    mMovePipInResponseToKeepClearAreasChangeCallback,
-                                    PIP_KEEP_CLEAR_AREAS_DELAY);
+                        mMainExecutor.removeCallbacks(
+                                mMovePipInResponseToKeepClearAreasChangeCallback);
+                        mMainExecutor.executeDelayed(
+                                mMovePipInResponseToKeepClearAreasChangeCallback,
+                                PIP_KEEP_CLEAR_AREAS_DELAY);
 
-                            ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
-                                    "onKeepClearAreasChanged: restricted=%s, unrestricted=%s",
-                                    restricted, unrestricted);
-                        }
+                        ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+                                "onKeepClearAreasChanged: restricted=%s, unrestricted=%s",
+                                restricted, unrestricted);
                     }
                 }
             };
@@ -660,25 +642,9 @@
                             // there's a keyguard present
                             return;
                         }
-                        int oldMaxMovementBound = mPipBoundsState.getMovementBounds().bottom;
                         onDisplayChangedUncheck(mDisplayController
                                         .getDisplayLayout(mPipDisplayLayoutState.getDisplayId()),
                                 false /* saveRestoreSnapFraction */);
-                        int newMaxMovementBound = mPipBoundsState.getMovementBounds().bottom;
-                        if (!mEnablePipKeepClearAlgorithm) {
-                            // offset PiP to adjust for bottom inset change
-                            int pipTop = mPipBoundsState.getBounds().top;
-                            int diff = newMaxMovementBound - oldMaxMovementBound;
-                            if (diff < 0 && pipTop > newMaxMovementBound) {
-                                // bottom inset has increased, move PiP up if it is too low
-                                mPipMotionHelper.animateToOffset(mPipBoundsState.getBounds(),
-                                        newMaxMovementBound - pipTop);
-                            }
-                            if (diff > 0 && oldMaxMovementBound == pipTop) {
-                                // bottom inset has decreased, move PiP down if it was by the edge
-                                mPipMotionHelper.animateToOffset(mPipBoundsState.getBounds(), diff);
-                            }
-                        }
                     }
                 });
 
@@ -947,14 +913,8 @@
      * Sets both shelf visibility and its height.
      */
     private void setShelfHeight(boolean visible, int height) {
-        if (mEnablePipKeepClearAlgorithm) {
-            // turn this into Launcher keep clear area registration instead
-            setLauncherKeepClearAreaHeight(visible, height);
-            return;
-        }
-        if (!mIsKeyguardShowingOrAnimating) {
-            setShelfHeightLocked(visible, height);
-        }
+        // turn this into Launcher keep clear area registration instead
+        setLauncherKeepClearAreaHeight(visible, height);
     }
 
     private void setLauncherKeepClearAreaHeight(boolean visible, int height) {
@@ -1015,16 +975,10 @@
     private Rect startSwipePipToHome(ComponentName componentName, ActivityInfo activityInfo,
             PictureInPictureParams pictureInPictureParams,
             int launcherRotation, Rect hotseatKeepClearArea) {
-
-        if (mEnablePipKeepClearAlgorithm) {
-            // preemptively add the keep clear area for Hotseat, so that it is taken into account
-            // when calculating the entry destination bounds of PiP window
-            mPipBoundsState.addNamedUnrestrictedKeepClearArea(LAUNCHER_KEEP_CLEAR_AREA_TAG,
-                    hotseatKeepClearArea);
-        } else {
-            int shelfHeight = hotseatKeepClearArea.height();
-            setShelfHeightLocked(shelfHeight > 0 /* visible */, shelfHeight);
-        }
+        // preemptively add the keep clear area for Hotseat, so that it is taken into account
+        // when calculating the entry destination bounds of PiP window
+        mPipBoundsState.addNamedUnrestrictedKeepClearArea(LAUNCHER_KEEP_CLEAR_AREA_TAG,
+                hotseatKeepClearArea);
         onDisplayRotationChangedNotInPip(mContext, launcherRotation);
         final Rect entryBounds = mPipTaskOrganizer.startSwipePipToHome(componentName, activityInfo,
                 pictureInPictureParams);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipDismissTargetHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipDismissTargetHandler.java
index da455f8..4e75847 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipDismissTargetHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipDismissTargetHandler.java
@@ -38,7 +38,7 @@
 import com.android.wm.shell.common.bubbles.DismissCircleView;
 import com.android.wm.shell.common.bubbles.DismissView;
 import com.android.wm.shell.common.magnetictarget.MagnetizedObject;
-import com.android.wm.shell.pip.PipUiEventLogger;
+import com.android.wm.shell.common.pip.PipUiEventLogger;
 
 import kotlin.Unit;
 
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMenuView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMenuView.java
index 779c539..837426a 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMenuView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMenuView.java
@@ -66,7 +66,7 @@
 import com.android.wm.shell.R;
 import com.android.wm.shell.animation.Interpolators;
 import com.android.wm.shell.common.ShellExecutor;
-import com.android.wm.shell.pip.PipUiEventLogger;
+import com.android.wm.shell.common.pip.PipUiEventLogger;
 import com.android.wm.shell.pip.PipUtils;
 import com.android.wm.shell.protolog.ShellProtoLogGroup;
 import com.android.wm.shell.splitscreen.SplitScreenController;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMotionHelper.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMotionHelper.java
index b251f6f..8f0a8e1 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMotionHelper.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMotionHelper.java
@@ -33,7 +33,6 @@
 import android.graphics.PointF;
 import android.graphics.Rect;
 import android.os.Debug;
-import android.os.SystemProperties;
 
 import com.android.internal.protolog.common.ProtoLog;
 import com.android.wm.shell.R;
@@ -48,19 +47,16 @@
 import com.android.wm.shell.pip.PipTransitionController;
 import com.android.wm.shell.protolog.ShellProtoLogGroup;
 
-import java.util.function.Consumer;
-
 import kotlin.Unit;
 import kotlin.jvm.functions.Function0;
 
+import java.util.function.Consumer;
+
 /**
  * A helper to animate and manipulate the PiP.
  */
 public class PipMotionHelper implements PipAppOpsListener.Callback,
         FloatingContentCoordinator.FloatingContent {
-
-    public static final boolean ENABLE_FLING_TO_DISMISS_PIP =
-            SystemProperties.getBoolean("persist.wm.debug.fling_to_dismiss_pip", false);
     private static final String TAG = "PipMotionHelper";
     private static final boolean DEBUG = false;
 
@@ -707,7 +703,7 @@
                     loc[1] = animatedPipBounds.top;
                 }
             };
-            mMagnetizedPip.setFlingToTargetEnabled(ENABLE_FLING_TO_DISMISS_PIP);
+            mMagnetizedPip.setFlingToTargetEnabled(false);
         }
 
         return mMagnetizedPip;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipResizeGestureHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipResizeGestureHandler.java
index abe2db0..4e687dd 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipResizeGestureHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipResizeGestureHandler.java
@@ -46,11 +46,11 @@
 import com.android.internal.policy.TaskResizingAlgorithm;
 import com.android.wm.shell.R;
 import com.android.wm.shell.common.ShellExecutor;
+import com.android.wm.shell.common.pip.PipUiEventLogger;
 import com.android.wm.shell.pip.PipAnimationController;
 import com.android.wm.shell.pip.PipBoundsAlgorithm;
 import com.android.wm.shell.pip.PipBoundsState;
 import com.android.wm.shell.pip.PipTaskOrganizer;
-import com.android.wm.shell.pip.PipUiEventLogger;
 
 import java.io.PrintWriter;
 import java.util.function.Consumer;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchHandler.java
index 3e95498a..6055fd9 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchHandler.java
@@ -34,7 +34,6 @@
 import android.graphics.Point;
 import android.graphics.PointF;
 import android.graphics.Rect;
-import android.os.SystemProperties;
 import android.provider.DeviceConfig;
 import android.util.Size;
 import android.view.DisplayCutout;
@@ -51,13 +50,13 @@
 import com.android.wm.shell.R;
 import com.android.wm.shell.common.FloatingContentCoordinator;
 import com.android.wm.shell.common.ShellExecutor;
+import com.android.wm.shell.common.pip.PipUiEventLogger;
 import com.android.wm.shell.common.pip.SizeSpecSource;
 import com.android.wm.shell.pip.PipAnimationController;
 import com.android.wm.shell.pip.PipBoundsAlgorithm;
 import com.android.wm.shell.pip.PipBoundsState;
 import com.android.wm.shell.pip.PipTaskOrganizer;
 import com.android.wm.shell.pip.PipTransitionController;
-import com.android.wm.shell.pip.PipUiEventLogger;
 import com.android.wm.shell.pip.PipUtils;
 import com.android.wm.shell.protolog.ShellProtoLogGroup;
 import com.android.wm.shell.sysui.ShellInit;
@@ -73,14 +72,6 @@
     private static final String TAG = "PipTouchHandler";
     private static final float DEFAULT_STASH_VELOCITY_THRESHOLD = 18000.f;
 
-    private boolean mEnablePipKeepClearAlgorithm =
-            SystemProperties.getBoolean("persist.wm.debug.enable_pip_keep_clear_algorithm", true);
-
-    @VisibleForTesting
-    void setEnablePipKeepClearAlgorithm(boolean value) {
-        mEnablePipKeepClearAlgorithm = value;
-    }
-
     // Allow PIP to resize to a slightly bigger state upon touch
     private boolean mEnableResize;
     private final Context mContext;
@@ -430,48 +421,6 @@
                 mIsImeShowing ? mImeOffset : 0,
                 !mIsImeShowing && mIsShelfShowing ? mShelfHeight : 0);
 
-        // If this is from an IME or shelf adjustment, then we should move the PiP so that it is not
-        // occluded by the IME or shelf.
-        if (fromImeAdjustment || fromShelfAdjustment) {
-            if (mTouchState.isUserInteracting() && mTouchState.isDragging()) {
-                // Defer the update of the current movement bounds until after the user finishes
-                // touching the screen
-            } else if (mEnablePipKeepClearAlgorithm) {
-                // Ignore moving PiP if keep clear algorithm is enabled, since IME and shelf height
-                // now are accounted for in the keep clear algorithm calculations
-            } else {
-                final boolean isExpanded = mMenuState == MENU_STATE_FULL && willResizeMenu();
-                final Rect toMovementBounds = new Rect();
-                mPipBoundsAlgorithm.getMovementBounds(curBounds, insetBounds,
-                        toMovementBounds, mIsImeShowing ? mImeHeight : 0);
-                final int prevBottom = mPipBoundsState.getMovementBounds().bottom
-                        - mMovementBoundsExtraOffsets;
-                // This is to handle landscape fullscreen IMEs, don't apply the extra offset in this
-                // case
-                final int toBottom = toMovementBounds.bottom < toMovementBounds.top
-                        ? toMovementBounds.bottom
-                        : toMovementBounds.bottom - extraOffset;
-
-                if (isExpanded) {
-                    curBounds.set(mPipBoundsState.getExpandedBounds());
-                    mPipBoundsAlgorithm.getSnapAlgorithm().applySnapFraction(curBounds,
-                            toMovementBounds, mSavedSnapFraction);
-                }
-
-                if (prevBottom < toBottom) {
-                    // The movement bounds are expanding
-                    if (curBounds.top > prevBottom - mBottomOffsetBufferPx) {
-                        mMotionHelper.animateToOffset(curBounds, toBottom - curBounds.top);
-                    }
-                } else if (prevBottom > toBottom) {
-                    // The movement bounds are shrinking
-                    if (curBounds.top > toBottom - mBottomOffsetBufferPx) {
-                        mMotionHelper.animateToOffset(curBounds, toBottom - curBounds.top);
-                    }
-                }
-            }
-        }
-
         // Update the movement bounds after doing the calculations based on the old movement bounds
         // above
         mPipBoundsState.setNormalMovementBounds(normalMovementBounds);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipActionsProvider.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipActionsProvider.java
index 3b44f10..7dc400c 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipActionsProvider.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipActionsProvider.java
@@ -35,7 +35,7 @@
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.protolog.common.ProtoLog;
 import com.android.wm.shell.R;
-import com.android.wm.shell.pip.PipMediaController;
+import com.android.wm.shell.common.pip.PipMediaController;
 import com.android.wm.shell.pip.PipUtils;
 import com.android.wm.shell.protolog.ShellProtoLogGroup;
 
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipController.java
index 5e583c2..0816dc7 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipController.java
@@ -48,11 +48,11 @@
 import com.android.wm.shell.common.TaskStackListenerCallback;
 import com.android.wm.shell.common.TaskStackListenerImpl;
 import com.android.wm.shell.common.pip.PipAppOpsListener;
+import com.android.wm.shell.common.pip.PipMediaController;
 import com.android.wm.shell.pip.PinnedStackListenerForwarder;
 import com.android.wm.shell.pip.Pip;
 import com.android.wm.shell.pip.PipAnimationController;
 import com.android.wm.shell.pip.PipDisplayLayoutState;
-import com.android.wm.shell.pip.PipMediaController;
 import com.android.wm.shell.pip.PipParamsChangedForwarder;
 import com.android.wm.shell.pip.PipTaskOrganizer;
 import com.android.wm.shell.pip.PipTransitionController;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipNotificationController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipNotificationController.java
index f22ee59..39c7a4b 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipNotificationController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipNotificationController.java
@@ -36,7 +36,7 @@
 import com.android.internal.protolog.common.ProtoLog;
 import com.android.internal.util.ImageUtils;
 import com.android.wm.shell.R;
-import com.android.wm.shell.pip.PipMediaController;
+import com.android.wm.shell.common.pip.PipMediaController;
 import com.android.wm.shell.pip.PipParamsChangedForwarder;
 import com.android.wm.shell.pip.PipUtils;
 import com.android.wm.shell.protolog.ShellProtoLogGroup;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipTaskOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipTaskOrganizer.java
index 4819f66..dbec607 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipTaskOrganizer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipTaskOrganizer.java
@@ -25,6 +25,7 @@
 import com.android.wm.shell.common.DisplayController;
 import com.android.wm.shell.common.ShellExecutor;
 import com.android.wm.shell.common.SyncTransactionQueue;
+import com.android.wm.shell.common.pip.PipUiEventLogger;
 import com.android.wm.shell.pip.PipAnimationController;
 import com.android.wm.shell.pip.PipBoundsAlgorithm;
 import com.android.wm.shell.pip.PipBoundsState;
@@ -35,7 +36,6 @@
 import com.android.wm.shell.pip.PipTaskOrganizer;
 import com.android.wm.shell.pip.PipTransitionController;
 import com.android.wm.shell.pip.PipTransitionState;
-import com.android.wm.shell.pip.PipUiEventLogger;
 import com.android.wm.shell.pip.PipUtils;
 import com.android.wm.shell.splitscreen.SplitScreenController;
 
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 2be7a49..29fff03 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
@@ -71,6 +71,7 @@
 import com.android.wm.shell.desktopmode.DesktopModeStatus;
 import com.android.wm.shell.desktopmode.DesktopTasksController;
 import com.android.wm.shell.freeform.FreeformTaskTransitionStarter;
+import com.android.wm.shell.splitscreen.SplitScreen;
 import com.android.wm.shell.splitscreen.SplitScreenController;
 import com.android.wm.shell.sysui.KeyguardChangeListener;
 import com.android.wm.shell.sysui.ShellController;
@@ -200,6 +201,19 @@
     @Override
     public void setSplitScreenController(SplitScreenController splitScreenController) {
         mSplitScreenController = splitScreenController;
+        mSplitScreenController.registerSplitScreenListener(new SplitScreen.SplitScreenListener() {
+            @Override
+            public void onTaskStageChanged(int taskId, int stage, boolean visible) {
+                if (visible) {
+                    DesktopModeWindowDecoration decor = mWindowDecorByTaskId.get(taskId);
+                    if (decor != null && DesktopModeStatus.isActive(mContext)
+                            && decor.mTaskInfo.getWindowingMode() == WINDOWING_MODE_FREEFORM) {
+                        mDesktopModeController.ifPresent(c -> c.setDesktopModeActive(false));
+                        mDesktopTasksController.ifPresent(c -> c.moveToSplit(decor.mTaskInfo));
+                    }
+                }
+            }
+        });
     }
 
     @Override
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipTaskOrganizerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipTaskOrganizerTest.java
index 1e3fe42..248d665 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipTaskOrganizerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipTaskOrganizerTest.java
@@ -53,6 +53,7 @@
 import com.android.wm.shell.common.DisplayLayout;
 import com.android.wm.shell.common.SyncTransactionQueue;
 import com.android.wm.shell.common.pip.PhoneSizeSpecSource;
+import com.android.wm.shell.common.pip.PipUiEventLogger;
 import com.android.wm.shell.common.pip.SizeSpecSource;
 import com.android.wm.shell.pip.phone.PhonePipMenuController;
 import com.android.wm.shell.splitscreen.SplitScreenController;
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipControllerTest.java
index 0ae2908..911f5e1 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipControllerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipControllerTest.java
@@ -56,12 +56,12 @@
 import com.android.wm.shell.common.TabletopModeController;
 import com.android.wm.shell.common.TaskStackListenerImpl;
 import com.android.wm.shell.common.pip.PipAppOpsListener;
+import com.android.wm.shell.common.pip.PipMediaController;
 import com.android.wm.shell.onehanded.OneHandedController;
 import com.android.wm.shell.pip.PipAnimationController;
 import com.android.wm.shell.pip.PipBoundsAlgorithm;
 import com.android.wm.shell.pip.PipBoundsState;
 import com.android.wm.shell.pip.PipDisplayLayoutState;
-import com.android.wm.shell.pip.PipMediaController;
 import com.android.wm.shell.pip.PipParamsChangedForwarder;
 import com.android.wm.shell.pip.PipSnapAlgorithm;
 import com.android.wm.shell.pip.PipTaskOrganizer;
@@ -76,7 +76,6 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.Mock;
-import org.mockito.Mockito;
 import org.mockito.MockitoAnnotations;
 
 import java.util.Optional;
@@ -329,21 +328,7 @@
     }
 
     @Test
-    public void onKeepClearAreasChanged_featureDisabled_pipBoundsStateDoesntChange() {
-        mPipController.setEnablePipKeepClearAlgorithm(false);
-        final int displayId = 1;
-        final Rect keepClearArea = new Rect(0, 0, 10, 10);
-        when(mMockPipDisplayLayoutState.getDisplayId()).thenReturn(displayId);
-
-        mPipController.mDisplaysChangedListener.onKeepClearAreasChanged(
-                displayId, Set.of(keepClearArea), Set.of());
-
-        verify(mMockPipBoundsState, never()).setKeepClearAreas(Mockito.anySet(), Mockito.anySet());
-    }
-
-    @Test
-    public void onKeepClearAreasChanged_featureEnabled_updatesPipBoundsState() {
-        mPipController.setEnablePipKeepClearAlgorithm(true);
+    public void onKeepClearAreasChanged_updatesPipBoundsState() {
         final int displayId = 1;
         final Rect keepClearArea = new Rect(0, 0, 10, 10);
         when(mMockPipDisplayLayoutState.getDisplayId()).thenReturn(displayId);
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipResizeGestureHandlerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipResizeGestureHandlerTest.java
index 689b5c5..12b4f3e 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipResizeGestureHandlerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipResizeGestureHandlerTest.java
@@ -37,6 +37,7 @@
 import com.android.wm.shell.common.FloatingContentCoordinator;
 import com.android.wm.shell.common.ShellExecutor;
 import com.android.wm.shell.common.pip.PhoneSizeSpecSource;
+import com.android.wm.shell.common.pip.PipUiEventLogger;
 import com.android.wm.shell.common.pip.SizeSpecSource;
 import com.android.wm.shell.pip.PipBoundsAlgorithm;
 import com.android.wm.shell.pip.PipBoundsState;
@@ -45,7 +46,6 @@
 import com.android.wm.shell.pip.PipSnapAlgorithm;
 import com.android.wm.shell.pip.PipTaskOrganizer;
 import com.android.wm.shell.pip.PipTransitionController;
-import com.android.wm.shell.pip.PipUiEventLogger;
 
 import org.junit.Before;
 import org.junit.Test;
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipTouchHandlerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipTouchHandlerTest.java
index 852183c..314f195d 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipTouchHandlerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipTouchHandlerTest.java
@@ -18,7 +18,6 @@
 
 import static org.junit.Assert.assertEquals;
 import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 
@@ -34,6 +33,7 @@
 import com.android.wm.shell.common.FloatingContentCoordinator;
 import com.android.wm.shell.common.ShellExecutor;
 import com.android.wm.shell.common.pip.PhoneSizeSpecSource;
+import com.android.wm.shell.common.pip.PipUiEventLogger;
 import com.android.wm.shell.common.pip.SizeSpecSource;
 import com.android.wm.shell.pip.PipBoundsAlgorithm;
 import com.android.wm.shell.pip.PipBoundsState;
@@ -42,7 +42,6 @@
 import com.android.wm.shell.pip.PipSnapAlgorithm;
 import com.android.wm.shell.pip.PipTaskOrganizer;
 import com.android.wm.shell.pip.PipTransitionController;
-import com.android.wm.shell.pip.PipUiEventLogger;
 import com.android.wm.shell.sysui.ShellInit;
 
 import org.junit.Before;
@@ -174,16 +173,4 @@
         verify(mPipResizeGestureHandler, times(1))
                 .updateMaxSize(expectedMaxSize.getWidth(), expectedMaxSize.getHeight());
     }
-
-    @Test
-    public void updateMovementBounds_withImeAdjustment_movesPip() {
-        mPipTouchHandler.setEnablePipKeepClearAlgorithm(false);
-        mFromImeAdjustment = true;
-        mPipTouchHandler.onImeVisibilityChanged(true /* imeVisible */, mImeHeight);
-
-        mPipTouchHandler.onMovementBoundsChanged(mInsetBounds, mPipBounds, mCurBounds,
-                mFromImeAdjustment, mFromShelfAdjustment, mDisplayRotation);
-
-        verify(mMotionHelper, times(1)).animateToOffset(any(), anyInt());
-    }
 }
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/tv/TvPipActionProviderTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/tv/TvPipActionProviderTest.java
index 02e6b8c..c40cd406 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/tv/TvPipActionProviderTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/tv/TvPipActionProviderTest.java
@@ -37,7 +37,7 @@
 import android.util.Log;
 
 import com.android.wm.shell.ShellTestCase;
-import com.android.wm.shell.pip.PipMediaController;
+import com.android.wm.shell.common.pip.PipMediaController;
 
 import org.junit.Before;
 import org.junit.Test;
diff --git a/libs/androidfw/AssetManager.cpp b/libs/androidfw/AssetManager.cpp
index fb2b571..795bb3c 100644
--- a/libs/androidfw/AssetManager.cpp
+++ b/libs/androidfw/AssetManager.cpp
@@ -91,7 +91,7 @@
     path.appendPath(kResourceCache);
 
     char buf[256]; // 256 chars should be enough for anyone...
-    strncpy(buf, pkgPath.string(), 255);
+    strncpy(buf, pkgPath.c_str(), 255);
     buf[255] = '\0';
     char* filename = buf;
     while (*filename && *filename == '/') {
@@ -183,15 +183,15 @@
     if (kAppZipName) {
         realPath.appendPath(kAppZipName);
     }
-    ap.type = ::getFileType(realPath.string());
+    ap.type = ::getFileType(realPath.c_str());
     if (ap.type == kFileTypeRegular) {
         ap.path = realPath;
     } else {
         ap.path = path;
-        ap.type = ::getFileType(path.string());
+        ap.type = ::getFileType(path.c_str());
         if (ap.type != kFileTypeDirectory && ap.type != kFileTypeRegular) {
             ALOGW("Asset path %s is neither a directory nor file (type=%d).",
-                 path.string(), (int)ap.type);
+                 path.c_str(), (int)ap.type);
             return false;
         }
     }
@@ -207,7 +207,7 @@
     }
 
     ALOGV("In %p Asset %s path: %s", this,
-         ap.type == kFileTypeDirectory ? "dir" : "zip", ap.path.string());
+         ap.type == kFileTypeDirectory ? "dir" : "zip", ap.path.c_str());
 
     ap.isSystemAsset = isSystemAsset;
     ssize_t apPos = mAssetPaths.add(ap);
@@ -248,7 +248,7 @@
 
     Asset* idmap = NULL;
     if ((idmap = openAssetFromFileLocked(idmapPath, Asset::ACCESS_BUFFER)) == NULL) {
-        ALOGW("failed to open idmap file %s\n", idmapPath.string());
+        ALOGW("failed to open idmap file %s\n", idmapPath.c_str());
         return false;
     }
 
@@ -256,7 +256,7 @@
     String8 overlayPath;
     if (!ResTable::getIdmapInfo(idmap->getBuffer(false), idmap->getLength(),
                 NULL, NULL, NULL, &targetPath, &overlayPath)) {
-        ALOGW("failed to read idmap file %s\n", idmapPath.string());
+        ALOGW("failed to read idmap file %s\n", idmapPath.c_str());
         delete idmap;
         return false;
     }
@@ -264,29 +264,29 @@
 
     if (overlayPath != packagePath) {
         ALOGW("idmap file %s inconcistent: expected path %s does not match actual path %s\n",
-                idmapPath.string(), packagePath.string(), overlayPath.string());
+                idmapPath.c_str(), packagePath.c_str(), overlayPath.c_str());
         return false;
     }
-    if (access(targetPath.string(), R_OK) != 0) {
-        ALOGW("failed to access file %s: %s\n", targetPath.string(), strerror(errno));
+    if (access(targetPath.c_str(), R_OK) != 0) {
+        ALOGW("failed to access file %s: %s\n", targetPath.c_str(), strerror(errno));
         return false;
     }
-    if (access(idmapPath.string(), R_OK) != 0) {
-        ALOGW("failed to access file %s: %s\n", idmapPath.string(), strerror(errno));
+    if (access(idmapPath.c_str(), R_OK) != 0) {
+        ALOGW("failed to access file %s: %s\n", idmapPath.c_str(), strerror(errno));
         return false;
     }
-    if (access(overlayPath.string(), R_OK) != 0) {
-        ALOGW("failed to access file %s: %s\n", overlayPath.string(), strerror(errno));
+    if (access(overlayPath.c_str(), R_OK) != 0) {
+        ALOGW("failed to access file %s: %s\n", overlayPath.c_str(), strerror(errno));
         return false;
     }
 
     asset_path oap;
     oap.path = overlayPath;
-    oap.type = ::getFileType(overlayPath.string());
+    oap.type = ::getFileType(overlayPath.c_str());
     oap.idmap = idmapPath;
 #if 0
     ALOGD("Overlay added: targetPath=%s overlayPath=%s idmapPath=%s\n",
-            targetPath.string(), overlayPath.string(), idmapPath.string());
+            targetPath.c_str(), overlayPath.c_str(), idmapPath.c_str());
 #endif
     mAssetPaths.add(oap);
     *cookie = static_cast<int32_t>(mAssetPaths.size());
@@ -310,7 +310,7 @@
     ap.type = kFileTypeRegular;
     ap.assumeOwnership = assume_ownership;
 
-    ALOGV("In %p Asset fd %d name: %s", this, fd, ap.path.string());
+    ALOGV("In %p Asset fd %d name: %s", this, fd, ap.path.c_str());
 
     ssize_t apPos = mAssetPaths.add(ap);
 
@@ -343,11 +343,11 @@
             assets[i] = openNonAssetInPathLocked("resources.arsc",
                     Asset::ACCESS_BUFFER, ap);
             if (assets[i] == NULL) {
-                ALOGW("failed to find resources.arsc in %s\n", ap.path.string());
+                ALOGW("failed to find resources.arsc in %s\n", ap.path.c_str());
                 goto exit;
             }
             if (tables[i].add(assets[i]) != NO_ERROR) {
-                ALOGW("failed to add %s to resource table", paths[i].string());
+                ALOGW("failed to add %s to resource table", paths[i].c_str());
                 goto exit;
             }
         }
@@ -449,8 +449,8 @@
     while (i > 0) {
         i--;
         ALOGV("Looking for asset '%s' in '%s'\n",
-                assetName.string(), mAssetPaths.itemAt(i).path.string());
-        Asset* pAsset = openNonAssetInPathLocked(assetName.string(), mode,
+                assetName.c_str(), mAssetPaths.itemAt(i).path.c_str());
+        Asset* pAsset = openNonAssetInPathLocked(assetName.c_str(), mode,
                 mAssetPaths.editItemAt(i));
         if (pAsset != NULL) {
             return pAsset != kExcludedAsset ? pAsset : NULL;
@@ -478,7 +478,7 @@
     size_t i = mAssetPaths.size();
     while (i > 0) {
         i--;
-        ALOGV("Looking for non-asset '%s' in '%s'\n", fileName, mAssetPaths.itemAt(i).path.string());
+        ALOGV("Looking for non-asset '%s' in '%s'\n", fileName, mAssetPaths.itemAt(i).path.c_str());
         Asset* pAsset = openNonAssetInPathLocked(
             fileName, mode, mAssetPaths.editItemAt(i));
         if (pAsset != NULL) {
@@ -500,7 +500,7 @@
 
     if (which < mAssetPaths.size()) {
         ALOGV("Looking for non-asset '%s' in '%s'\n", fileName,
-                mAssetPaths.itemAt(which).path.string());
+                mAssetPaths.itemAt(which).path.c_str());
         Asset* pAsset = openNonAssetInPathLocked(
             fileName, mode, mAssetPaths.editItemAt(which));
         if (pAsset != NULL) {
@@ -546,10 +546,10 @@
     ResTable* sharedRes = NULL;
     bool shared = true;
     bool onlyEmptyResources = true;
-    ATRACE_NAME(ap.path.string());
+    ATRACE_NAME(ap.path.c_str());
     Asset* idmap = openIdmapLocked(ap);
     size_t nextEntryIdx = mResources->getTableCount();
-    ALOGV("Looking for resource asset in '%s'\n", ap.path.string());
+    ALOGV("Looking for resource asset in '%s'\n", ap.path.c_str());
     if (ap.type != kFileTypeDirectory && ap.rawFd < 0) {
         if (nextEntryIdx == 0) {
             // The first item is typically the framework resources,
@@ -565,7 +565,7 @@
             ass = const_cast<AssetManager*>(this)->
                 mZipSet.getZipResourceTableAsset(ap.path);
             if (ass == NULL) {
-                ALOGV("loading resource table %s\n", ap.path.string());
+                ALOGV("loading resource table %s\n", ap.path.c_str());
                 ass = const_cast<AssetManager*>(this)->
                     openNonAssetInPathLocked("resources.arsc",
                                              Asset::ACCESS_BUFFER,
@@ -580,7 +580,7 @@
                 // If this is the first resource table in the asset
                 // manager, then we are going to cache it so that we
                 // can quickly copy it out for others.
-                ALOGV("Creating shared resources for %s", ap.path.string());
+                ALOGV("Creating shared resources for %s", ap.path.c_str());
                 sharedRes = new ResTable();
                 sharedRes->add(ass, idmap, nextEntryIdx + 1, false);
 #ifdef __ANDROID__
@@ -589,14 +589,14 @@
                 String8 overlaysListPath(data);
                 overlaysListPath.appendPath(kResourceCache);
                 overlaysListPath.appendPath("overlays.list");
-                addSystemOverlays(overlaysListPath.string(), ap.path, sharedRes, nextEntryIdx);
+                addSystemOverlays(overlaysListPath.c_str(), ap.path, sharedRes, nextEntryIdx);
 #endif
                 sharedRes = const_cast<AssetManager*>(this)->
                     mZipSet.setZipResourceTable(ap.path, sharedRes);
             }
         }
     } else {
-        ALOGV("loading resource table %s\n", ap.path.string());
+        ALOGV("loading resource table %s\n", ap.path.c_str());
         ass = const_cast<AssetManager*>(this)->
             openNonAssetInPathLocked("resources.arsc",
                                      Asset::ACCESS_BUFFER,
@@ -607,10 +607,10 @@
     if ((ass != NULL || sharedRes != NULL) && ass != kExcludedAsset) {
         ALOGV("Installing resource asset %p in to table %p\n", ass, mResources);
         if (sharedRes != NULL) {
-            ALOGV("Copying existing resources for %s", ap.path.string());
+            ALOGV("Copying existing resources for %s", ap.path.c_str());
             mResources->add(sharedRes, ap.isSystemAsset);
         } else {
-            ALOGV("Parsing resources for %s", ap.path.string());
+            ALOGV("Parsing resources for %s", ap.path.c_str());
             mResources->add(ass, idmap, nextEntryIdx + 1, !shared, appAsLib, ap.isSystemAsset);
         }
         onlyEmptyResources = false;
@@ -692,9 +692,9 @@
         ass = const_cast<AssetManager*>(this)->
             openAssetFromFileLocked(ap.idmap, Asset::ACCESS_BUFFER);
         if (ass) {
-            ALOGV("loading idmap %s\n", ap.idmap.string());
+            ALOGV("loading idmap %s\n", ap.idmap.c_str());
         } else {
-            ALOGW("failed to load idmap %s\n", ap.idmap.string());
+            ALOGW("failed to load idmap %s\n", ap.idmap.c_str());
         }
     }
     return ass;
@@ -812,7 +812,7 @@
         ZipFileRO* pZip = getZipFileLocked(ap);
         if (pZip != NULL) {
             ALOGV("GOT zip, checking NA '%s'", (const char*) path);
-            ZipEntryRO entry = pZip->findEntryByName(path.string());
+            ZipEntryRO entry = pZip->findEntryByName(path.c_str());
             if (entry != NULL) {
                 ALOGV("FOUND NA in Zip file for %s", (const char*) path);
                 pAsset = openAssetFromZipLocked(pZip, entry, mode, path);
@@ -823,7 +823,7 @@
         if (pAsset != NULL) {
             /* create a "source" name, for debug/display */
             pAsset->setAssetSource(
-                    createZipSourceNameLocked(ZipSet::getPathName(ap.path.string()), String8(""),
+                    createZipSourceNameLocked(ZipSet::getPathName(ap.path.c_str()), String8(""),
                                                 String8(fileName)));
         }
     }
@@ -870,7 +870,7 @@
     }
 
     if (ap.rawFd < 0) {
-        ALOGV("getZipFileLocked: Creating new zip from path %s", ap.path.string());
+        ALOGV("getZipFileLocked: Creating new zip from path %s", ap.path.c_str());
         ap.zip = mZipSet.getSharedZip(ap.path);
     } else {
         ALOGV("getZipFileLocked: Creating new zip from fd %d", ap.rawFd);
@@ -897,12 +897,12 @@
 {
     Asset* pAsset = NULL;
 
-    if (strcasecmp(pathName.getPathExtension().string(), ".gz") == 0) {
+    if (strcasecmp(pathName.getPathExtension().c_str(), ".gz") == 0) {
         //printf("TRYING '%s'\n", (const char*) pathName);
-        pAsset = Asset::createFromCompressedFile(pathName.string(), mode);
+        pAsset = Asset::createFromCompressedFile(pathName.c_str(), mode);
     } else {
         //printf("TRYING '%s'\n", (const char*) pathName);
-        pAsset = Asset::createFromFile(pathName.string(), mode);
+        pAsset = Asset::createFromFile(pathName.c_str(), mode);
     }
 
     return pAsset;
@@ -940,12 +940,12 @@
 
     if (method == ZipFileRO::kCompressStored) {
         pAsset = Asset::createFromUncompressedMap(std::move(*dataMap), mode);
-        ALOGV("Opened uncompressed entry %s in zip %s mode %d: %p", entryName.string(),
+        ALOGV("Opened uncompressed entry %s in zip %s mode %d: %p", entryName.c_str(),
                 dataMap->file_name(), mode, pAsset.get());
     } else {
         pAsset = Asset::createFromCompressedMap(std::move(*dataMap),
             static_cast<size_t>(uncompressedLen), mode);
-        ALOGV("Opened compressed entry %s in zip %s mode %d: %p", entryName.string(),
+        ALOGV("Opened compressed entry %s in zip %s mode %d: %p", entryName.c_str(),
                 dataMap->file_name(), mode, pAsset.get());
     }
     if (pAsset == NULL) {
@@ -993,10 +993,10 @@
         i--;
         const asset_path& ap = mAssetPaths.itemAt(i);
         if (ap.type == kFileTypeRegular) {
-            ALOGV("Adding directory %s from zip %s", dirName, ap.path.string());
+            ALOGV("Adding directory %s from zip %s", dirName, ap.path.c_str());
             scanAndMergeZipLocked(pMergedInfo, ap, kAssetsRoot, dirName);
         } else {
-            ALOGV("Adding directory %s from dir %s", dirName, ap.path.string());
+            ALOGV("Adding directory %s from dir %s", dirName, ap.path.c_str());
             scanAndMergeDirLocked(pMergedInfo, ap, kAssetsRoot, dirName);
         }
     }
@@ -1042,10 +1042,10 @@
     if (which < mAssetPaths.size()) {
         const asset_path& ap = mAssetPaths.itemAt(which);
         if (ap.type == kFileTypeRegular) {
-            ALOGV("Adding directory %s from zip %s", dirName, ap.path.string());
+            ALOGV("Adding directory %s from zip %s", dirName, ap.path.c_str());
             scanAndMergeZipLocked(pMergedInfo, ap, NULL, dirName);
         } else {
-            ALOGV("Adding directory %s from dir %s", dirName, ap.path.string());
+            ALOGV("Adding directory %s from dir %s", dirName, ap.path.c_str());
             scanAndMergeDirLocked(pMergedInfo, ap, NULL, dirName);
         }
     }
@@ -1075,7 +1075,7 @@
 {
     assert(pMergedInfo != NULL);
 
-    //printf("scanAndMergeDir: %s %s %s\n", ap.path.string(), rootDir, dirName);
+    //printf("scanAndMergeDir: %s %s %s\n", ap.path.c_str(), rootDir, dirName);
 
     String8 path = createPathNameLocked(ap, rootDir);
     if (dirName[0] != '\0')
@@ -1100,7 +1100,7 @@
         const char* name;
         int nameLen;
 
-        name = pContents->itemAt(i).getFileName().string();
+        name = pContents->itemAt(i).getFileName().c_str();
         nameLen = strlen(name);
         if (nameLen > exclExtLen &&
             strcmp(name + (nameLen - exclExtLen), kExcludeExtension) == 0)
@@ -1111,8 +1111,8 @@
             matchIdx = AssetDir::FileInfo::findEntry(pMergedInfo, match);
             if (matchIdx > 0) {
                 ALOGV("Excluding '%s' [%s]\n",
-                    pMergedInfo->itemAt(matchIdx).getFileName().string(),
-                    pMergedInfo->itemAt(matchIdx).getSourceName().string());
+                    pMergedInfo->itemAt(matchIdx).getFileName().c_str(),
+                    pMergedInfo->itemAt(matchIdx).getSourceName().c_str());
                 pMergedInfo->removeAt(matchIdx);
             } else {
                 //printf("+++ no match on '%s'\n", (const char*) match);
@@ -1150,9 +1150,9 @@
     struct dirent* entry;
     FileType fileType;
 
-    ALOGV("Scanning dir '%s'\n", path.string());
+    ALOGV("Scanning dir '%s'\n", path.c_str());
 
-    dir = opendir(path.string());
+    dir = opendir(path.c_str());
     if (dir == NULL)
         return NULL;
 
@@ -1176,7 +1176,7 @@
             fileType = kFileTypeUnknown;
 #else
         // stat the file
-        fileType = ::getFileType(path.appendPathCopy(entry->d_name).string());
+        fileType = ::getFileType(path.appendPathCopy(entry->d_name).c_str());
 #endif
 
         if (fileType != kFileTypeRegular && fileType != kFileTypeDirectory)
@@ -1184,7 +1184,7 @@
 
         AssetDir::FileInfo info;
         info.set(String8(entry->d_name), fileType);
-        if (strcasecmp(info.getFileName().getPathExtension().string(), ".gz") == 0)
+        if (strcasecmp(info.getFileName().getPathExtension().c_str(), ".gz") == 0)
             info.setFileName(info.getFileName().getBasePath());
         info.setSourceName(path.appendPathCopy(info.getFileName()));
         pContents->add(info);
@@ -1212,11 +1212,11 @@
 
     pZip = mZipSet.getZip(ap.path);
     if (pZip == NULL) {
-        ALOGW("Failure opening zip %s\n", ap.path.string());
+        ALOGW("Failure opening zip %s\n", ap.path.c_str());
         return false;
     }
 
-    zipName = ZipSet::getPathName(ap.path.string());
+    zipName = ZipSet::getPathName(ap.path.c_str());
 
     /* convert "sounds" to "rootDir/sounds" */
     if (rootDir != NULL) dirName = rootDir;
@@ -1240,7 +1240,7 @@
      */
     int dirNameLen = dirName.length();
     void *iterationCookie;
-    if (!pZip->startIteration(&iterationCookie, dirName.string(), NULL)) {
+    if (!pZip->startIteration(&iterationCookie, dirName.c_str(), NULL)) {
         ALOGW("ZipFileRO::startIteration returned false");
         return false;
     }
@@ -1254,7 +1254,7 @@
             ALOGE("ARGH: name too long?\n");
             continue;
         }
-        //printf("Comparing %s in %s?\n", nameBuf, dirName.string());
+        //printf("Comparing %s in %s?\n", nameBuf, dirName.c_str());
         if (dirNameLen == 0 || nameBuf[dirNameLen] == '/')
         {
             const char* cp;
@@ -1275,7 +1275,7 @@
                     createZipSourceNameLocked(zipName, dirName, info.getFileName()));
 
                 contents.add(info);
-                //printf("FOUND: file '%s'\n", info.getFileName().string());
+                //printf("FOUND: file '%s'\n", info.getFileName().c_str());
             } else {
                 /* this is a subdir; add it if we don't already have it*/
                 String8 subdirName(cp, nextSlash - cp);
@@ -1291,7 +1291,7 @@
                     dirs.add(subdirName);
                 }
 
-                //printf("FOUND: dir '%s'\n", subdirName.string());
+                //printf("FOUND: dir '%s'\n", subdirName.c_str());
             }
         }
     }
@@ -1427,10 +1427,10 @@
     if (kIsDebug) {
         ALOGI("Creating SharedZip %p %s\n", this, (const char*)mPath);
     }
-    ALOGV("+++ opening zip '%s'\n", mPath.string());
-    mZipFile = ZipFileRO::open(mPath.string());
+    ALOGV("+++ opening zip '%s'\n", mPath.c_str());
+    mZipFile = ZipFileRO::open(mPath.c_str());
     if (mZipFile == NULL) {
-        ALOGD("failed to open Zip archive '%s'\n", mPath.string());
+        ALOGD("failed to open Zip archive '%s'\n", mPath.c_str());
     }
 }
 
@@ -1441,11 +1441,11 @@
     if (kIsDebug) {
         ALOGI("Creating SharedZip %p fd=%d %s\n", this, fd, (const char*)mPath);
     }
-    ALOGV("+++ opening zip fd=%d '%s'\n", fd, mPath.string());
-    mZipFile = ZipFileRO::openFd(fd, mPath.string());
+    ALOGV("+++ opening zip fd=%d '%s'\n", fd, mPath.c_str());
+    mZipFile = ZipFileRO::openFd(fd, mPath.c_str());
     if (mZipFile == NULL) {
         ::close(fd);
-        ALOGD("failed to open Zip archive fd=%d '%s'\n", fd, mPath.string());
+        ALOGD("failed to open Zip archive fd=%d '%s'\n", fd, mPath.c_str());
     }
 }
 
@@ -1520,7 +1520,7 @@
 
 bool AssetManager::SharedZip::isUpToDate()
 {
-    time_t modWhen = getFileModDate(mPath.string());
+    time_t modWhen = getFileModDate(mPath.c_str());
     return mModWhen == modWhen;
 }
 
@@ -1551,7 +1551,7 @@
     }
     if (mZipFile != NULL) {
         delete mZipFile;
-        ALOGV("Closed '%s'\n", mPath.string());
+        ALOGV("Closed '%s'\n", mPath.c_str());
     }
 }
 
diff --git a/libs/androidfw/BackupData.cpp b/libs/androidfw/BackupData.cpp
index 76a430e..fec0e77 100644
--- a/libs/androidfw/BackupData.cpp
+++ b/libs/androidfw/BackupData.cpp
@@ -106,8 +106,8 @@
         k = key;
     }
     if (kIsDebug) {
-        ALOGD("Writing header: prefix='%s' key='%s' dataSize=%zu", m_keyPrefix.string(),
-                key.string(), dataSize);
+        ALOGD("Writing header: prefix='%s' key='%s' dataSize=%zu", m_keyPrefix.c_str(),
+                key.c_str(), dataSize);
     }
 
     entity_header_v1 header;
@@ -128,7 +128,7 @@
     m_pos += amt;
 
     if (kIsDebug) ALOGI("writing entity header key, %zd bytes", keyLen+1);
-    amt = write(m_fd, k.string(), keyLen+1);
+    amt = write(m_fd, k.c_str(), keyLen+1);
     if (amt != keyLen+1) {
         m_status = errno;
         return m_status;
diff --git a/libs/androidfw/BackupHelpers.cpp b/libs/androidfw/BackupHelpers.cpp
index e80e948..3582609 100644
--- a/libs/androidfw/BackupHelpers.cpp
+++ b/libs/androidfw/BackupHelpers.cpp
@@ -179,7 +179,7 @@
             }
 
             // filename is not NULL terminated, but it is padded
-            amt = write(fd, name.string(), nameLen);
+            amt = write(fd, name.c_str(), nameLen);
             if (amt != nameLen) {
                 ALOGW("write_snapshot_file error writing filename %s", strerror(errno));
                 return 1;
@@ -203,7 +203,7 @@
 static int
 write_delete_file(BackupDataWriter* dataStream, const String8& key)
 {
-    LOGP("write_delete_file %s\n", key.string());
+    LOGP("write_delete_file %s\n", key.c_str());
     return dataStream->WriteEntityHeader(key, -1);
 }
 
@@ -211,7 +211,7 @@
 write_update_file(BackupDataWriter* dataStream, int fd, int mode, const String8& key,
         char const* realFilename)
 {
-    LOGP("write_update_file %s (%s) : mode 0%o\n", realFilename, key.string(), mode);
+    LOGP("write_update_file %s (%s) : mode 0%o\n", realFilename, key.c_str(), mode);
 
     const int bufsize = 4*1024;
     int err;
@@ -365,7 +365,7 @@
             r.s.size = st.st_size;
 
             if (newSnapshot.indexOfKey(key) >= 0) {
-                LOGP("back_up_files key already in use '%s'", key.string());
+                LOGP("back_up_files key already in use '%s'", key.c_str());
                 return -1;
             }
 
@@ -390,30 +390,30 @@
         int cmp = p.compare(q);
         if (cmp < 0) {
             // file present in oldSnapshot, but not present in newSnapshot
-            LOGP("file removed: %s", p.string());
+            LOGP("file removed: %s", p.c_str());
             write_delete_file(dataStream, p);
             n++;
         } else if (cmp > 0) {
             // file added
-            LOGP("file added: %s crc=0x%08x", g.file.string(), g.s.crc32);
-            write_update_file(dataStream, q, g.file.string());
+            LOGP("file added: %s crc=0x%08x", g.file.c_str(), g.s.crc32);
+            write_update_file(dataStream, q, g.file.c_str());
             m++;
         } else {
             // same file exists in both old and new; check whether to update
             const FileState& f = oldSnapshot.valueAt(n);
 
-            LOGP("%s", q.string());
+            LOGP("%s", q.c_str());
             LOGP("  old: modTime=%d,%d mode=%04o size=%-3d crc32=0x%08x",
                     f.modTime_sec, f.modTime_nsec, f.mode, f.size, f.crc32);
             LOGP("  new: modTime=%d,%d mode=%04o size=%-3d crc32=0x%08x",
                     g.s.modTime_sec, g.s.modTime_nsec, g.s.mode, g.s.size, g.s.crc32);
             if (f.modTime_sec != g.s.modTime_sec || f.modTime_nsec != g.s.modTime_nsec
                     || f.mode != g.s.mode || f.size != g.s.size || f.crc32 != g.s.crc32) {
-                int fd = open(g.file.string(), O_RDONLY);
+                int fd = open(g.file.c_str(), O_RDONLY);
                 if (fd < 0) {
-                    ALOGE("Unable to read file for backup: %s", g.file.string());
+                    ALOGE("Unable to read file for backup: %s", g.file.c_str());
                 } else {
-                    write_update_file(dataStream, fd, g.s.mode, p, g.file.string());
+                    write_update_file(dataStream, fd, g.s.mode, p, g.file.c_str());
                     close(fd);
                 }
             }
@@ -432,7 +432,7 @@
     while (m<M) {
         const String8& q = newSnapshot.keyAt(m);
         FileRec& g = newSnapshot.editValueAt(m);
-        write_update_file(dataStream, q, g.file.string());
+        write_update_file(dataStream, q, g.file.c_str());
         m++;
     }
 
@@ -483,7 +483,7 @@
         BackupDataWriter* writer)
 {
     // In the output stream everything is stored relative to the root
-    const char* relstart = filepath.string() + rootpath.length();
+    const char* relstart = filepath.c_str() + rootpath.length();
     if (*relstart == '/') relstart++;     // won't be true when path == rootpath
     String8 relpath(relstart);
 
@@ -514,9 +514,9 @@
 
     int err = 0;
     struct stat64 s;
-    if (lstat64(filepath.string(), &s) != 0) {
+    if (lstat64(filepath.c_str(), &s) != 0) {
         err = errno;
-        ALOGE("Error %d (%s) from lstat64(%s)", err, strerror(err), filepath.string());
+        ALOGE("Error %d (%s) from lstat64(%s)", err, strerror(err), filepath.c_str());
         return err;
     }
 
@@ -541,10 +541,10 @@
 
     // !!! TODO: use mmap when possible to avoid churning the buffer cache
     // !!! TODO: this will break with symlinks; need to use readlink(2)
-    int fd = open(filepath.string(), O_RDONLY);
+    int fd = open(filepath.c_str(), O_RDONLY);
     if (fd < 0) {
         err = errno;
-        ALOGE("Error %d (%s) from open(%s)", err, strerror(err), filepath.string());
+        ALOGE("Error %d (%s) from open(%s)", err, strerror(err), filepath.c_str());
         return err;
     }
 
@@ -592,7 +592,7 @@
     } else if (S_ISREG(s.st_mode)) {
         type = '0';     // tar magic: '0' == normal file
     } else {
-        ALOGW("Error: unknown file mode 0%o [%s]", s.st_mode, filepath.string());
+        ALOGW("Error: unknown file mode 0%o [%s]", s.st_mode, filepath.c_str());
         goto cleanup;
     }
     buf[156] = type;
@@ -620,16 +620,16 @@
         //    [ 345 : 155 ] filename path prefix
         // We only use the prefix area if fullname won't fit in the path
         if (fullname.length() > 100) {
-            strncpy(buf, relpath.string(), 100);
-            strncpy(buf + 345, prefix.string(), 155);
+            strncpy(buf, relpath.c_str(), 100);
+            strncpy(buf + 345, prefix.c_str(), 155);
         } else {
-            strncpy(buf, fullname.string(), 100);
+            strncpy(buf, fullname.c_str(), 100);
         }
     }
 
     // [ 329 : 8 ] and [ 337 : 8 ] devmajor/devminor, not used
 
-    ALOGI("   Name: %s", fullname.string());
+    ALOGI("   Name: %s", fullname.c_str());
 
     // If we're using a pax extended header, build & write that here; lengths are
     // already preflighted
@@ -647,7 +647,7 @@
 
         // fullname was generated above with the ustar paths
         paxLen += write_pax_header_entry(paxData + paxLen, PAXDATA_SIZE - paxLen,
-                "path", fullname.string());
+                "path", fullname.c_str());
 
         // Now we know how big the pax data is
 
@@ -656,9 +656,9 @@
 
         String8 leaf = fullname.getPathLeaf();
         memset(paxHeader, 0, 100);                  // rewrite the name area
-        snprintf(paxHeader, 100, "PaxHeader/%s", leaf.string());
+        snprintf(paxHeader, 100, "PaxHeader/%s", leaf.c_str());
         memset(paxHeader + 345, 0, 155);            // rewrite the prefix area
-        strncpy(paxHeader + 345, prefix.string(), 155);
+        strncpy(paxHeader + 345, prefix.c_str(), 155);
 
         paxHeader[156] = 'x';                       // mark it as a pax extended header
 
@@ -691,12 +691,12 @@
             ssize_t nRead = read(fd, buf, toRead);
             if (nRead < 0) {
                 err = errno;
-                ALOGE("Unable to read file [%s], err=%d (%s)", filepath.string(),
+                ALOGE("Unable to read file [%s], err=%d (%s)", filepath.c_str(),
                         err, strerror(err));
                 break;
             } else if (nRead == 0) {
                 ALOGE("EOF but expect %lld more bytes in [%s]", (long long) toWrite,
-                        filepath.string());
+                        filepath.c_str());
                 err = EIO;
                 break;
             }
@@ -762,7 +762,7 @@
     file_metadata_v1 metadata;
     amt = in->ReadEntityData(&metadata, sizeof(metadata));
     if (amt != sizeof(metadata)) {
-        ALOGW("Could not read metadata for %s -- %ld / %s", filename.string(),
+        ALOGW("Could not read metadata for %s -- %ld / %s", filename.c_str(),
                 (long)amt, strerror(errno));
         return EIO;
     }
@@ -779,9 +779,9 @@
 
     // Write the file and compute the crc
     crc = crc32(0L, Z_NULL, 0);
-    fd = open(filename.string(), O_CREAT|O_RDWR|O_TRUNC, mode);
+    fd = open(filename.c_str(), O_CREAT|O_RDWR|O_TRUNC, mode);
     if (fd == -1) {
-        ALOGW("Could not open file %s -- %s", filename.string(), strerror(errno));
+        ALOGW("Could not open file %s -- %s", filename.c_str(), strerror(errno));
         return errno;
     }
 
@@ -789,7 +789,7 @@
         err = write(fd, buf, amt);
         if (err != amt) {
             close(fd);
-            ALOGW("Error '%s' writing '%s'", strerror(errno), filename.string());
+            ALOGW("Error '%s' writing '%s'", strerror(errno), filename.c_str());
             return errno;
         }
         crc = crc32(crc, (Bytef*)buf, amt);
@@ -798,9 +798,9 @@
     close(fd);
 
     // Record for the snapshot
-    err = stat(filename.string(), &st);
+    err = stat(filename.c_str(), &st);
     if (err != 0) {
-        ALOGW("Error stating file that we just created %s", filename.string());
+        ALOGW("Error stating file that we just created %s", filename.c_str());
         return errno;
     }
 
@@ -1104,9 +1104,9 @@
             fprintf(stderr, "state %zu expected={%d/%d, %04o, 0x%08x, 0x%08x, %3zu} '%s'\n"
                             "          actual={%d/%d, %04o, 0x%08x, 0x%08x, %3d} '%s'\n", i,
                     states[i].modTime_sec, states[i].modTime_nsec, states[i].mode, states[i].size,
-                    states[i].crc32, name.length(), filenames[i].string(),
+                    states[i].crc32, name.length(), filenames[i].c_str(),
                     state.modTime_sec, state.modTime_nsec, state.mode, state.size, state.crc32,
-                    state.nameLen, name.string());
+                    state.nameLen, name.c_str());
             matched = false;
         }
     }
@@ -1152,9 +1152,9 @@
         return err;
     }
 
-    err = writer.WriteEntityData(text.string(), text.length()+1);
+    err = writer.WriteEntityData(text.c_str(), text.length()+1);
     if (err != 0) {
-        fprintf(stderr, "write failed for data '%s'\n", text.string());
+        fprintf(stderr, "write failed for data '%s'\n", text.c_str());
         return errno;
     }
 
@@ -1230,7 +1230,7 @@
         goto finished;
     }
     if (string != str) {
-        fprintf(stderr, "ReadEntityHeader expected key '%s' got '%s'\n", str, string.string());
+        fprintf(stderr, "ReadEntityHeader expected key '%s' got '%s'\n", str, string.c_str());
         err = EINVAL;
         goto finished;
     }
diff --git a/libs/androidfw/ConfigDescription.cpp b/libs/androidfw/ConfigDescription.cpp
index cf2fd6f..e08030c 100644
--- a/libs/androidfw/ConfigDescription.cpp
+++ b/libs/androidfw/ConfigDescription.cpp
@@ -905,7 +905,7 @@
 
 std::string ConfigDescription::to_string() const {
   const String8 str = toString();
-  return std::string(str.string(), str.size());
+  return std::string(str.c_str(), str.size());
 }
 
 bool ConfigDescription::Dominates(const ConfigDescription& o) const {
diff --git a/libs/androidfw/CursorWindow.cpp b/libs/androidfw/CursorWindow.cpp
index 2a6dc7b..5e645cc 100644
--- a/libs/androidfw/CursorWindow.cpp
+++ b/libs/androidfw/CursorWindow.cpp
@@ -84,7 +84,7 @@
     String8 ashmemName("CursorWindow: ");
     ashmemName.append(mName);
 
-    ashmemFd = ashmem_create_region(ashmemName.string(), mInflatedSize);
+    ashmemFd = ashmem_create_region(ashmemName.c_str(), mInflatedSize);
     if (ashmemFd < 0) {
         PLOG(ERROR) << "Failed ashmem_create_region";
         goto fail_silent;
diff --git a/libs/androidfw/ObbFile.cpp b/libs/androidfw/ObbFile.cpp
index 95332a3..c6a9632 100644
--- a/libs/androidfw/ObbFile.cpp
+++ b/libs/androidfw/ObbFile.cpp
@@ -217,7 +217,7 @@
     free(scanBuf);
 
 #ifdef DEBUG
-    ALOGI("Obb scan succeeded: packageName=%s, version=%d\n", mPackageName.string(), mVersion);
+    ALOGI("Obb scan succeeded: packageName=%s, version=%d\n", mPackageName.c_str(), mVersion);
 #endif
 
     return true;
@@ -288,7 +288,7 @@
         return false;
     }
 
-    if (write(fd, mPackageName.string(), packageNameLen) != (ssize_t)packageNameLen) {
+    if (write(fd, mPackageName.c_str(), packageNameLen) != (ssize_t)packageNameLen) {
         ALOGW("couldn't write package name: %s\n", strerror(errno));
         return false;
     }
diff --git a/libs/androidfw/ResourceTypes.cpp b/libs/androidfw/ResourceTypes.cpp
index 29d33da..c7a17af 100644
--- a/libs/androidfw/ResourceTypes.cpp
+++ b/libs/androidfw/ResourceTypes.cpp
@@ -1042,7 +1042,7 @@
 
     if ((mHeader->flags&ResStringPool_header::UTF8_FLAG) != 0) {
         if (kDebugStringPoolNoisy) {
-            ALOGI("indexOfString UTF-8: %s", String8(str, strLen).string());
+            ALOGI("indexOfString UTF-8: %s", String8(str, strLen).c_str());
         }
 
         // The string pool contains UTF 8 strings; we don't want to cause
@@ -1103,7 +1103,7 @@
                         ALOGI("Looking at %s, i=%d\n", s->data(), i);
                     }
                     if (str8Len == s->size()
-                            && memcmp(s->data(), str8.string(), str8Len) == 0) {
+                            && memcmp(s->data(), str8.c_str(), str8Len) == 0) {
                         if (kDebugStringPoolNoisy) {
                             ALOGI("MATCH!");
                         }
@@ -1115,7 +1115,7 @@
 
     } else {
         if (kDebugStringPoolNoisy) {
-            ALOGI("indexOfString UTF-16: %s", String8(str, strLen).string());
+            ALOGI("indexOfString UTF-16: %s", String8(str, strLen).c_str());
         }
 
         if (mHeader->flags&ResStringPool_header::SORTED_FLAG) {
@@ -1133,7 +1133,7 @@
                 int c = s.has_value() ? strzcmp16(s->data(), s->size(), str, strLen) : -1;
                 if (kDebugStringPoolNoisy) {
                     ALOGI("Looking at %s, cmp=%d, l/mid/h=%d/%d/%d\n",
-                          String8(s->data(), s->size()).string(), c, (int)l, (int)mid, (int)h);
+                          String8(s->data(), s->size()).c_str(), c, (int)l, (int)mid, (int)h);
                 }
                 if (c == 0) {
                     if (kDebugStringPoolNoisy) {
@@ -1157,7 +1157,7 @@
                     return base::unexpected(s.error());
                 }
                 if (kDebugStringPoolNoisy) {
-                    ALOGI("Looking at %s, i=%d\n", String8(s->data(), s->size()).string(), i);
+                    ALOGI("Looking at %s, i=%d\n", String8(s->data(), s->size()).c_str(), i);
                 }
                 if (s.has_value() && strLen == s->size() &&
                         strzcmp16(s->data(), s->size(), str, strLen) == 0) {
@@ -1525,8 +1525,8 @@
 {
     String16 nsStr(ns != NULL ? ns : "");
     String16 attrStr(attr);
-    return indexOfAttribute(ns ? nsStr.string() : NULL, ns ? nsStr.size() : 0,
-                            attrStr.string(), attrStr.size());
+    return indexOfAttribute(ns ? nsStr.c_str() : NULL, ns ? nsStr.size() : 0,
+                            attrStr.c_str(), attrStr.size());
 }
 
 ssize_t ResXMLParser::indexOfAttribute(const char16_t* ns, size_t nsLen,
@@ -1544,8 +1544,8 @@
             }
             attr8 = String8(attr, attrLen);
             if (kDebugStringPoolNoisy) {
-                ALOGI("indexOfAttribute UTF8 %s (%zu) / %s (%zu)", ns8.string(), nsLen,
-                        attr8.string(), attrLen);
+                ALOGI("indexOfAttribute UTF8 %s (%zu) / %s (%zu)", ns8.c_str(), nsLen,
+                        attr8.c_str(), attrLen);
             }
             for (size_t i=0; i<N; i++) {
                 size_t curNsLen = 0, curAttrLen = 0;
@@ -1555,7 +1555,7 @@
                     ALOGI("  curNs=%s (%zu), curAttr=%s (%zu)", curNs, curNsLen, curAttr, curAttrLen);
                 }
                 if (curAttr != NULL && curNsLen == nsLen && curAttrLen == attrLen
-                        && memcmp(attr8.string(), curAttr, attrLen) == 0) {
+                        && memcmp(attr8.c_str(), curAttr, attrLen) == 0) {
                     if (ns == NULL) {
                         if (curNs == NULL) {
                             if (kDebugStringPoolNoisy) {
@@ -1565,8 +1565,8 @@
                         }
                     } else if (curNs != NULL) {
                         //printf(" --> ns=%s, curNs=%s\n",
-                        //       String8(ns).string(), String8(curNs).string());
-                        if (memcmp(ns8.string(), curNs, nsLen) == 0) {
+                        //       String8(ns).c_str(), String8(curNs).c_str());
+                        if (memcmp(ns8.c_str(), curNs, nsLen) == 0) {
                             if (kDebugStringPoolNoisy) {
                                 ALOGI("  FOUND!");
                             }
@@ -1578,8 +1578,8 @@
         } else {
             if (kDebugStringPoolNoisy) {
                 ALOGI("indexOfAttribute UTF16 %s (%zu) / %s (%zu)",
-                        String8(ns, nsLen).string(), nsLen,
-                        String8(attr, attrLen).string(), attrLen);
+                        String8(ns, nsLen).c_str(), nsLen,
+                        String8(attr, attrLen).c_str(), attrLen);
             }
             for (size_t i=0; i<N; i++) {
                 size_t curNsLen = 0, curAttrLen = 0;
@@ -1587,8 +1587,8 @@
                 const char16_t* curAttr = getAttributeName(i, &curAttrLen);
                 if (kDebugStringPoolNoisy) {
                     ALOGI("  curNs=%s (%zu), curAttr=%s (%zu)",
-                            String8(curNs, curNsLen).string(), curNsLen,
-                            String8(curAttr, curAttrLen).string(), curAttrLen);
+                            String8(curNs, curNsLen).c_str(), curNsLen,
+                            String8(curAttr, curAttrLen).c_str(), curAttrLen);
                 }
                 if (curAttr != NULL && curNsLen == nsLen && curAttrLen == attrLen
                         && (memcmp(attr, curAttr, attrLen*sizeof(char16_t)) == 0)) {
@@ -1601,7 +1601,7 @@
                         }
                     } else if (curNs != NULL) {
                         //printf(" --> ns=%s, curNs=%s\n",
-                        //       String8(ns).string(), String8(curNs).string());
+                        //       String8(ns).c_str(), String8(curNs).c_str());
                         if (memcmp(ns, curNs, nsLen*sizeof(char16_t)) == 0) {
                             if (kDebugStringPoolNoisy) {
                                 ALOGI("  FOUND!");
@@ -4458,7 +4458,7 @@
         return false;
     }
 
-    outName->package = grp->name.string();
+    outName->package = grp->name.c_str();
     outName->packageLen = grp->name.size();
     if (allowUtf8) {
         outName->type8 = UnpackOptionalString(entry.typeStr.string8(), &outName->typeLen);
@@ -4558,7 +4558,7 @@
                 outValue->dataType,
                 outValue->dataType == Res_value::TYPE_STRING ?
                     String8(UnpackOptionalString(
-                        entry.package->header->values.stringAt(outValue->data), &len)).string() :
+                        entry.package->header->values.stringAt(outValue->data), &len)).c_str() :
                     "",
                 outValue->data);
     }
@@ -4927,7 +4927,7 @@
     AutoMutex _lock2(mFilteredConfigLock);
 
     if (kDebugTableGetEntry) {
-        ALOGI("Setting parameters: %s\n", params->toString().string());
+        ALOGI("Setting parameters: %s\n", params->toString().c_str());
     }
     mParams = *params;
     for (size_t p = 0; p < mPackageGroups.size(); p++) {
@@ -5038,7 +5038,7 @@
             if (name[1] == 'i' && name[2] == 'n'
                 && name[3] == 'd' && name[4] == 'e' && name[5] == 'x'
                 && name[6] == '_') {
-                int index = atoi(String8(name + 7, nameLen - 7).string());
+                int index = atoi(String8(name + 7, nameLen - 7).c_str());
                 if (Res_CHECKID(index)) {
                     ALOGW("Array resource index: %d is too large.",
                          index);
@@ -5104,9 +5104,9 @@
 
     if (kDebugTableNoisy) {
         printf("Looking for identifier: type=%s, name=%s, package=%s\n",
-                String8(type, typeLen).string(),
-                String8(name, nameLen).string(),
-                String8(package, packageLen).string());
+                String8(type, typeLen).c_str(),
+                String8(name, nameLen).c_str(),
+                String8(package, packageLen).c_str());
     }
 
     const String16 attr("attr");
@@ -5117,9 +5117,9 @@
         const PackageGroup* group = mPackageGroups[ig];
 
         if (strzcmp16(package, packageLen,
-                      group->name.string(), group->name.size())) {
+                      group->name.c_str(), group->name.size())) {
             if (kDebugTableNoisy) {
-                printf("Skipping package group: %s\n", String8(group->name).string());
+                printf("Skipping package group: %s\n", String8(group->name).c_str());
             }
             continue;
         }
@@ -5144,8 +5144,8 @@
                     }
                     return identifier;
                 }
-            } while (strzcmp16(attr.string(), attr.size(), targetType, targetTypeLen) == 0
-                    && (targetType = attrPrivate.string())
+            } while (strzcmp16(attr.c_str(), attr.size(), targetType, targetTypeLen) == 0
+                    && (targetType = attrPrivate.c_str())
                     && (targetTypeLen = attrPrivate.size())
             );
         }
@@ -5564,7 +5564,7 @@
         }
     }
 
-    //printf("Value for: %s\n", String8(s, len).string());
+    //printf("Value for: %s\n", String8(s, len).c_str());
 
     uint32_t l10nReq = ResTable_map::L10N_NOT_REQUIRED;
     uint32_t attrMin = 0x80000000, attrMax = 0x7fffffff;
@@ -5619,7 +5619,7 @@
         // be to any other type; we just need to count on the client making
         // sure the referenced type is correct.
 
-        //printf("Looking up ref: %s\n", String8(s, len).string());
+        //printf("Looking up ref: %s\n", String8(s, len).c_str());
 
         // It's a reference!
         if (len == 5 && s[1]=='n' && s[2]=='u' && s[3]=='l' && s[4]=='l') {
@@ -5659,8 +5659,8 @@
             }
 
             uint32_t specFlags = 0;
-            uint32_t rid = identifierForName(name.string(), name.size(), type.string(),
-                    type.size(), package.string(), package.size(), &specFlags);
+            uint32_t rid = identifierForName(name.c_str(), name.size(), type.c_str(),
+                    type.size(), package.c_str(), package.size(), &specFlags);
             if (rid != 0) {
                 if (enforcePrivate) {
                     if (accessor == NULL || accessor->getAssetsPackage() != package) {
@@ -5679,8 +5679,8 @@
                         Res_GETTYPE(rid), Res_GETENTRY(rid));
                     if (kDebugTableNoisy) {
                         ALOGI("Incl %s:%s/%s: 0x%08x\n",
-                                String8(package).string(), String8(type).string(),
-                                String8(name).string(), rid);
+                                String8(package).c_str(), String8(type).c_str(),
+                                String8(name).c_str(), rid);
                     }
                 }
 
@@ -5698,8 +5698,8 @@
                 if (rid != 0) {
                     if (kDebugTableNoisy) {
                         ALOGI("Pckg %s:%s/%s: 0x%08x\n",
-                                String8(package).string(), String8(type).string(),
-                                String8(name).string(), rid);
+                                String8(package).c_str(), String8(type).c_str(),
+                                String8(name).c_str(), rid);
                     }
                     uint32_t packageId = Res_GETPACKAGE(rid) + 1;
                     if (packageId == 0x00) {
@@ -5788,7 +5788,7 @@
                 }
             } else {
                 outValue->data = color;
-                //printf("Color input=%s, output=0x%x\n", String8(s, len).string(), color);
+                //printf("Color input=%s, output=0x%x\n", String8(s, len).c_str(), color);
                 return true;
             }
         } else {
@@ -5800,8 +5800,8 @@
                 #if 0
                 fprintf(stderr, "%s: Color ID %s value %s is not valid\n",
                         "Resource File", //(const char*)in->getPrintableSource(),
-                        String8(*curTag).string(),
-                        String8(s, len).string());
+                        String8(*curTag).c_str(),
+                        String8(s, len).c_str());
                 #endif
                 return false;
             }
@@ -5815,7 +5815,7 @@
         // be to any other type; we just need to count on the client making
         // sure the referenced type is correct.
 
-        //printf("Looking up attr: %s\n", String8(s, len).string());
+        //printf("Looking up attr: %s\n", String8(s, len).c_str());
 
         static const String16 attr16("attr");
         String16 package, type, name;
@@ -5828,13 +5828,13 @@
         }
 
         //printf("Pkg: %s, Type: %s, Name: %s\n",
-        //       String8(package).string(), String8(type).string(),
-        //       String8(name).string());
+        //       String8(package).c_str(), String8(type).c_str(),
+        //       String8(name).c_str());
         uint32_t specFlags = 0;
         uint32_t rid =
-            identifierForName(name.string(), name.size(),
-                              type.string(), type.size(),
-                              package.string(), package.size(), &specFlags);
+            identifierForName(name.c_str(), name.size(),
+                              type.c_str(), type.size(),
+                              package.c_str(), package.size(), &specFlags);
         if (rid != 0) {
             if (enforcePrivate) {
                 if ((specFlags&ResTable_typeSpec::SPEC_PUBLIC) == 0) {
@@ -5992,8 +5992,8 @@
                     if (getResourceName(bag->map.name.ident, false, &rname)) {
                         #if 0
                         printf("Matching %s against %s (0x%08x)\n",
-                               String8(s, len).string(),
-                               String8(rname.name, rname.nameLen).string(),
+                               String8(s, len).c_str(),
+                               String8(rname.name, rname.nameLen).c_str(),
                                bag->map.name.ident);
                         #endif
                         if (strzcmp16(s, len, rname.name, rname.nameLen) == 0) {
@@ -6036,7 +6036,7 @@
                 while (pos < end && *pos != '|') {
                     pos++;
                 }
-                //printf("Looking for: %s\n", String8(start, pos-start).string());
+                //printf("Looking for: %s\n", String8(start, pos-start).c_str());
                 const bag_entry* bagi = bag;
                 ssize_t i;
                 for (i=0; i<cnt; i++, bagi++) {
@@ -6045,8 +6045,8 @@
                         if (getResourceName(bagi->map.name.ident, false, &rname)) {
                             #if 0
                             printf("Matching %s against %s (0x%08x)\n",
-                                   String8(start,pos-start).string(),
-                                   String8(rname.name, rname.nameLen).string(),
+                                   String8(start,pos-start).c_str(),
+                                   String8(rname.name, rname.nameLen).c_str(),
                                    bagi->map.name.ident);
                             #endif
                             if (strzcmp16(start, pos-start, rname.name, rname.nameLen) == 0) {
@@ -6373,7 +6373,7 @@
 }
 
 static bool compareString8AndCString(const String8& str, const char* cStr) {
-    return strcmp(str.string(), cStr) < 0;
+    return strcmp(str.c_str(), cStr) < 0;
 }
 
 void ResTable::getLocales(Vector<String8>* locales, bool includeSystemLocales,
@@ -6387,7 +6387,7 @@
         const auto endIter = locales->end();
 
         auto iter = std::lower_bound(beginIter, endIter, locale, compareString8AndCString);
-        if (iter == endIter || strcmp(iter->string(), locale) != 0) {
+        if (iter == endIter || strcmp(iter->c_str(), locale) != 0) {
             locales->insertAt(String8(locale), std::distance(beginIter, iter));
         }
     });
@@ -6984,7 +6984,7 @@
                         ResTable_config thisConfig;
                         thisConfig.copyFromDtoH(type->config);
                         ALOGI("Adding config to type %d: %s\n", type->id,
-                                thisConfig.toString().string());
+                                thisConfig.toString().c_str());
                     }
                 }
             } else {
@@ -7061,7 +7061,7 @@
         char16_t tmpName[sizeof(entry->packageName) / sizeof(char16_t)];
         strcpy16_dtoh(tmpName, entry->packageName, sizeof(entry->packageName) / sizeof(char16_t));
         if (kDebugLibNoisy) {
-            ALOGV("Found lib entry %s with id %d\n", String8(tmpName).string(),
+            ALOGV("Found lib entry %s with id %d\n", String8(tmpName).c_str(),
                     dtohl(entry->packageId));
         }
         if (packageId >= 256) {
@@ -7340,7 +7340,7 @@
                     current_res.nameLen,
                     current_res.type,
                     current_res.typeLen,
-                    targetPackageName.string(),
+                    targetPackageName.c_str(),
                     targetPackageName.size(),
                     &typeSpecFlags);
 
@@ -7447,7 +7447,7 @@
 }
 
 
-#define CHAR16_TO_CSTR(c16, len) (String8(String16(c16,len)).string())
+#define CHAR16_TO_CSTR(c16, len) (String8(String16(c16,len)).c_str())
 
 #define CHAR16_ARRAY_EQ(constant, var, len) \
         (((len) == (sizeof(constant)/sizeof((constant)[0]))) && (0 == memcmp((var), (constant), (len))))
@@ -7542,13 +7542,13 @@
         const char* str8 = UnpackOptionalString(pkg->header->values.string8At(
                 value.data), &len);
         if (str8 != NULL) {
-            printf("(string8) \"%s\"\n", normalizeForOutput(str8).string());
+            printf("(string8) \"%s\"\n", normalizeForOutput(str8).c_str());
         } else {
             const char16_t* str16 = UnpackOptionalString(pkg->header->values.stringAt(
                     value.data), &len);
             if (str16 != NULL) {
                 printf("(string16) \"%s\"\n",
-                    normalizeForOutput(String8(str16, len).string()).string());
+                    normalizeForOutput(String8(str16, len).c_str()).c_str());
             } else {
                 printf("(string) null\n");
             }
@@ -7589,7 +7589,7 @@
         const PackageGroup* pg = mPackageGroups[pgIndex];
         printf("Package Group %d id=0x%02x packageCount=%d name=%s\n",
                 (int)pgIndex, pg->id, (int)pg->packages.size(),
-                String8(pg->name).string());
+                String8(pg->name).c_str());
 
         const KeyedVector<String16, uint8_t>& refEntries = pg->dynamicRefTable.entries();
         const size_t refEntryCount = refEntries.size();
@@ -7598,7 +7598,7 @@
             for (size_t refIndex = 0; refIndex < refEntryCount; refIndex++) {
                 printf("    0x%02x -> %s\n",
                         refEntries.valueAt(refIndex),
-                        String8(refEntries.keyAt(refIndex)).string());
+                        String8(refEntries.keyAt(refIndex)).c_str());
             }
             printf("\n");
         }
@@ -7624,7 +7624,7 @@
                 strcpy16_dtoh(tmpName, pkg->package->name,
                               sizeof(pkg->package->name)/sizeof(pkg->package->name[0]));
                 printf("  Package %d id=0x%02x name=%s\n", (int)pkgIndex,
-                        pkg->package->id, String8(tmpName).string());
+                        pkg->package->id, String8(tmpName).c_str());
             }
 
             for (size_t typeIndex = 0; typeIndex < pg->types.size(); typeIndex++) {
@@ -7666,7 +7666,7 @@
                             printf("      spec resource 0x%08x %s:%s/%s: flags=0x%08x\n",
                                 resID,
                                 CHAR16_TO_CSTR(resName.package, resName.packageLen),
-                                type8.string(), name8.string(),
+                                type8.c_str(), name8.c_str(),
                                 dtohl(typeConfigs->typeSpecFlags[entryIndex]));
                         } else {
                             printf("      INVALID TYPE CONFIG FOR RESOURCE 0x%08x\n", resID);
@@ -7687,7 +7687,7 @@
 
                     String8 configStr = thisConfig.toString();
                     printf("      config %s", configStr.size() > 0
-                            ? configStr.string() : "(default)");
+                            ? configStr.c_str() : "(default)");
                     if (type->flags != 0u) {
                         printf(" flags=0x%02x", type->flags);
                         if (type->flags & ResTable_type::FLAG_SPARSE) {
@@ -7761,7 +7761,7 @@
                             }
                             printf("        resource 0x%08x %s:%s/%s: ", resID,
                                     CHAR16_TO_CSTR(resName.package, resName.packageLen),
-                                    type8.string(), name8.string());
+                                    type8.c_str(), name8.c_str());
                         } else {
                             printf("        INVALID RESOURCE 0x%08x: ", resID);
                         }
diff --git a/libs/androidfw/include/androidfw/Asset.h b/libs/androidfw/include/androidfw/Asset.h
index 19febcd..f3776b5 100644
--- a/libs/androidfw/include/androidfw/Asset.h
+++ b/libs/androidfw/include/androidfw/Asset.h
@@ -135,7 +135,7 @@
      * This is NOT intended to be used for anything except debug output.
      * DO NOT try to parse this or use it to open a file.
      */
-    const char* getAssetSource(void) const { return mAssetSource.string(); }
+    const char* getAssetSource(void) const { return mAssetSource.c_str(); }
 
     /*
      * Create the asset from a file descriptor.
diff --git a/libs/androidfw/include/androidfw/ConfigDescription.h b/libs/androidfw/include/androidfw/ConfigDescription.h
index 7fbd7c0..83a80ce 100644
--- a/libs/androidfw/include/androidfw/ConfigDescription.h
+++ b/libs/androidfw/include/androidfw/ConfigDescription.h
@@ -213,7 +213,7 @@
 
 inline ::std::ostream& operator<<(::std::ostream& out,
                                   const ConfigDescription& o) {
-  return out << o.toString().string();
+  return out << o.toString().c_str();
 }
 
 }  // namespace android
diff --git a/libs/androidfw/tests/BackupData_test.cpp b/libs/androidfw/tests/BackupData_test.cpp
index e25b616..7d3a341 100644
--- a/libs/androidfw/tests/BackupData_test.cpp
+++ b/libs/androidfw/tests/BackupData_test.cpp
@@ -56,10 +56,10 @@
         mFilename.append(m_external_storage);
         mFilename.append(TEST_FILENAME);
 
-        ::unlink(mFilename.string());
-        int fd = ::open(mFilename.string(), O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);
+        ::unlink(mFilename.c_str());
+        int fd = ::open(mFilename.c_str(), O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);
         if (fd < 0) {
-            FAIL() << "Couldn't create " << mFilename.string() << " for writing";
+            FAIL() << "Couldn't create " << mFilename.c_str() << " for writing";
         }
         mKey1 = String8(KEY1);
         mKey2 = String8(KEY2);
@@ -72,7 +72,7 @@
 };
 
 TEST_F(BackupDataTest, WriteAndReadSingle) {
-  int fd = ::open(mFilename.string(), O_WRONLY);
+  int fd = ::open(mFilename.c_str(), O_WRONLY);
   BackupDataWriter* writer = new BackupDataWriter(fd);
 
   EXPECT_EQ(NO_ERROR, writer->WriteEntityHeader(mKey1, sizeof(DATA1)))
@@ -81,7 +81,7 @@
           << "WriteEntityData returned an error";
 
   ::close(fd);
-  fd = ::open(mFilename.string(), O_RDONLY);
+  fd = ::open(mFilename.c_str(), O_RDONLY);
   BackupDataReader* reader = new BackupDataReader(fd);
   EXPECT_EQ(NO_ERROR, reader->Status())
           << "Reader ctor failed";
@@ -114,7 +114,7 @@
 }
 
 TEST_F(BackupDataTest, WriteAndReadMultiple) {
-  int fd = ::open(mFilename.string(), O_WRONLY);
+  int fd = ::open(mFilename.c_str(), O_WRONLY);
   BackupDataWriter* writer = new BackupDataWriter(fd);
   writer->WriteEntityHeader(mKey1, sizeof(DATA1));
   writer->WriteEntityData(DATA1, sizeof(DATA1));
@@ -122,7 +122,7 @@
   writer->WriteEntityData(DATA2, sizeof(DATA2));
 
   ::close(fd);
-  fd = ::open(mFilename.string(), O_RDONLY);
+  fd = ::open(mFilename.c_str(), O_RDONLY);
   BackupDataReader* reader = new BackupDataReader(fd);
 
   bool done;
@@ -162,7 +162,7 @@
 }
 
 TEST_F(BackupDataTest, SkipEntity) {
-  int fd = ::open(mFilename.string(), O_WRONLY);
+  int fd = ::open(mFilename.c_str(), O_WRONLY);
   BackupDataWriter* writer = new BackupDataWriter(fd);
   writer->WriteEntityHeader(mKey1, sizeof(DATA1));
   writer->WriteEntityData(DATA1, sizeof(DATA1));
@@ -172,7 +172,7 @@
   writer->WriteEntityData(DATA3, sizeof(DATA3));
 
   ::close(fd);
-  fd = ::open(mFilename.string(), O_RDONLY);
+  fd = ::open(mFilename.c_str(), O_RDONLY);
   BackupDataReader* reader = new BackupDataReader(fd);
 
   bool done;
@@ -217,14 +217,14 @@
 }
 
 TEST_F(BackupDataTest, DeleteEntity) {
-  int fd = ::open(mFilename.string(), O_WRONLY);
+  int fd = ::open(mFilename.c_str(), O_WRONLY);
   BackupDataWriter* writer = new BackupDataWriter(fd);
   writer->WriteEntityHeader(mKey1, sizeof(DATA1));
   writer->WriteEntityData(DATA1, sizeof(DATA1));
   writer->WriteEntityHeader(mKey2, -1);
 
   ::close(fd);
-  fd = ::open(mFilename.string(), O_RDONLY);
+  fd = ::open(mFilename.c_str(), O_RDONLY);
   BackupDataReader* reader = new BackupDataReader(fd);
 
   bool done;
@@ -256,7 +256,7 @@
 }
 
 TEST_F(BackupDataTest, EneityAfterDelete) {
-  int fd = ::open(mFilename.string(), O_WRONLY);
+  int fd = ::open(mFilename.c_str(), O_WRONLY);
   BackupDataWriter* writer = new BackupDataWriter(fd);
   writer->WriteEntityHeader(mKey1, sizeof(DATA1));
   writer->WriteEntityData(DATA1, sizeof(DATA1));
@@ -265,7 +265,7 @@
   writer->WriteEntityData(DATA3, sizeof(DATA3));
 
   ::close(fd);
-  fd = ::open(mFilename.string(), O_RDONLY);
+  fd = ::open(mFilename.c_str(), O_RDONLY);
   BackupDataReader* reader = new BackupDataReader(fd);
 
   bool done;
@@ -317,7 +317,7 @@
 }
 
 TEST_F(BackupDataTest, OnlyDeleteEntities) {
-  int fd = ::open(mFilename.string(), O_WRONLY);
+  int fd = ::open(mFilename.c_str(), O_WRONLY);
   BackupDataWriter* writer = new BackupDataWriter(fd);
   writer->WriteEntityHeader(mKey1, -1);
   writer->WriteEntityHeader(mKey2, -1);
@@ -325,7 +325,7 @@
   writer->WriteEntityHeader(mKey4, -1);
 
   ::close(fd);
-  fd = ::open(mFilename.string(), O_RDONLY);
+  fd = ::open(mFilename.c_str(), O_RDONLY);
   BackupDataReader* reader = new BackupDataReader(fd);
 
   bool done;
@@ -385,13 +385,13 @@
 }
 
 TEST_F(BackupDataTest, ReadDeletedEntityData) {
-  int fd = ::open(mFilename.string(), O_WRONLY);
+  int fd = ::open(mFilename.c_str(), O_WRONLY);
   BackupDataWriter* writer = new BackupDataWriter(fd);
   writer->WriteEntityHeader(mKey1, -1);
   writer->WriteEntityHeader(mKey2, -1);
 
   ::close(fd);
-  fd = ::open(mFilename.string(), O_RDONLY);
+  fd = ::open(mFilename.c_str(), O_RDONLY);
   BackupDataReader* reader = new BackupDataReader(fd);
 
   bool done;
diff --git a/libs/androidfw/tests/CommonHelpers.cpp b/libs/androidfw/tests/CommonHelpers.cpp
index 3396729..10138de 100644
--- a/libs/androidfw/tests/CommonHelpers.cpp
+++ b/libs/androidfw/tests/CommonHelpers.cpp
@@ -60,7 +60,7 @@
 std::string GetStringFromPool(const ResStringPool* pool, uint32_t idx) {
   auto str = pool->string8ObjectAt(idx);
   CHECK(str.has_value()) << "failed to find string entry";
-  return std::string(str->string(), str->length());
+  return std::string(str->c_str(), str->length());
 }
 
 }  // namespace android
diff --git a/libs/androidfw/tests/ConfigDescription_test.cpp b/libs/androidfw/tests/ConfigDescription_test.cpp
index f5c01e5..ec478b0 100644
--- a/libs/androidfw/tests/ConfigDescription_test.cpp
+++ b/libs/androidfw/tests/ConfigDescription_test.cpp
@@ -50,10 +50,10 @@
 TEST(ConfigDescriptionTest, ParseBasicQualifiers) {
   ConfigDescription config;
   EXPECT_TRUE(TestParse("", &config));
-  EXPECT_EQ(std::string(""), config.toString().string());
+  EXPECT_EQ(std::string(""), config.toString().c_str());
 
   EXPECT_TRUE(TestParse("fr-land", &config));
-  EXPECT_EQ(std::string("fr-land"), config.toString().string());
+  EXPECT_EQ(std::string("fr-land"), config.toString().c_str());
 
   EXPECT_TRUE(
       TestParse("mcc310-pl-sw720dp-normal-long-port-night-"
@@ -61,22 +61,22 @@
                 &config));
   EXPECT_EQ(std::string("mcc310-pl-sw720dp-normal-long-port-night-"
                         "xhdpi-keyssoft-qwerty-navexposed-nonav-v13"),
-            config.toString().string());
+            config.toString().c_str());
 }
 
 TEST(ConfigDescriptionTest, ParseLocales) {
   ConfigDescription config;
   EXPECT_TRUE(TestParse("en-rUS", &config));
-  EXPECT_EQ(std::string("en-rUS"), config.toString().string());
+  EXPECT_EQ(std::string("en-rUS"), config.toString().c_str());
 }
 
 TEST(ConfigDescriptionTest, ParseQualifierAddedInApi13) {
   ConfigDescription config;
   EXPECT_TRUE(TestParse("sw600dp", &config));
-  EXPECT_EQ(std::string("sw600dp-v13"), config.toString().string());
+  EXPECT_EQ(std::string("sw600dp-v13"), config.toString().c_str());
 
   EXPECT_TRUE(TestParse("sw600dp-v8", &config));
-  EXPECT_EQ(std::string("sw600dp-v13"), config.toString().string());
+  EXPECT_EQ(std::string("sw600dp-v13"), config.toString().c_str());
 }
 
 TEST(ConfigDescriptionTest, ParseCarAttribute) {
@@ -91,13 +91,13 @@
   EXPECT_EQ(android::ResTable_config::SCREENROUND_YES,
             config.screenLayout2 & android::ResTable_config::MASK_SCREENROUND);
   EXPECT_EQ(SDK_MARSHMALLOW, config.sdkVersion);
-  EXPECT_EQ(std::string("round-v23"), config.toString().string());
+  EXPECT_EQ(std::string("round-v23"), config.toString().c_str());
 
   EXPECT_TRUE(TestParse("notround", &config));
   EXPECT_EQ(android::ResTable_config::SCREENROUND_NO,
             config.screenLayout2 & android::ResTable_config::MASK_SCREENROUND);
   EXPECT_EQ(SDK_MARSHMALLOW, config.sdkVersion);
-  EXPECT_EQ(std::string("notround-v23"), config.toString().string());
+  EXPECT_EQ(std::string("notround-v23"), config.toString().c_str());
 }
 
 TEST(ConfigDescriptionTest, TestWideColorGamutQualifier) {
@@ -106,13 +106,13 @@
   EXPECT_EQ(android::ResTable_config::WIDE_COLOR_GAMUT_YES,
             config.colorMode & android::ResTable_config::MASK_WIDE_COLOR_GAMUT);
   EXPECT_EQ(SDK_O, config.sdkVersion);
-  EXPECT_EQ(std::string("widecg-v26"), config.toString().string());
+  EXPECT_EQ(std::string("widecg-v26"), config.toString().c_str());
 
   EXPECT_TRUE(TestParse("nowidecg", &config));
   EXPECT_EQ(android::ResTable_config::WIDE_COLOR_GAMUT_NO,
             config.colorMode & android::ResTable_config::MASK_WIDE_COLOR_GAMUT);
   EXPECT_EQ(SDK_O, config.sdkVersion);
-  EXPECT_EQ(std::string("nowidecg-v26"), config.toString().string());
+  EXPECT_EQ(std::string("nowidecg-v26"), config.toString().c_str());
 }
 
 TEST(ConfigDescriptionTest, TestHdrQualifier) {
@@ -121,13 +121,13 @@
   EXPECT_EQ(android::ResTable_config::HDR_YES,
             config.colorMode & android::ResTable_config::MASK_HDR);
   EXPECT_EQ(SDK_O, config.sdkVersion);
-  EXPECT_EQ(std::string("highdr-v26"), config.toString().string());
+  EXPECT_EQ(std::string("highdr-v26"), config.toString().c_str());
 
   EXPECT_TRUE(TestParse("lowdr", &config));
   EXPECT_EQ(android::ResTable_config::HDR_NO,
             config.colorMode & android::ResTable_config::MASK_HDR);
   EXPECT_EQ(SDK_O, config.sdkVersion);
-  EXPECT_EQ(std::string("lowdr-v26"), config.toString().string());
+  EXPECT_EQ(std::string("lowdr-v26"), config.toString().c_str());
 }
 
 TEST(ConfigDescriptionTest, ParseVrAttribute) {
@@ -135,7 +135,7 @@
   EXPECT_TRUE(TestParse("vrheadset", &config));
   EXPECT_EQ(android::ResTable_config::UI_MODE_TYPE_VR_HEADSET, config.uiMode);
   EXPECT_EQ(SDK_O, config.sdkVersion);
-  EXPECT_EQ(std::string("vrheadset-v26"), config.toString().string());
+  EXPECT_EQ(std::string("vrheadset-v26"), config.toString().c_str());
 }
 
 static inline ConfigDescription ParseConfigOrDie(android::StringPiece str) {
diff --git a/libs/androidfw/tests/ObbFile_test.cpp b/libs/androidfw/tests/ObbFile_test.cpp
index 1151121..ba818c4 100644
--- a/libs/androidfw/tests/ObbFile_test.cpp
+++ b/libs/androidfw/tests/ObbFile_test.cpp
@@ -43,9 +43,9 @@
         mFileName.append(externalStorage);
         mFileName.append(TEST_FILENAME);
 
-        int fd = ::open(mFileName.string(), O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);
+        int fd = ::open(mFileName.c_str(), O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);
         if (fd < 0) {
-            FAIL() << "Couldn't create " << mFileName.string() << " for tests";
+            FAIL() << "Couldn't create " << mFileName.c_str() << " for tests";
         }
     }
 
@@ -69,17 +69,17 @@
     EXPECT_TRUE(mObbFile->setSalt(salt, SALT_SIZE))
             << "Salt should be successfully set";
 
-    EXPECT_TRUE(mObbFile->writeTo(mFileName.string()))
+    EXPECT_TRUE(mObbFile->writeTo(mFileName.c_str()))
             << "couldn't write to fake .obb file";
 
     mObbFile = new ObbFile();
 
-    EXPECT_TRUE(mObbFile->readFrom(mFileName.string()))
+    EXPECT_TRUE(mObbFile->readFrom(mFileName.c_str()))
             << "couldn't read from fake .obb file";
 
     EXPECT_EQ(versionNum, mObbFile->getVersion())
             << "version didn't come out the same as it went in";
-    const char* currentPackageName = mObbFile->getPackageName().string();
+    const char* currentPackageName = mObbFile->getPackageName().c_str();
     EXPECT_STREQ(packageName, currentPackageName)
             << "package name didn't come out the same as it went in";
 
diff --git a/libs/androidfw/tests/ResTable_test.cpp b/libs/androidfw/tests/ResTable_test.cpp
index fbf7098..945981b 100644
--- a/libs/androidfw/tests/ResTable_test.cpp
+++ b/libs/androidfw/tests/ResTable_test.cpp
@@ -64,8 +64,8 @@
   String16 defPackage("com.android.basic");
   String16 testName("@string/test1");
   uint32_t resID =
-      table.identifierForName(testName.string(), testName.size(), 0, 0,
-                              defPackage.string(), defPackage.size());
+      table.identifierForName(testName.c_str(), testName.size(), 0, 0,
+                              defPackage.c_str(), defPackage.size());
   ASSERT_NE(uint32_t(0x00000000), resID);
   ASSERT_EQ(basic::R::string::test1, resID);
 }
diff --git a/libs/androidfw/tests/Split_test.cpp b/libs/androidfw/tests/Split_test.cpp
index 2c242db..3d88577 100644
--- a/libs/androidfw/tests/Split_test.cpp
+++ b/libs/androidfw/tests/Split_test.cpp
@@ -261,8 +261,8 @@
   const String16 package("com.android.basic");
   ASSERT_EQ(
       R::string::test3,
-      table.identifierForName(name.string(), name.size(), type.string(),
-                              type.size(), package.string(), package.size()));
+      table.identifierForName(name.c_str(), name.size(), type.c_str(),
+                              type.size(), package.c_str(), package.size()));
 }
 
 }  // namespace
diff --git a/libs/androidfw/tests/TestHelpers.cpp b/libs/androidfw/tests/TestHelpers.cpp
index 10c0a4f..c6f657c 100644
--- a/libs/androidfw/tests/TestHelpers.cpp
+++ b/libs/androidfw/tests/TestHelpers.cpp
@@ -79,9 +79,9 @@
   }
 
   if (String8(expected_str) != *actual_str) {
-    return AssertionFailure() << actual_str->string();
+    return AssertionFailure() << actual_str->c_str();
   }
-  return AssertionSuccess() << actual_str->string();
+  return AssertionSuccess() << actual_str->c_str();
 }
 
 }  // namespace android
diff --git a/libs/hwui/RenderNode.h b/libs/hwui/RenderNode.h
index d1e04ad..d27c428c 100644
--- a/libs/hwui/RenderNode.h
+++ b/libs/hwui/RenderNode.h
@@ -114,7 +114,7 @@
         return mDisplayList.containsProjectionReceiver();
     }
 
-    const char* getName() const { return mName.string(); }
+    const char* getName() const { return mName.c_str(); }
 
     void setName(const char* name) {
         if (name) {
diff --git a/libs/hwui/pipeline/skia/SkiaPipeline.cpp b/libs/hwui/pipeline/skia/SkiaPipeline.cpp
index b020e96..cb23bcc 100644
--- a/libs/hwui/pipeline/skia/SkiaPipeline.cpp
+++ b/libs/hwui/pipeline/skia/SkiaPipeline.cpp
@@ -200,7 +200,7 @@
             String8 cachesOutput;
             mRenderThread.cacheManager().dumpMemoryUsage(cachesOutput,
                                                          &mRenderThread.renderState());
-            ALOGE("%s", cachesOutput.string());
+            ALOGE("%s", cachesOutput.c_str());
             if (errorHandler) {
                 std::ostringstream err;
                 err << "Unable to create layer for " << node->getName();
diff --git a/libs/hwui/renderthread/RenderThread.cpp b/libs/hwui/renderthread/RenderThread.cpp
index eb28c08..0dea941 100644
--- a/libs/hwui/renderthread/RenderThread.cpp
+++ b/libs/hwui/renderthread/RenderThread.cpp
@@ -357,7 +357,7 @@
 
     String8 cachesOutput;
     mCacheManager->dumpMemoryUsage(cachesOutput, mRenderState);
-    dprintf(fd, "\nPipeline=%s\n%s\n", pipelineToString(), cachesOutput.string());
+    dprintf(fd, "\nPipeline=%s\n%s\n", pipelineToString(), cachesOutput.c_str());
 }
 
 void RenderThread::getMemoryUsage(size_t* cpuUsage, size_t* gpuUsage) {
diff --git a/libs/hwui/utils/LinearAllocator.cpp b/libs/hwui/utils/LinearAllocator.cpp
index 8baa4b77..eab888e 100644
--- a/libs/hwui/utils/LinearAllocator.cpp
+++ b/libs/hwui/utils/LinearAllocator.cpp
@@ -31,15 +31,11 @@
 #include <utils/Log.h>
 #include <utils/Macros.h>
 
-// The ideal size of a page allocation (these need to be multiples of 8)
-#define INITIAL_PAGE_SIZE ((size_t)512)  // 512b
-#define MAX_PAGE_SIZE ((size_t)131072)   // 128kb
-
 // The maximum amount of wasted space we can have per page
 // Allocations exceeding this will have their own dedicated page
 // If this is too low, we will malloc too much
 // Too high, and we may waste too much space
-// Must be smaller than INITIAL_PAGE_SIZE
+// Must be smaller than kInitialPageSize
 #define MAX_WASTE_RATIO (0.5f)
 
 #if LOG_NDEBUG
@@ -75,6 +71,10 @@
 namespace android {
 namespace uirenderer {
 
+// The ideal size of a page allocation (these need to be multiples of 8)
+static constexpr size_t kInitialPageSize = 512;  // 512b
+static constexpr size_t kMaxPageSize = 131072;   // 128kb
+
 class LinearAllocator::Page {
 public:
     Page* next() { return mNextPage; }
@@ -94,8 +94,8 @@
 };
 
 LinearAllocator::LinearAllocator()
-        : mPageSize(INITIAL_PAGE_SIZE)
-        , mMaxAllocSize(INITIAL_PAGE_SIZE * MAX_WASTE_RATIO)
+        : mPageSize(kInitialPageSize)
+        , mMaxAllocSize(kInitialPageSize * MAX_WASTE_RATIO)
         , mNext(0)
         , mCurrentPage(0)
         , mPages(0)
@@ -135,8 +135,8 @@
 void LinearAllocator::ensureNext(size_t size) {
     if (fitsInCurrentPage(size)) return;
 
-    if (mCurrentPage && mPageSize < MAX_PAGE_SIZE) {
-        mPageSize = min(MAX_PAGE_SIZE, mPageSize * 2);
+    if (mCurrentPage && mPageSize < kMaxPageSize) {
+        mPageSize = min(kMaxPageSize, mPageSize * 2);
         mMaxAllocSize = mPageSize * MAX_WASTE_RATIO;
         mPageSize = ALIGN(mPageSize);
     }
diff --git a/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouter2ManagerTest.java b/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouter2ManagerTest.java
index 4193ffa..3d448a8 100644
--- a/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouter2ManagerTest.java
+++ b/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouter2ManagerTest.java
@@ -918,7 +918,7 @@
         CountDownLatch addedLatch = new CountDownLatch(1);
         CountDownLatch preferenceLatch = new CountDownLatch(1);
 
-        // A dummy callback is required to send route feature info.
+        // A placeholder callback is required to send route feature info.
         RouteCallback routeCallback = new RouteCallback() {};
         MediaRouter2Manager.Callback managerCallback =
                 new MediaRouter2Manager.Callback() {
diff --git a/packages/CtsShim/build/Android.bp b/packages/CtsShim/build/Android.bp
index d778feb..d6b7ecf 100644
--- a/packages/CtsShim/build/Android.bp
+++ b/packages/CtsShim/build/Android.bp
@@ -208,3 +208,22 @@
     ],
     min_sdk_version: "24",
 }
+
+//##########################################################
+// Variant: Add apk to an apex
+android_app {
+    name: "CtsShimAddApkToApex",
+    sdk_version: "current",
+    srcs: ["shim_add_apk_to_apex/src/android/addapktoapex/app/AddApkToApexDeviceActivity.java"],
+    optimize: {
+        enabled: false,
+    },
+    dex_preopt: {
+        enabled: false,
+    },
+    manifest: "shim_add_apk_to_apex/AndroidManifestAddApkToApex.xml",
+    apex_available: [
+        "//apex_available:platform",
+        "com.android.apex.cts.shim.v2_add_apk_to_apex",
+    ],
+}
diff --git a/packages/CtsShim/build/shim_add_apk_to_apex/AndroidManifestAddApkToApex.xml b/packages/CtsShim/build/shim_add_apk_to_apex/AndroidManifestAddApkToApex.xml
new file mode 100644
index 0000000..0e620b0
--- /dev/null
+++ b/packages/CtsShim/build/shim_add_apk_to_apex/AndroidManifestAddApkToApex.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+     package="android.addapktoapex.app">
+
+    <application>
+        <activity android:name=".AddApkToApexDeviceActivity"
+             android:exported="true">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN"/>
+                <category android:name="android.intent.category.LAUNCHER"/>
+            </intent-filter>
+        </activity>
+    </application>
+
+</manifest>
\ No newline at end of file
diff --git a/packages/CtsShim/build/shim_add_apk_to_apex/src/android/addapktoapex/app/AddApkToApexDeviceActivity.java b/packages/CtsShim/build/shim_add_apk_to_apex/src/android/addapktoapex/app/AddApkToApexDeviceActivity.java
new file mode 100644
index 0000000..c68904b
--- /dev/null
+++ b/packages/CtsShim/build/shim_add_apk_to_apex/src/android/addapktoapex/app/AddApkToApexDeviceActivity.java
@@ -0,0 +1,42 @@
+/*
+ * 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.addapktoapex.app;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.util.Log;
+
+/**
+ * A simple activity which logs to Logcat.
+ */
+public class AddApkToApexDeviceActivity extends Activity {
+
+    private static final String TAG = AddApkToApexDeviceActivity.class.getSimpleName();
+
+    /**
+     * The test string to log.
+     */
+    private static final String TEST_STRING = "AddApkToApexTestString";
+
+    @Override
+    public void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+        // Log the test string to Logcat.
+        Log.i(TAG, TEST_STRING);
+    }
+
+}
diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/PackageInstallerActivity.java b/packages/PackageInstaller/src/com/android/packageinstaller/PackageInstallerActivity.java
index e071c11..891896d 100644
--- a/packages/PackageInstaller/src/com/android/packageinstaller/PackageInstallerActivity.java
+++ b/packages/PackageInstaller/src/com/android/packageinstaller/PackageInstallerActivity.java
@@ -430,7 +430,7 @@
         if (mLocalLOGV) Log.i(TAG, "onResume(): mAppSnippet=" + mAppSnippet);
 
         if (mAppSnippet != null) {
-            // load dummy layout with OK button disabled until we override this layout in
+            // load placeholder layout with OK button disabled until we override this layout in
             // startInstallConfirm
             bindUi();
             checkIfAllowedAndInitiateInstall();
diff --git a/packages/SettingsLib/src/com/android/settingslib/fuelgauge/BatteryStatus.java b/packages/SettingsLib/src/com/android/settingslib/fuelgauge/BatteryStatus.java
index 9ab84d2..f90a17a 100644
--- a/packages/SettingsLib/src/com/android/settingslib/fuelgauge/BatteryStatus.java
+++ b/packages/SettingsLib/src/com/android/settingslib/fuelgauge/BatteryStatus.java
@@ -45,6 +45,7 @@
     private static final int EXTREME_LOW_BATTERY_THRESHOLD = 3;
     private static final int DEFAULT_CHARGING_VOLTAGE_MICRO_VOLT = 5000000;
 
+    public static final int BATTERY_LEVEL_UNKNOWN = -1;
     public static final int CHARGING_UNKNOWN = -1;
     public static final int CHARGING_SLOWLY = 0;
     public static final int CHARGING_REGULAR = 1;
@@ -186,12 +187,13 @@
     /** Gets the battery level from the intent. */
     public static int getBatteryLevel(Intent batteryChangedIntent) {
         if (batteryChangedIntent == null) {
-            return -1; /*invalid battery level*/
+            return BATTERY_LEVEL_UNKNOWN;
         }
-        final int level = batteryChangedIntent.getIntExtra(BatteryManager.EXTRA_LEVEL, -1);
+        final int level =
+                batteryChangedIntent.getIntExtra(BatteryManager.EXTRA_LEVEL, BATTERY_LEVEL_UNKNOWN);
         final int scale = batteryChangedIntent.getIntExtra(BatteryManager.EXTRA_SCALE, 0);
         return scale == 0
-                ? -1 /*invalid battery level*/
+                ? BATTERY_LEVEL_UNKNOWN
                 : Math.round((level / (float) scale) * 100f);
     }
 
diff --git a/packages/SettingsProvider/src/android/provider/settings/backup/GlobalSettings.java b/packages/SettingsProvider/src/android/provider/settings/backup/GlobalSettings.java
index 41ce58e..294df72 100644
--- a/packages/SettingsProvider/src/android/provider/settings/backup/GlobalSettings.java
+++ b/packages/SettingsProvider/src/android/provider/settings/backup/GlobalSettings.java
@@ -24,7 +24,7 @@
     /**
      * These keys may be mentioned in the SETTINGS_TO_BACKUP arrays in SystemSettings
      * and SecureSettings as well.  This is because those tables drive both backup and
-     * restore, and restore needs to properly whitelist keys that used to live
+     * restore, and restore needs to properly allowlist keys that used to live
      * in those namespaces.
      *
      * NOTE: Settings are backed up and restored in the order they appear
diff --git a/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java b/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java
index 3efb41d..c2dbf98 100644
--- a/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java
+++ b/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java
@@ -240,6 +240,7 @@
         Settings.Secure.HEARING_AID_CALL_ROUTING,
         Settings.Secure.HEARING_AID_MEDIA_ROUTING,
         Settings.Secure.HEARING_AID_SYSTEM_SOUNDS_ROUTING,
-        Settings.Secure.ACCESSIBILITY_FONT_SCALING_HAS_BEEN_CHANGED
+        Settings.Secure.ACCESSIBILITY_FONT_SCALING_HAS_BEEN_CHANGED,
+        Settings.Secure.SEARCH_PRESS_HOLD_NAV_HANDLE_ENABLED
     };
 }
diff --git a/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java b/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
index e5f7f88..a49461e 100644
--- a/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
+++ b/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
@@ -198,6 +198,7 @@
         VALIDATORS.put(Secure.ASSIST_GESTURE_WAKE_ENABLED, BOOLEAN_VALIDATOR);
         VALIDATORS.put(Secure.ASSIST_TOUCH_GESTURE_ENABLED, BOOLEAN_VALIDATOR);
         VALIDATORS.put(Secure.ASSIST_LONG_PRESS_HOME_ENABLED, BOOLEAN_VALIDATOR);
+        VALIDATORS.put(Secure.SEARCH_PRESS_HOLD_NAV_HANDLE_ENABLED, BOOLEAN_VALIDATOR);
         VALIDATORS.put(Secure.VR_DISPLAY_MODE, new DiscreteValueValidator(new String[] {"0", "1"}));
         VALIDATORS.put(Secure.NOTIFICATION_BADGING, BOOLEAN_VALIDATOR);
         VALIDATORS.put(Secure.NOTIFICATION_DISMISS_RTL, BOOLEAN_VALIDATOR);
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java
index 056be2e..53c8dc9 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java
@@ -905,7 +905,7 @@
     @VisibleForTesting
     SettingsBackupWhitelist getBackupWhitelist(Uri contentUri) {
         // Figure out the white list and redirects to the global table.  We restore anything
-        // in either the backup whitelist or the legacy-restore whitelist for this table.
+        // in either the backup allowlist or the legacy-restore allowlist for this table.
         String[] whitelist;
         Map<String, Validator> validators = null;
         if (contentUri.equals(Settings.Secure.CONTENT_URI)) {
@@ -1453,7 +1453,7 @@
     }
 
     /**
-     * Store the whitelist of settings to be backed up and validators for them.
+     * Store the allowlist of settings to be backed up and validators for them.
      */
     @VisibleForTesting
     static class SettingsBackupWhitelist {
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
index a83bfda..ef4e84f 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
@@ -1926,6 +1926,9 @@
         dumpSetting(s, p,
                 Settings.Secure.ASSIST_LONG_PRESS_HOME_ENABLED,
                 SecureSettingsProto.Assist.LONG_PRESS_HOME_ENABLED);
+        dumpSetting(s, p,
+                Settings.Secure.SEARCH_PRESS_HOLD_NAV_HANDLE_ENABLED,
+                SecureSettingsProto.Assist.SEARCH_PRESS_HOLD_NAV_HANDLE_ENABLED);
         p.end(assistToken);
 
         final long assistHandlesToken = p.start(SecureSettingsProto.ASSIST_HANDLES);
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index b76c66b..215a040 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -250,7 +250,7 @@
     public static final int WRITE_FALLBACK_SETTINGS_FILES_JOB_ID = 1;
     public static final long ONE_DAY_INTERVAL_MILLIS = 24 * 60 * 60 * 1000L;
 
-    // Overlay specified settings whitelisted for Instant Apps
+    // Overlay specified settings allowlisted for Instant Apps
     private static final Set<String> OVERLAY_ALLOWED_GLOBAL_INSTANT_APP_SETTINGS = new ArraySet<>();
     private static final Set<String> OVERLAY_ALLOWED_SYSTEM_INSTANT_APP_SETTINGS = new ArraySet<>();
     private static final Set<String> OVERLAY_ALLOWED_SECURE_INSTANT_APP_SETTINGS = new ArraySet<>();
@@ -2131,7 +2131,7 @@
 
     @GuardedBy("mLock")
     private List<String> getSettingsNamesLocked(int settingsType, int userId) {
-        // Don't enforce the instant app whitelist for now -- its too prone to unintended breakage
+        // Don't enforce the instant app allowlist for now -- its too prone to unintended breakage
         // in the current form.
         return mSettingsRegistry.getSettingsNamesLocked(settingsType, userId);
     }
@@ -2172,7 +2172,7 @@
         }
         if (!getInstantAppAccessibleSettings(settingsType).contains(settingName)
                 && !getOverlayInstantAppAccessibleSettings(settingsType).contains(settingName)) {
-            // Don't enforce the instant app whitelist for now -- its too prone to unintended
+            // Don't enforce the instant app allowlist for now -- its too prone to unintended
             // breakage in the current form.
             Slog.w(LOG_TAG, "Instant App " + ai.packageName
                     + " trying to access unexposed setting, this will be an error in the future.");
diff --git a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/ClockRegistry.kt b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/ClockRegistry.kt
index 798bdec4..ab0225d 100644
--- a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/ClockRegistry.kt
+++ b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/ClockRegistry.kt
@@ -409,6 +409,18 @@
             scope.launch(bgDispatcher) { mutateSetting { it.copy(seedColor = value) } }
         }
 
+    // Returns currentClockId if clock is connected, otherwise DEFAULT_CLOCK_ID. Since this
+    // is dependent on which clocks are connected, it may change when a clock is installed or
+    // removed from the device (unlike currentClockId).
+    // TODO: Merge w/ CurrentClockId when we convert to a flow. We shouldn't need both behaviors.
+    val activeClockId: String
+        get() {
+            if (!availableClocks.containsKey(currentClockId)) {
+                return DEFAULT_CLOCK_ID
+            }
+            return currentClockId
+        }
+
     init {
         // Register default clock designs
         for (clock in defaultClockProvider.getClocks()) {
diff --git a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/DefaultClockController.kt b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/DefaultClockController.kt
index e7a53e5b..b28920c 100644
--- a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/DefaultClockController.kt
+++ b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/DefaultClockController.kt
@@ -65,7 +65,7 @@
     protected var onSecondaryDisplay: Boolean = false
 
     override val events: DefaultClockEvents
-    override val config = ClockConfig()
+    override val config = ClockConfig(DEFAULT_CLOCK_ID)
 
     init {
         val parent = FrameLayout(ctx)
diff --git a/packages/SystemUI/docs/qs-tiles.md b/packages/SystemUI/docs/qs-tiles.md
index 488f8c7..bd0b4ab 100644
--- a/packages/SystemUI/docs/qs-tiles.md
+++ b/packages/SystemUI/docs/qs-tiles.md
@@ -123,7 +123,7 @@
 
 ### API classes
 
-The classes that define the public API are in [core/java/android/service/quicksettings](core/java/android/service/quicksettings).
+The classes that define the public API are in [core/java/android/service/quicksettings](/core/java/android/service/quicksettings).
 
 #### Tile
 
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/ClockProviderPlugin.kt b/packages/SystemUI/plugin/src/com/android/systemui/plugins/ClockProviderPlugin.kt
index 527f8007..e2f4793 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/ClockProviderPlugin.kt
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/ClockProviderPlugin.kt
@@ -199,6 +199,8 @@
 
 /** Render configuration for the full clock. Modifies the way systemUI behaves with this clock. */
 data class ClockConfig(
+    val id: String,
+
     /** Transition to AOD should move smartspace like large clock instead of small clock */
     val useAlternateSmartspaceAODTransition: Boolean = false,
 
diff --git a/packages/SystemUI/res-keyguard/layout/shade_carrier_new.xml b/packages/SystemUI/res-keyguard/layout/shade_carrier_new.xml
new file mode 100644
index 0000000..952f056
--- /dev/null
+++ b/packages/SystemUI/res-keyguard/layout/shade_carrier_new.xml
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+**
+** Copyright 2023, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+<com.android.systemui.statusbar.pipeline.mobile.ui.view.ModernShadeCarrierGroupMobileView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/carrier_combo"
+    android:layout_width="wrap_content"
+    android:layout_height="match_parent"
+    android:gravity="center_vertical"
+    android:orientation="horizontal" >
+
+    <com.android.systemui.util.AutoMarqueeTextView
+        android:id="@+id/mobile_carrier_text"
+        android:layout_width="0dp"
+        android:layout_height="wrap_content"
+        android:layout_weight="1"
+        android:layout_marginEnd="@dimen/qs_carrier_margin_width"
+        android:visibility="gone"
+        android:textDirection="locale"
+        android:marqueeRepeatLimit="marquee_forever"
+        android:singleLine="true"
+        android:maxEms="7"/>
+
+    <include layout="@layout/status_bar_mobile_signal_group_new" />
+
+</com.android.systemui.statusbar.pipeline.mobile.ui.view.ModernShadeCarrierGroupMobileView>
+
diff --git a/packages/SystemUI/res/drawable/stat_sys_ringer_silent.xml b/packages/SystemUI/res/drawable/stat_sys_ringer_silent.xml
index 4a9d41f..b83f15a 100644
--- a/packages/SystemUI/res/drawable/stat_sys_ringer_silent.xml
+++ b/packages/SystemUI/res/drawable/stat_sys_ringer_silent.xml
@@ -14,6 +14,4 @@
     limitations under the License.
 -->
 <inset xmlns:android="http://schemas.android.com/apk/res/android"
-    android:insetLeft="3dp"
-    android:insetRight="3dp"
     android:drawable="@drawable/ic_speaker_mute" />
diff --git a/packages/SystemUI/res/layout/screenshot_work_profile_first_run.xml b/packages/SystemUI/res/layout/screenshot_work_profile_first_run.xml
index 78cd718..39ec09b 100644
--- a/packages/SystemUI/res/layout/screenshot_work_profile_first_run.xml
+++ b/packages/SystemUI/res/layout/screenshot_work_profile_first_run.xml
@@ -34,8 +34,8 @@
         android:layout_height="@dimen/overlay_dismiss_button_tappable_size"
         android:contentDescription="@string/screenshot_dismiss_work_profile">
         <ImageView
-            android:layout_width="16dp"
-            android:layout_height="16dp"
+            android:layout_width="24dp"
+            android:layout_height="24dp"
             android:layout_gravity="center"
             android:background="@drawable/circular_background"
             android:backgroundTint="?androidprv:attr/materialColorSurfaceContainerHigh"
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java
index b589887..06b6692 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java
@@ -39,6 +39,7 @@
 public class KeyguardClockSwitch extends RelativeLayout {
 
     private static final String TAG = "KeyguardClockSwitch";
+    public static final String MISSING_CLOCK_ID = "CLOCK_MISSING";
 
     private static final long CLOCK_OUT_MILLIS = 133;
     private static final long CLOCK_IN_MILLIS = 167;
@@ -196,6 +197,14 @@
         return mLogBuffer;
     }
 
+    /** Returns the id of the currently rendering clock */
+    public String getClockId() {
+        if (mClock == null) {
+            return MISSING_CLOCK_ID;
+        }
+        return mClock.getConfig().getId();
+    }
+
     void setClock(ClockController clock, int statusBarState) {
         mClock = clock;
 
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java
index 0ed802e..4ccd3a9 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java
@@ -222,8 +222,10 @@
         mSmallClockFrame = mView.findViewById(R.id.lockscreen_clock_view);
         mLargeClockFrame = mView.findViewById(R.id.lockscreen_clock_view_large);
 
-        mDumpManager.unregisterDumpable(getClass().toString()); // unregister previous clocks
-        mDumpManager.registerDumpable(getClass().toString(), this);
+        if (!mOnlyClock) {
+            mDumpManager.unregisterDumpable(getClass().toString()); // unregister previous clocks
+            mDumpManager.registerDumpable(getClass().toString(), this);
+        }
 
         if (mFeatureFlags.isEnabled(LOCKSCREEN_WALLPAPER_DREAM_ENABLED)) {
             mStatusArea = mView.findViewById(R.id.keyguard_status_area);
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java
index 04692c4..9f3908a 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java
@@ -27,6 +27,7 @@
 import static com.android.keyguard.KeyguardSecurityContainer.USER_TYPE_SECONDARY_USER;
 import static com.android.keyguard.KeyguardSecurityContainer.USER_TYPE_WORK_PROFILE;
 import static com.android.systemui.DejankUtils.whitelistIpcs;
+import static com.android.systemui.flags.Flags.LOCKSCREEN_ENABLE_LANDSCAPE;
 import static com.android.systemui.flags.Flags.REVAMPED_BOUNCER_MESSAGES;
 
 import android.app.ActivityManager;
@@ -370,8 +371,12 @@
 
                 @Override
                 public void onOrientationChanged(int orientation) {
-                    KeyguardSecurityContainerController.this
+                    if (mFeatureFlags.isEnabled(LOCKSCREEN_ENABLE_LANDSCAPE)) {
+                        // TODO(b/295603468)
+                        // Fix reinflation of views when flag is enabled.
+                        KeyguardSecurityContainerController.this
                             .onDensityOrFontScaleOrOrientationChanged();
+                    }
                 }
             };
     private final KeyguardUpdateMonitorCallback mKeyguardUpdateMonitorCallback =
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
index f73a602..64c4eec 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
@@ -107,6 +107,7 @@
 import com.android.systemui.statusbar.notification.row.dagger.NotificationShelfComponent;
 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;
@@ -184,6 +185,7 @@
             MediaProjectionModule.class,
             MediaProjectionTaskSwitcherModule.class,
             MotionToolModule.class,
+            NotificationIconAreaControllerModule.class,
             PeopleHubModule.class,
             PeopleModule.class,
             PluginModule.class,
diff --git a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
index 93bdac2..6d68eef 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
+++ b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
@@ -398,6 +398,10 @@
     // TODO(b/294588085): Tracking Bug
     val WIFI_SECONDARY_NETWORKS = releasedFlag("wifi_secondary_networks")
 
+    // TODO(b/290676905): Tracking Bug
+    val NEW_SHADE_CARRIER_GROUP_MOBILE_ICONS =
+        unreleasedFlag("new_shade_carrier_group_mobile_icons")
+
     // 700 - dialer/calls
     // TODO(b/254512734): Tracking Bug
     val ONGOING_CALL_STATUS_BAR_CHIP = releasedFlag("ongoing_call_status_bar_chip")
@@ -502,21 +506,6 @@
     val WM_CAPTION_ON_SHELL =
         sysPropBooleanFlag("persist.wm.debug.caption_on_shell", default = true)
 
-    @Keep
-    @JvmField
-    val ENABLE_FLING_TO_DISMISS_BUBBLE =
-        sysPropBooleanFlag("persist.wm.debug.fling_to_dismiss_bubble", default = true)
-
-    @Keep
-    @JvmField
-    val ENABLE_FLING_TO_DISMISS_PIP =
-        sysPropBooleanFlag("persist.wm.debug.fling_to_dismiss_pip", default = true)
-
-    @Keep
-    @JvmField
-    val ENABLE_PIP_KEEP_CLEAR_ALGORITHM =
-        sysPropBooleanFlag("persist.wm.debug.enable_pip_keep_clear_algorithm", default = true)
-
     // TODO(b/256873975): Tracking Bug
     @JvmField
     @Keep
@@ -538,13 +527,6 @@
             teamfood = false
         )
 
-    // TODO(b/198643358): Tracking bug
-    @Keep
-    @JvmField
-    val ENABLE_PIP_SIZE_LARGE_SCREEN =
-        sysPropBooleanFlag("persist.wm.debug.enable_pip_size_large_screen", default = true)
-
-
     // TODO(b/293252410) : Tracking Bug
     @JvmField
     val LOCKSCREEN_ENABLE_LANDSCAPE =
@@ -628,6 +610,10 @@
     // TODO(b/251205791): Tracking Bug
     @JvmField val SCREENSHOT_APP_CLIPS = releasedFlag("screenshot_app_clips")
 
+    /** TODO(b/295143676): Tracking bug. When enable, captures a screenshot for each display. */
+    @JvmField
+    val MULTI_DISPLAY_SCREENSHOT = unreleasedFlag("multi_display_screenshot")
+
     // 1400 - columbus
     // TODO(b/254512756): Tracking Bug
     val QUICK_TAP_IN_PCC = releasedFlag("quick_tap_in_pcc")
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardKeyEventInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardKeyEventInteractor.kt
index 635961b..e501ece 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardKeyEventInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardKeyEventInteractor.kt
@@ -54,7 +54,11 @@
         if (event.handleAction()) {
             when (event.keyCode) {
                 KeyEvent.KEYCODE_MENU -> return dispatchMenuKeyEvent()
-                KeyEvent.KEYCODE_SPACE -> return dispatchSpaceEvent()
+                KeyEvent.KEYCODE_SPACE,
+                KeyEvent.KEYCODE_ENTER ->
+                    if (isDeviceInteractive()) {
+                        return collapseShadeLockedOrShowPrimaryBouncer()
+                    }
             }
         }
         return false
@@ -90,16 +94,22 @@
                 (statusBarStateController.state != StatusBarState.SHADE) &&
                 statusBarKeyguardViewManager.shouldDismissOnMenuPressed()
         if (shouldUnlockOnMenuPressed) {
-            shadeController.animateCollapseShadeForced()
-            return true
+            return collapseShadeLockedOrShowPrimaryBouncer()
         }
         return false
     }
 
-    private fun dispatchSpaceEvent(): Boolean {
-        if (isDeviceInteractive() && statusBarStateController.state != StatusBarState.SHADE) {
-            shadeController.animateCollapseShadeForced()
-            return true
+    private fun collapseShadeLockedOrShowPrimaryBouncer(): Boolean {
+        when (statusBarStateController.state) {
+            StatusBarState.SHADE -> return false
+            StatusBarState.SHADE_LOCKED -> {
+                shadeController.animateCollapseShadeForced()
+                return true
+            }
+            StatusBarState.KEYGUARD -> {
+                statusBarKeyguardViewManager.showPrimaryBouncer(true)
+                return true
+            }
         }
         return false
     }
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseAdapter.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseAdapter.java
index a3d1d8c..d8824983 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseAdapter.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseAdapter.java
@@ -515,11 +515,13 @@
             mSeekBar.setOnTouchListener((v, event) -> false);
             updateIconAreaClickListener((v) -> {
                 if (device.getCurrentVolume() == 0) {
+                    mController.logInteractionUnmuteDevice(device);
                     mSeekBar.setVolume(UNMUTE_DEFAULT_VOLUME);
                     mController.adjustVolume(device, UNMUTE_DEFAULT_VOLUME);
                     updateUnmutedVolumeIcon();
                     mIconAreaLayout.setOnTouchListener(((iconV, event) -> false));
                 } else {
+                    mController.logInteractionMuteDevice(device);
                     mSeekBar.resetVolume();
                     mController.adjustVolume(device, 0);
                     updateMutedVolumeIcon();
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java
index b431bab..13cd8e3 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java
@@ -843,6 +843,14 @@
         mMetricLogger.logInteractionAdjustVolume(device);
     }
 
+    void logInteractionMuteDevice(MediaDevice device) {
+        mMetricLogger.logInteractionMute(device);
+    }
+
+    void logInteractionUnmuteDevice(MediaDevice device) {
+        mMetricLogger.logInteractionUnmute(device);
+    }
+
     String getPackageName() {
         return mPackageName;
     }
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputMetricLogger.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputMetricLogger.java
index 412d1a3..ffd626a 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputMetricLogger.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputMetricLogger.java
@@ -154,6 +154,38 @@
     }
 
     /**
+     * Do the metric logging of muting device.
+     */
+    public void logInteractionMute(MediaDevice source) {
+        if (DEBUG) {
+            Log.d(TAG, "logInteraction - Mute");
+        }
+
+        SysUiStatsLog.write(
+                SysUiStatsLog.MEDIAOUTPUT_OP_INTERACTION_REPORT,
+                SysUiStatsLog.MEDIA_OUTPUT_OP_INTERACTION_REPORTED__INTERACTION_TYPE__MUTE,
+                getInteractionDeviceType(source),
+                getLoggingPackageName(),
+                source.isSuggestedDevice());
+    }
+
+    /**
+     * Do the metric logging of unmuting device.
+     */
+    public void logInteractionUnmute(MediaDevice source) {
+        if (DEBUG) {
+            Log.d(TAG, "logInteraction - Unmute");
+        }
+
+        SysUiStatsLog.write(
+                SysUiStatsLog.MEDIAOUTPUT_OP_INTERACTION_REPORT,
+                SysUiStatsLog.MEDIA_OUTPUT_OP_INTERACTION_REPORTED__INTERACTION_TYPE__UNMUTE,
+                getInteractionDeviceType(source),
+                getLoggingPackageName(),
+                source.isSuggestedDevice());
+    }
+
+    /**
      * Do the metric logging of content switching failure.
      *
      * @param deviceItemList media item list for device count updating
diff --git a/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordPermissionDialog.kt b/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordPermissionDialog.kt
index e8683fb..fb99775 100644
--- a/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordPermissionDialog.kt
+++ b/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordPermissionDialog.kt
@@ -63,6 +63,7 @@
     override fun onCreate(savedInstanceState: Bundle?) {
         super.onCreate(savedInstanceState)
         setDialogTitle(R.string.screenrecord_permission_dialog_title)
+        setTitle(R.string.screenrecord_title)
         setStartButtonText(R.string.screenrecord_permission_dialog_continue)
         setStartButtonOnClickListener { v: View? ->
             onStartRecordingClicked?.run()
diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
index cabbeb1..014093d 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
@@ -985,6 +985,7 @@
         // Make sure the clock is in the correct position after the unlock animation
         // so that it's not in the wrong place when we show the keyguard again.
         positionClockAndNotifications(true /* forceClockUpdate */);
+        mScrimController.onUnlockAnimationFinished();
     }
 
     private void unlockAnimationStarted(
@@ -1243,6 +1244,13 @@
             mKeyguardStatusViewController.init();
         }
         mKeyguardStatusViewController.setSplitShadeEnabled(mSplitShadeEnabled);
+        mKeyguardStatusViewController.getView().addOnLayoutChangeListener(
+                (v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom) -> {
+                    int oldHeight = oldBottom - oldTop;
+                    if (v.getHeight() != oldHeight) {
+                        mNotificationStackScrollLayoutController.animateNextTopPaddingChange();
+                    }
+                });
 
         updateClockAppearance();
 
diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java
index 832a25b..798f2d5 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java
@@ -21,8 +21,6 @@
 import static com.android.systemui.util.kotlin.JavaAdapterKt.collectFlow;
 
 import android.app.StatusBarManager;
-import android.media.AudioManager;
-import android.media.session.MediaSessionLegacyHelper;
 import android.os.PowerManager;
 import android.util.Log;
 import android.view.GestureDetector;
@@ -47,6 +45,7 @@
 import com.android.systemui.dock.DockManager;
 import com.android.systemui.flags.FeatureFlags;
 import com.android.systemui.flags.Flags;
+import com.android.systemui.keyevent.domain.interactor.KeyEventInteractor;
 import com.android.systemui.keyguard.KeyguardUnlockAnimationController;
 import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor;
 import com.android.systemui.keyguard.shared.model.TransitionState;
@@ -101,13 +100,21 @@
     private final NotificationInsetsController mNotificationInsetsController;
     private final boolean mIsTrackpadCommonEnabled;
     private final FeatureFlags mFeatureFlags;
+    private final KeyEventInteractor mKeyEventInteractor;
     private GestureDetector mPulsingWakeupGestureHandler;
     private GestureDetector mDreamingWakeupGestureHandler;
     private View mBrightnessMirror;
     private boolean mTouchActive;
     private boolean mTouchCancelled;
     private MotionEvent mDownEvent;
+    // TODO rename to mLaunchAnimationRunning
     private boolean mExpandAnimationRunning;
+    /**
+     *  When mExpandAnimationRunning is true and the touch dispatcher receives a down even after
+     *  uptime exceeds this, the dispatcher will stop blocking touches for the launch animation,
+     *  which has presumabely not completed due to an error.
+     */
+    private long mLaunchAnimationTimeout;
     private NotificationStackScrollLayout mStackScrollLayout;
     private PhoneStatusBarViewController mStatusBarViewController;
     private final CentralSurfaces mService;
@@ -164,7 +171,8 @@
             FeatureFlags featureFlags,
             SystemClock clock,
             BouncerMessageInteractor bouncerMessageInteractor,
-            BouncerLogger bouncerLogger) {
+            BouncerLogger bouncerLogger,
+            KeyEventInteractor keyEventInteractor) {
         mLockscreenShadeTransitionController = transitionController;
         mFalsingCollector = falsingCollector;
         mStatusBarStateController = statusBarStateController;
@@ -190,6 +198,7 @@
         mNotificationInsetsController = notificationInsetsController;
         mIsTrackpadCommonEnabled = featureFlags.isEnabled(TRACKPAD_GESTURE_COMMON);
         mFeatureFlags = featureFlags;
+        mKeyEventInteractor = keyEventInteractor;
 
         // This view is not part of the newly inflated expanded status bar.
         mBrightnessMirror = mView.findViewById(R.id.brightness_mirror_container);
@@ -278,7 +287,12 @@
                     return logDownDispatch(ev, "touch cancelled", false);
                 }
                 if (mExpandAnimationRunning) {
-                    return logDownDispatch(ev, "expand animation running", false);
+                    if (isDown && mClock.uptimeMillis() > mLaunchAnimationTimeout) {
+                        mShadeLogger.d("NSWVC: launch animation timed out");
+                        setExpandAnimationRunning(false);
+                    } else {
+                        return logDownDispatch(ev, "expand animation running", false);
+                    }
                 }
 
                 if (mKeyguardUnlockAnimationController.isPlayingCannedUnlockAnimation()) {
@@ -457,44 +471,17 @@
 
             @Override
             public boolean interceptMediaKey(KeyEvent event) {
-                return mService.interceptMediaKey(event);
+                return mKeyEventInteractor.interceptMediaKey(event);
             }
 
             @Override
             public boolean dispatchKeyEventPreIme(KeyEvent event) {
-                return mService.dispatchKeyEventPreIme(event);
+                return mKeyEventInteractor.dispatchKeyEventPreIme(event);
             }
 
             @Override
             public boolean dispatchKeyEvent(KeyEvent event) {
-                boolean down = event.getAction() == KeyEvent.ACTION_DOWN;
-                switch (event.getKeyCode()) {
-                    case KeyEvent.KEYCODE_BACK:
-                        if (!down) {
-                            mBackActionInteractor.onBackRequested();
-                        }
-                        return true;
-                    case KeyEvent.KEYCODE_MENU:
-                        if (!down) {
-                            return mService.onMenuPressed();
-                        }
-                        break;
-                    case KeyEvent.KEYCODE_SPACE:
-                        if (!down) {
-                            return mService.onSpacePressed();
-                        }
-                        break;
-                    case KeyEvent.KEYCODE_VOLUME_DOWN:
-                    case KeyEvent.KEYCODE_VOLUME_UP:
-                        if (mStatusBarStateController.isDozing()) {
-                            MediaSessionLegacyHelper.getHelper(mView.getContext())
-                                    .sendVolumeKeyEvent(
-                                            event, AudioManager.USE_DEFAULT_STREAM_TYPE, true);
-                            return true;
-                        }
-                        break;
-                }
-                return false;
+                return mKeyEventInteractor.dispatchKeyEvent(event);
             }
         });
 
@@ -555,8 +542,12 @@
         pw.println(mTouchActive);
     }
 
-    private void setExpandAnimationRunning(boolean running) {
+    @VisibleForTesting
+    void setExpandAnimationRunning(boolean running) {
         if (mExpandAnimationRunning != running) {
+            if (running) {
+                mLaunchAnimationTimeout = mClock.uptimeMillis() + 5000;
+            }
             mExpandAnimationRunning = running;
             mNotificationShadeWindowController.setLaunchingActivity(mExpandAnimationRunning);
         }
diff --git a/packages/SystemUI/src/com/android/systemui/shade/carrier/ShadeCarrier.java b/packages/SystemUI/src/com/android/systemui/shade/carrier/ShadeCarrier.java
index 8586828..8612cdf 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/carrier/ShadeCarrier.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/carrier/ShadeCarrier.java
@@ -34,6 +34,7 @@
 import com.android.settingslib.graph.SignalDrawable;
 import com.android.systemui.FontSizeUtils;
 import com.android.systemui.R;
+import com.android.systemui.statusbar.pipeline.mobile.ui.view.ModernShadeCarrierGroupMobileView;
 import com.android.systemui.util.LargeScreenUtils;
 
 import java.util.Objects;
@@ -44,6 +45,7 @@
     private TextView mCarrierText;
     private ImageView mMobileSignal;
     private ImageView mMobileRoaming;
+    private ModernShadeCarrierGroupMobileView mModernMobileView;
     private View mSpacer;
     @Nullable
     private CellSignalState mLastSignalState;
@@ -77,6 +79,23 @@
         updateResources();
     }
 
+    /** Removes a ModernStatusBarMobileView from the ViewGroup. */
+    public void removeModernMobileView() {
+        if (mModernMobileView != null) {
+            removeView(mModernMobileView);
+            mModernMobileView = null;
+        }
+    }
+
+    /** Adds a ModernStatusBarMobileView to the ViewGroup. */
+    public void addModernMobileView(ModernShadeCarrierGroupMobileView mobileView) {
+        mModernMobileView = mobileView;
+        mMobileGroup.setVisibility(View.GONE);
+        mSpacer.setVisibility(View.GONE);
+        mCarrierText.setVisibility(View.GONE);
+        addView(mobileView);
+    }
+
     /**
      * Update the state of this view
      * @param state the current state of the signal for this view
diff --git a/packages/SystemUI/src/com/android/systemui/shade/carrier/ShadeCarrierGroupController.java b/packages/SystemUI/src/com/android/systemui/shade/carrier/ShadeCarrierGroupController.java
index ad49b26..98d8a53 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/carrier/ShadeCarrierGroupController.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/carrier/ShadeCarrierGroupController.java
@@ -16,6 +16,7 @@
 
 package com.android.systemui.shade.carrier;
 
+import static android.telephony.SubscriptionManager.INVALID_SIM_SLOT_INDEX;
 import static android.view.View.IMPORTANT_FOR_ACCESSIBILITY_YES;
 
 import android.annotation.MainThread;
@@ -46,8 +47,17 @@
 import com.android.systemui.statusbar.connectivity.MobileDataIndicators;
 import com.android.systemui.statusbar.connectivity.NetworkController;
 import com.android.systemui.statusbar.connectivity.SignalCallback;
+import com.android.systemui.statusbar.connectivity.ui.MobileContextProvider;
+import com.android.systemui.statusbar.phone.StatusBarLocation;
+import com.android.systemui.statusbar.pipeline.StatusBarPipelineFlags;
+import com.android.systemui.statusbar.pipeline.mobile.ui.MobileUiAdapter;
+import com.android.systemui.statusbar.pipeline.mobile.ui.binder.MobileIconsBinder;
+import com.android.systemui.statusbar.pipeline.mobile.ui.view.ModernShadeCarrierGroupMobileView;
+import com.android.systemui.statusbar.pipeline.mobile.ui.viewmodel.MobileIconsViewModel;
+import com.android.systemui.statusbar.pipeline.mobile.ui.viewmodel.ShadeCarrierGroupMobileIconViewModel;
 import com.android.systemui.util.CarrierConfigTracker;
 
+import java.util.List;
 import java.util.function.Consumer;
 
 import javax.inject.Inject;
@@ -62,12 +72,16 @@
 
     private final ActivityStarter mActivityStarter;
     private final Handler mBgHandler;
+    private final Context mContext;
     private final NetworkController mNetworkController;
     private final CarrierTextManager mCarrierTextManager;
     private final TextView mNoSimTextView;
     // Non final for testing
     private H mMainHandler;
     private final Callback mCallback;
+    private final MobileIconsViewModel mMobileIconsViewModel;
+    private final MobileContextProvider mMobileContextProvider;
+    private final StatusBarPipelineFlags mStatusBarPipelineFlags;
     private boolean mListening;
     private final CellSignalState[] mInfos =
             new CellSignalState[SIM_SLOTS];
@@ -91,7 +105,7 @@
                         Log.w(TAG, "setMobileDataIndicators - slot: " + slotIndex);
                         return;
                     }
-                    if (slotIndex == SubscriptionManager.INVALID_SIM_SLOT_INDEX) {
+                    if (slotIndex == INVALID_SIM_SLOT_INDEX) {
                         Log.e(TAG, "Invalid SIM slot index for subscription: " + indicators.subId);
                         return;
                     }
@@ -129,15 +143,25 @@
         }
     }
 
-    private ShadeCarrierGroupController(ShadeCarrierGroup view, ActivityStarter activityStarter,
-            @Background Handler bgHandler, @Main Looper mainLooper,
+    private ShadeCarrierGroupController(
+            ShadeCarrierGroup view,
+            ActivityStarter activityStarter,
+            @Background Handler bgHandler,
+            @Main Looper mainLooper,
             NetworkController networkController,
-            CarrierTextManager.Builder carrierTextManagerBuilder, Context context,
-            CarrierConfigTracker carrierConfigTracker, SlotIndexResolver slotIndexResolver) {
-
+            CarrierTextManager.Builder carrierTextManagerBuilder,
+            Context context,
+            CarrierConfigTracker carrierConfigTracker,
+            SlotIndexResolver slotIndexResolver,
+            MobileUiAdapter mobileUiAdapter,
+            MobileContextProvider mobileContextProvider,
+            StatusBarPipelineFlags statusBarPipelineFlags
+    ) {
+        mContext = context;
         mActivityStarter = activityStarter;
         mBgHandler = bgHandler;
         mNetworkController = networkController;
+        mStatusBarPipelineFlags = statusBarPipelineFlags;
         mCarrierTextManager = carrierTextManagerBuilder
                 .setShowAirplaneMode(false)
                 .setShowMissingSim(false)
@@ -162,6 +186,14 @@
         mCarrierGroups[1] = view.getCarrier2View();
         mCarrierGroups[2] = view.getCarrier3View();
 
+        mMobileContextProvider = mobileContextProvider;
+        mMobileIconsViewModel = mobileUiAdapter.getMobileIconsViewModel();
+
+        if (mStatusBarPipelineFlags.useNewShadeCarrierGroupMobileIcons()) {
+            mobileUiAdapter.setShadeCarrierGroupController(this);
+            MobileIconsBinder.bind(view, mMobileIconsViewModel);
+        }
+
         mCarrierDividers[0] = view.getCarrierDivider1();
         mCarrierDividers[1] = view.getCarrierDivider2();
 
@@ -193,6 +225,50 @@
         });
     }
 
+    /** Updates the number of visible mobile icons using the new pipeline. */
+    public void updateModernMobileIcons(List<Integer> subIds) {
+        if (!mStatusBarPipelineFlags.useNewShadeCarrierGroupMobileIcons()) {
+            Log.d(TAG, "ignoring new pipeline callback because new mobile icon is disabled");
+            return;
+        }
+
+        for (ShadeCarrier carrier : mCarrierGroups) {
+            carrier.removeModernMobileView();
+        }
+
+        List<IconData> iconDataList = processSubIdList(subIds);
+
+        for (IconData iconData : iconDataList) {
+            ShadeCarrier carrier = mCarrierGroups[iconData.slotIndex];
+
+            Context mobileContext =
+                    mMobileContextProvider.getMobileContextForSub(iconData.subId, mContext);
+            ModernShadeCarrierGroupMobileView modernMobileView = ModernShadeCarrierGroupMobileView
+                    .constructAndBind(
+                        mobileContext,
+                        mMobileIconsViewModel.getLogger(),
+                        "mobile_carrier_shade_group",
+                        (ShadeCarrierGroupMobileIconViewModel) mMobileIconsViewModel
+                                .viewModelForSub(iconData.subId,
+                                    StatusBarLocation.SHADE_CARRIER_GROUP)
+                    );
+            carrier.addModernMobileView(modernMobileView);
+        }
+    }
+
+    @VisibleForTesting
+    List<IconData> processSubIdList(List<Integer> subIds) {
+        return subIds
+                .stream()
+                .limit(SIM_SLOTS)
+                .map(subId -> new IconData(subId, getSlotIndex(subId)))
+                .filter(iconData ->
+                        iconData.slotIndex < SIM_SLOTS
+                                && iconData.slotIndex != INVALID_SIM_SLOT_INDEX
+                )
+                .toList();
+    }
+
     @VisibleForTesting
     protected int getSlotIndex(int subscriptionId) {
         return mSlotIndexResolver.getSlotIndex(subscriptionId);
@@ -269,8 +345,12 @@
             }
         }
 
-        for (int i = 0; i < SIM_SLOTS; i++) {
-            mCarrierGroups[i].updateState(mInfos[i], singleCarrier);
+        if (mStatusBarPipelineFlags.useNewShadeCarrierGroupMobileIcons()) {
+            Log.d(TAG, "ignoring old pipeline callback because new mobile icon is enabled");
+        } else {
+            for (int i = 0; i < SIM_SLOTS; i++) {
+                mCarrierGroups[i].updateState(mInfos[i], singleCarrier);
+            }
         }
 
         mCarrierDividers[0].setVisibility(
@@ -306,7 +386,7 @@
                         Log.w(TAG, "updateInfoCarrier - slot: " + slot);
                         continue;
                     }
-                    if (slot == SubscriptionManager.INVALID_SIM_SLOT_INDEX) {
+                    if (slot == INVALID_SIM_SLOT_INDEX) {
                         Log.e(TAG,
                                 "Invalid SIM slot index for subscription: "
                                         + info.subscriptionIds[i]);
@@ -385,12 +465,24 @@
         private final Context mContext;
         private final CarrierConfigTracker mCarrierConfigTracker;
         private final SlotIndexResolver mSlotIndexResolver;
+        private final MobileUiAdapter mMobileUiAdapter;
+        private final MobileContextProvider mMobileContextProvider;
+        private final StatusBarPipelineFlags mStatusBarPipelineFlags;
 
         @Inject
-        public Builder(ActivityStarter activityStarter, @Background Handler handler,
-                @Main Looper looper, NetworkController networkController,
-                CarrierTextManager.Builder carrierTextControllerBuilder, Context context,
-                CarrierConfigTracker carrierConfigTracker, SlotIndexResolver slotIndexResolver) {
+        public Builder(
+                ActivityStarter activityStarter,
+                @Background Handler handler,
+                @Main Looper looper,
+                NetworkController networkController,
+                CarrierTextManager.Builder carrierTextControllerBuilder,
+                Context context,
+                CarrierConfigTracker carrierConfigTracker,
+                SlotIndexResolver slotIndexResolver,
+                MobileUiAdapter mobileUiAdapter,
+                MobileContextProvider mobileContextProvider,
+                StatusBarPipelineFlags statusBarPipelineFlags
+        ) {
             mActivityStarter = activityStarter;
             mHandler = handler;
             mLooper = looper;
@@ -399,6 +491,9 @@
             mContext = context;
             mCarrierConfigTracker = carrierConfigTracker;
             mSlotIndexResolver = slotIndexResolver;
+            mMobileUiAdapter = mobileUiAdapter;
+            mMobileContextProvider = mobileContextProvider;
+            mStatusBarPipelineFlags = statusBarPipelineFlags;
         }
 
         public Builder setShadeCarrierGroup(ShadeCarrierGroup view) {
@@ -407,9 +502,20 @@
         }
 
         public ShadeCarrierGroupController build() {
-            return new ShadeCarrierGroupController(mView, mActivityStarter, mHandler, mLooper,
-                    mNetworkController, mCarrierTextControllerBuilder, mContext,
-                    mCarrierConfigTracker, mSlotIndexResolver);
+            return new ShadeCarrierGroupController(
+                    mView,
+                    mActivityStarter,
+                    mHandler,
+                    mLooper,
+                    mNetworkController,
+                    mCarrierTextControllerBuilder,
+                    mContext,
+                    mCarrierConfigTracker,
+                    mSlotIndexResolver,
+                    mMobileUiAdapter,
+                    mMobileContextProvider,
+                    mStatusBarPipelineFlags
+            );
         }
     }
 
@@ -448,4 +554,15 @@
             return SubscriptionManager.getSlotIndex(subscriptionId);
         }
     }
+
+    @VisibleForTesting
+    static class IconData {
+        public final int subId;
+        public final int slotIndex;
+
+        IconData(int subId, int slotIndex) {
+            this.subId = subId;
+            this.slotIndex = slotIndex;
+        }
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ActionClickLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/ActionClickLogger.kt
index d3c19b7..5042f1b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ActionClickLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ActionClickLogger.kt
@@ -31,56 +31,68 @@
 ) {
     fun logInitialClick(
         entry: NotificationEntry?,
+        index: Integer?,
         pendingIntent: PendingIntent
     ) {
         buffer.log(TAG, LogLevel.DEBUG, {
             str1 = entry?.key
             str2 = entry?.ranking?.channel?.id
-            str3 = pendingIntent.intent.toString()
+            str3 = pendingIntent.toString()
+            int1 = index?.toInt() ?: Int.MIN_VALUE
         }, {
-            "ACTION CLICK $str1 (channel=$str2) for pending intent $str3"
+            "ACTION CLICK $str1 (channel=$str2) for pending intent $str3 at index $int1"
         })
     }
 
     fun logRemoteInputWasHandled(
-        entry: NotificationEntry?
+        entry: NotificationEntry?,
+        index: Int?
     ) {
         buffer.log(TAG, LogLevel.DEBUG, {
             str1 = entry?.key
+            int1 = index ?: Int.MIN_VALUE
         }, {
-            "  [Action click] Triggered remote input (for $str1))"
+            "  [Action click] Triggered remote input (for $str1) at index $int1"
         })
     }
 
     fun logStartingIntentWithDefaultHandler(
         entry: NotificationEntry?,
-        pendingIntent: PendingIntent
+        pendingIntent: PendingIntent,
+        index: Int?
     ) {
         buffer.log(TAG, LogLevel.DEBUG, {
             str1 = entry?.key
-            str2 = pendingIntent.intent.toString()
+            str2 = pendingIntent.toString()
+            int1 = index ?: Int.MIN_VALUE
         }, {
-            "  [Action click] Launching intent $str2 via default handler (for $str1)"
+            "  [Action click] Launching intent $str2 via default handler (for $str1 at index $int1)"
         })
     }
 
     fun logWaitingToCloseKeyguard(
-        pendingIntent: PendingIntent
+        pendingIntent: PendingIntent,
+        index: Int?
     ) {
         buffer.log(TAG, LogLevel.DEBUG, {
-            str1 = pendingIntent.intent.toString()
+            str1 = pendingIntent.toString()
+            int1 = index ?: Int.MIN_VALUE
         }, {
-            "  [Action click] Intent $str1 launches an activity, dismissing keyguard first..."
+            "  [Action click] Intent $str1 at index $int1 launches an activity, dismissing " +
+                    "keyguard first..."
         })
     }
 
     fun logKeyguardGone(
-        pendingIntent: PendingIntent
+        pendingIntent: PendingIntent,
+        index: Int?
     ) {
         buffer.log(TAG, LogLevel.DEBUG, {
-            str1 = pendingIntent.intent.toString()
+            str1 = pendingIntent.toString()
+            int1 = index ?: Int.MIN_VALUE
         }, {
-            "  [Action click] Keyguard dismissed, calling default handler for intent $str1"
+            "  [Action click] Keyguard dismissed, calling default handler for intent $str1 at " +
+                    "index $int1"
         })
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationClickNotifier.kt b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationClickNotifier.kt
index abf81c5..692a997 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationClickNotifier.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationClickNotifier.kt
@@ -2,10 +2,12 @@
 
 import android.app.Notification
 import android.os.RemoteException
+import android.util.Log
 import com.android.internal.statusbar.IStatusBarService
 import com.android.internal.statusbar.NotificationVisibility
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.dagger.qualifiers.Main
+import com.android.systemui.dagger.qualifiers.UiBackground
 import com.android.systemui.util.Assert
 import java.util.concurrent.Executor
 import javax.inject.Inject
@@ -21,7 +23,8 @@
 @SysUISingleton
 public class NotificationClickNotifier @Inject constructor(
     val barService: IStatusBarService,
-    @Main val mainExecutor: Executor
+    @Main val mainExecutor: Executor,
+    @UiBackground val backgroundExecutor: Executor
 ) {
     val listeners = mutableListOf<NotificationInteractionListener>()
 
@@ -48,13 +51,14 @@
         visibility: NotificationVisibility,
         generatedByAssistant: Boolean
     ) {
-        try {
-            barService.onNotificationActionClick(
-                    key, actionIndex, action, visibility, generatedByAssistant)
-        } catch (e: RemoteException) {
-            // nothing
+        backgroundExecutor.execute {
+            try {
+                barService.onNotificationActionClick(
+                        key, actionIndex, action, visibility, generatedByAssistant)
+            } catch (e: RemoteException) {
+                // nothing
+            }
         }
-
         mainExecutor.execute {
             notifyListenersAboutInteraction(key)
         }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java
index da84afe..8089fd9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java
@@ -119,11 +119,14 @@
             mPowerInteractor.wakeUpIfDozing(
                     "NOTIFICATION_CLICK", PowerManager.WAKE_REASON_GESTURE);
 
+            Integer actionIndex = (Integer)
+                    view.getTag(com.android.internal.R.id.notification_action_index_tag);
+
             final NotificationEntry entry = getNotificationForParent(view.getParent());
-            mLogger.logInitialClick(entry, pendingIntent);
+            mLogger.logInitialClick(entry, actionIndex, pendingIntent);
 
             if (handleRemoteInput(view, pendingIntent)) {
-                mLogger.logRemoteInputWasHandled(entry);
+                mLogger.logRemoteInputWasHandled(entry, actionIndex);
                 return true;
             }
 
@@ -141,9 +144,9 @@
             }
             Notification.Action action = getActionFromView(view, entry, pendingIntent);
             return mCallback.handleRemoteViewClick(view, pendingIntent,
-                    action == null ? false : action.isAuthenticationRequired(), () -> {
+                    action == null ? false : action.isAuthenticationRequired(), actionIndex, () -> {
                     Pair<Intent, ActivityOptions> options = response.getLaunchOptions(view);
-                    mLogger.logStartingIntentWithDefaultHandler(entry, pendingIntent);
+                    mLogger.logStartingIntentWithDefaultHandler(entry, pendingIntent, actionIndex);
                     boolean started = RemoteViews.startPendingIntent(view, pendingIntent, options);
                     if (started) releaseNotificationIfKeptForRemoteInputHistory(entry);
                     return started;
@@ -692,11 +695,13 @@
          * @param view
          * @param pendingIntent
          * @param appRequestedAuth
+         * @param actionIndex
          * @param defaultHandler
          * @return  true iff the click was handled
          */
         boolean handleRemoteViewClick(View view, PendingIntent pendingIntent,
-                boolean appRequestedAuth, ClickHandler defaultHandler);
+                boolean appRequestedAuth, @Nullable Integer actionIndex,
+                ClickHandler defaultHandler);
     }
 
     /**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java
index d6a14604..6dd24ea 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java
@@ -48,8 +48,10 @@
 import com.android.internal.jank.InteractionJankMonitor;
 import com.android.internal.jank.InteractionJankMonitor.Configuration;
 import com.android.internal.logging.UiEventLogger;
+import com.android.keyguard.KeyguardClockSwitch;
 import com.android.systemui.DejankUtils;
 import com.android.systemui.Dumpable;
+import com.android.systemui.R;
 import com.android.systemui.dagger.SysUISingleton;
 import com.android.systemui.dump.DumpManager;
 import com.android.systemui.plugins.statusbar.StatusBarStateController.StateListener;
@@ -420,6 +422,25 @@
         }
     }
 
+    /** Returns the id of the currently rendering clock */
+    public String getClockId() {
+        if (mView == null) {
+            return KeyguardClockSwitch.MISSING_CLOCK_ID;
+        }
+
+        View clockSwitch = mView.findViewById(R.id.keyguard_clock_container);
+        if (clockSwitch == null) {
+            Log.e(TAG, "Clock container was missing");
+            return KeyguardClockSwitch.MISSING_CLOCK_ID;
+        }
+        if (!(clockSwitch instanceof KeyguardClockSwitch)) {
+            Log.e(TAG, "Clock container was incorrect type: " + clockSwitch);
+            return KeyguardClockSwitch.MISSING_CLOCK_ID;
+        }
+
+        return ((KeyguardClockSwitch) clockSwitch).getClockId();
+    }
+
     private void beginInteractionJankMonitor() {
         final boolean shouldPost =
                 (mIsDozing && mDozeAmount == 0) || (!mIsDozing && mDozeAmount == 1);
@@ -429,6 +450,7 @@
                         Choreographer.CALLBACK_ANIMATION, this::beginInteractionJankMonitor, null);
             } else {
                 Configuration.Builder builder = Configuration.Builder.withView(getCujType(), mView)
+                        .setTag(getClockId())
                         .setDeferMonitorForAnimationStart(false);
                 mInteractionJankMonitor.begin(builder);
             }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/OWNERS b/packages/SystemUI/src/com/android/systemui/statusbar/notification/OWNERS
index ed80f33..5558ab1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/OWNERS
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/OWNERS
@@ -2,13 +2,17 @@
 
 # Bug component: 78010
 
-aaliomer@google.com
+aioana@google.com
 aroederer@google.com
+iyz@google.com
 jeffdq@google.com
 juliacr@google.com
 juliatuttle@google.com
+kurucz@google.com
+liuyining@google.com
 lynhan@google.com
-steell@google.com
+matiashe@google.com
+valiiftime@google.com
 yurilin@google.com
 
 per-file MediaNotificationProcessor.java = ethibodeau@google.com, asc@google.com
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewbinder/NotificationIconAreaControllerViewBinderWrapperImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewbinder/NotificationIconAreaControllerViewBinderWrapperImpl.kt
new file mode 100644
index 0000000..26dfe3e
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewbinder/NotificationIconAreaControllerViewBinderWrapperImpl.kt
@@ -0,0 +1,684 @@
+/*
+ * 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.icon.ui.viewbinder
+
+import android.content.Context
+import android.graphics.Color
+import android.graphics.Rect
+import android.os.Bundle
+import android.os.Trace
+import android.view.LayoutInflater
+import android.view.View
+import android.widget.FrameLayout
+import androidx.annotation.ColorInt
+import androidx.annotation.VisibleForTesting
+import androidx.collection.ArrayMap
+import com.android.app.animation.Interpolators
+import com.android.internal.statusbar.StatusBarIcon
+import com.android.internal.util.ContrastColorUtil
+import com.android.settingslib.Utils
+import com.android.systemui.R
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.demomode.DemoMode
+import com.android.systemui.demomode.DemoModeController
+import com.android.systemui.flags.FeatureFlags
+import com.android.systemui.flags.Flags
+import com.android.systemui.flags.ViewRefactorFlag
+import com.android.systemui.plugins.DarkIconDispatcher
+import com.android.systemui.plugins.statusbar.StatusBarStateController
+import com.android.systemui.statusbar.CrossFadeHelper
+import com.android.systemui.statusbar.NotificationListener
+import com.android.systemui.statusbar.NotificationMediaManager
+import com.android.systemui.statusbar.NotificationShelfController
+import com.android.systemui.statusbar.StatusBarIconView
+import com.android.systemui.statusbar.StatusBarState
+import com.android.systemui.statusbar.notification.NotificationUtils
+import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator
+import com.android.systemui.statusbar.notification.collection.ListEntry
+import com.android.systemui.statusbar.notification.collection.NotificationEntry
+import com.android.systemui.statusbar.notification.collection.provider.SectionStyleProvider
+import com.android.systemui.statusbar.notification.icon.ui.viewmodel.NotificationIconContainerAlwaysOnDisplayViewModel
+import com.android.systemui.statusbar.notification.icon.ui.viewmodel.NotificationIconContainerShelfViewModel
+import com.android.systemui.statusbar.notification.icon.ui.viewmodel.NotificationIconContainerStatusBarViewModel
+import com.android.systemui.statusbar.notification.shelf.ui.viewbinder.NotificationShelfViewBinderWrapperControllerImpl
+import com.android.systemui.statusbar.phone.DozeParameters
+import com.android.systemui.statusbar.phone.KeyguardBypassController
+import com.android.systemui.statusbar.phone.NotificationIconAreaController
+import com.android.systemui.statusbar.phone.NotificationIconContainer
+import com.android.systemui.statusbar.phone.ScreenOffAnimationController
+import com.android.systemui.statusbar.window.StatusBarWindowController
+import com.android.wm.shell.bubbles.Bubbles
+import java.util.Optional
+import java.util.function.Function
+import javax.inject.Inject
+import kotlinx.coroutines.DisposableHandle
+
+/**
+ * Controller class for [NotificationIconContainer]. This implementation serves as a temporary
+ * wrapper around [NotificationIconContainerViewBinder], so that external code can continue to
+ * depend on the [NotificationIconAreaController] interface. Once
+ * [LegacyNotificationIconAreaControllerImpl] is removed, this class can go away and the ViewBinder
+ * can be used directly.
+ */
+@SysUISingleton
+class NotificationIconAreaControllerViewBinderWrapperImpl
+@Inject
+constructor(
+    private val context: Context,
+    private val statusBarStateController: StatusBarStateController,
+    private val wakeUpCoordinator: NotificationWakeUpCoordinator,
+    private val bypassController: KeyguardBypassController,
+    private val mediaManager: NotificationMediaManager,
+    notificationListener: NotificationListener,
+    private val dozeParameters: DozeParameters,
+    private val sectionStyleProvider: SectionStyleProvider,
+    private val bubblesOptional: Optional<Bubbles>,
+    demoModeController: DemoModeController,
+    darkIconDispatcher: DarkIconDispatcher,
+    featureFlags: FeatureFlags,
+    private val statusBarWindowController: StatusBarWindowController,
+    private val screenOffAnimationController: ScreenOffAnimationController,
+    private val shelfIconsViewModel: NotificationIconContainerShelfViewModel,
+    private val statusBarIconsViewModel: NotificationIconContainerStatusBarViewModel,
+    private val aodIconsViewModel: NotificationIconContainerAlwaysOnDisplayViewModel,
+) :
+    NotificationIconAreaController,
+    DarkIconDispatcher.DarkReceiver,
+    StatusBarStateController.StateListener,
+    NotificationWakeUpCoordinator.WakeUpListener,
+    DemoMode {
+
+    private val contrastColorUtil: ContrastColorUtil = ContrastColorUtil.getInstance(context)
+    private val updateStatusBarIcons = Runnable { updateStatusBarIcons() }
+    private val shelfRefactor = ViewRefactorFlag(featureFlags, Flags.NOTIFICATION_SHELF_REFACTOR)
+    private val tintAreas = ArrayList<Rect>()
+
+    private var iconSize = 0
+    private var iconHPadding = 0
+    private var iconTint = Color.WHITE
+    private var notificationEntries = listOf<ListEntry>()
+    private var notificationIconArea: View? = null
+    private var notificationIcons: NotificationIconContainer? = null
+    private var shelfIcons: NotificationIconContainer? = null
+    private var aodIcons: NotificationIconContainer? = null
+    private var aodBindJob: DisposableHandle? = null
+    private var aodIconAppearTranslation = 0
+    private var animationsEnabled = false
+    private var aodIconTint = 0
+    private var aodIconsVisible = false
+    private var showLowPriority = true
+
+    @VisibleForTesting
+    val settingsListener: NotificationListener.NotificationSettingsListener =
+        object : NotificationListener.NotificationSettingsListener {
+            override fun onStatusBarIconsBehaviorChanged(hideSilentStatusIcons: Boolean) {
+                showLowPriority = !hideSilentStatusIcons
+                updateStatusBarIcons()
+            }
+        }
+
+    init {
+        statusBarStateController.addCallback(this)
+        wakeUpCoordinator.addListener(this)
+        demoModeController.addCallback(this)
+        notificationListener.addNotificationSettingsListener(settingsListener)
+        initializeNotificationAreaViews(context)
+        reloadAodColor()
+        darkIconDispatcher.addDarkReceiver(this)
+    }
+
+    @VisibleForTesting
+    fun shouldShowLowPriorityIcons(): Boolean {
+        return showLowPriority
+    }
+
+    /** Called by the Keyguard*ViewController whose view contains the aod icons. */
+    override fun setupAodIcons(aodIcons: NotificationIconContainer) {
+        val changed = this.aodIcons != null && aodIcons !== this.aodIcons
+        if (changed) {
+            this.aodIcons!!.setAnimationsEnabled(false)
+            this.aodIcons!!.removeAllViews()
+            aodBindJob?.dispose()
+        }
+        this.aodIcons = aodIcons
+        this.aodIcons!!.setOnLockScreen(true)
+        aodBindJob = NotificationIconContainerViewBinder.bind(aodIcons, aodIconsViewModel)
+        updateAodIconsVisibility(animate = false, forceUpdate = changed)
+        updateAnimations()
+        if (changed) {
+            updateAodNotificationIcons()
+        }
+        updateIconLayoutParams(context)
+    }
+
+    override fun setupShelf(notificationShelfController: NotificationShelfController) =
+        NotificationShelfViewBinderWrapperControllerImpl.unsupported
+
+    override fun setShelfIcons(icons: NotificationIconContainer) {
+        if (shelfRefactor.expectEnabled()) {
+            NotificationIconContainerViewBinder.bind(icons, shelfIconsViewModel)
+            shelfIcons = icons
+        }
+    }
+
+    override fun onDensityOrFontScaleChanged(context: Context) {
+        updateIconLayoutParams(context)
+    }
+
+    /** Returns the view that represents the notification area. */
+    override fun getNotificationInnerAreaView(): View? {
+        return notificationIconArea
+    }
+
+    /**
+     * See [com.android.systemui.statusbar.policy.DarkIconDispatcher.setIconsDarkArea]. Sets the
+     * color that should be used to tint any icons in the notification area.
+     *
+     * @param tintAreas the areas in which to tint the icons, specified in screen coordinates
+     * @param darkIntensity
+     */
+    override fun onDarkChanged(tintAreas: ArrayList<Rect>, darkIntensity: Float, iconTint: Int) {
+        this.tintAreas.clear()
+        this.tintAreas.addAll(tintAreas)
+        if (DarkIconDispatcher.isInAreas(tintAreas, notificationIconArea)) {
+            this.iconTint = iconTint
+        }
+        applyNotificationIconsTint()
+    }
+
+    /** Updates the notifications with the given list of notifications to display. */
+    override fun updateNotificationIcons(entries: List<ListEntry>) {
+        notificationEntries = entries
+        updateNotificationIcons()
+    }
+
+    private fun updateStatusBarIcons() {
+        updateIconsForLayout(
+            { entry: NotificationEntry -> entry.icons.statusBarIcon },
+            notificationIcons,
+            showAmbient = false /* showAmbient */,
+            showLowPriority = showLowPriority,
+            hideDismissed = true /* hideDismissed */,
+            hideRepliedMessages = true /* hideRepliedMessages */,
+            hideCurrentMedia = false /* hideCurrentMedia */,
+            hidePulsing = false /* hidePulsing */
+        )
+    }
+
+    override fun updateAodNotificationIcons() {
+        if (aodIcons == null) {
+            return
+        }
+        updateIconsForLayout(
+            { entry: NotificationEntry -> entry.icons.aodIcon },
+            aodIcons,
+            showAmbient = false /* showAmbient */,
+            showLowPriority = true /* showLowPriority */,
+            hideDismissed = true /* hideDismissed */,
+            hideRepliedMessages = true /* hideRepliedMessages */,
+            hideCurrentMedia = true /* hideCurrentMedia */,
+            hidePulsing = bypassController.bypassEnabled /* hidePulsing */
+        )
+    }
+
+    override fun showIconIsolated(icon: StatusBarIconView?, animated: Boolean) {
+        notificationIcons!!.showIconIsolated(icon, animated)
+    }
+
+    override fun setIsolatedIconLocation(iconDrawingRect: Rect, requireStateUpdate: Boolean) {
+        notificationIcons!!.setIsolatedIconLocation(iconDrawingRect, requireStateUpdate)
+    }
+
+    override fun onDozingChanged(isDozing: Boolean) {
+        if (aodIcons == null) {
+            return
+        }
+        val animate = (dozeParameters.alwaysOn && !dozeParameters.displayNeedsBlanking)
+        aodIcons!!.setDozing(isDozing, animate, 0)
+    }
+
+    override fun setAnimationsEnabled(enabled: Boolean) {
+        animationsEnabled = enabled
+        updateAnimations()
+    }
+
+    override fun onStateChanged(newState: Int) {
+        updateAodIconsVisibility(animate = false, forceUpdate = false)
+        updateAnimations()
+    }
+
+    override fun onThemeChanged() {
+        reloadAodColor()
+        updateAodIconColors()
+    }
+
+    override fun getHeight(): Int {
+        return if (aodIcons == null) 0 else aodIcons!!.height
+    }
+
+    @VisibleForTesting
+    fun appearAodIcons() {
+        if (aodIcons == null) {
+            return
+        }
+        if (screenOffAnimationController.shouldAnimateAodIcons()) {
+            aodIcons!!.translationY = -aodIconAppearTranslation.toFloat()
+            aodIcons!!.alpha = 0f
+            animateInAodIconTranslation()
+            aodIcons!!
+                .animate()
+                .alpha(1f)
+                .setInterpolator(Interpolators.LINEAR)
+                .setDuration(AOD_ICONS_APPEAR_DURATION)
+                .start()
+        } else {
+            aodIcons!!.alpha = 1.0f
+            aodIcons!!.translationY = 0f
+        }
+    }
+
+    override fun onFullyHiddenChanged(isFullyHidden: Boolean) {
+        var animate = true
+        if (!bypassController.bypassEnabled) {
+            animate = dozeParameters.alwaysOn && !dozeParameters.displayNeedsBlanking
+            // We only want the appear animations to happen when the notifications get fully hidden,
+            // since otherwise the unhide animation overlaps
+            animate = animate and isFullyHidden
+        }
+        updateAodIconsVisibility(animate, false /* force */)
+        updateAodNotificationIcons()
+        updateAodIconColors()
+    }
+
+    override fun onPulseExpansionChanged(expandingChanged: Boolean) {
+        if (expandingChanged) {
+            updateAodIconsVisibility(animate = true, forceUpdate = false)
+        }
+    }
+
+    override fun demoCommands(): List<String> {
+        val commands = ArrayList<String>()
+        commands.add(DemoMode.COMMAND_NOTIFICATIONS)
+        return commands
+    }
+
+    override fun dispatchDemoCommand(command: String, args: Bundle) {
+        if (notificationIconArea != null) {
+            val visible = args.getString("visible")
+            val vis = if ("false" == visible) View.INVISIBLE else View.VISIBLE
+            notificationIconArea?.visibility = vis
+        }
+    }
+
+    override fun onDemoModeFinished() {
+        if (notificationIconArea != null) {
+            notificationIconArea?.visibility = View.VISIBLE
+        }
+    }
+
+    private fun inflateIconArea(inflater: LayoutInflater): View {
+        return inflater.inflate(R.layout.notification_icon_area, null)
+    }
+
+    /** Initializes the views that will represent the notification area. */
+    private fun initializeNotificationAreaViews(context: Context) {
+        reloadDimens(context)
+        val layoutInflater = LayoutInflater.from(context)
+        notificationIconArea = inflateIconArea(layoutInflater)
+        notificationIcons = notificationIconArea?.findViewById(R.id.notificationIcons)
+        NotificationIconContainerViewBinder.bind(notificationIcons!!, statusBarIconsViewModel)
+    }
+
+    private fun updateIconLayoutParams(context: Context) {
+        reloadDimens(context)
+        val params = generateIconLayoutParams()
+        for (i in 0 until notificationIcons!!.childCount) {
+            val child = notificationIcons!!.getChildAt(i)
+            child.layoutParams = params
+        }
+        if (shelfIcons != null) {
+            for (i in 0 until shelfIcons!!.childCount) {
+                val child = shelfIcons!!.getChildAt(i)
+                child.layoutParams = params
+            }
+        }
+        if (aodIcons != null) {
+            for (i in 0 until aodIcons!!.childCount) {
+                val child = aodIcons!!.getChildAt(i)
+                child.layoutParams = params
+            }
+        }
+    }
+
+    private fun generateIconLayoutParams(): FrameLayout.LayoutParams {
+        return FrameLayout.LayoutParams(
+            iconSize + 2 * iconHPadding,
+            statusBarWindowController.statusBarHeight
+        )
+    }
+
+    private fun reloadDimens(context: Context) {
+        val res = context.resources
+        iconSize = res.getDimensionPixelSize(com.android.internal.R.dimen.status_bar_icon_size_sp)
+        iconHPadding = res.getDimensionPixelSize(R.dimen.status_bar_icon_horizontal_margin)
+        aodIconAppearTranslation = res.getDimensionPixelSize(R.dimen.shelf_appear_translation)
+    }
+
+    private fun shouldShowNotificationIcon(
+        entry: NotificationEntry,
+        showAmbient: Boolean,
+        showLowPriority: Boolean,
+        hideDismissed: Boolean,
+        hideRepliedMessages: Boolean,
+        hideCurrentMedia: Boolean,
+        hidePulsing: Boolean
+    ): Boolean {
+        if (!showAmbient && sectionStyleProvider.isMinimized(entry)) {
+            return false
+        }
+        if (hideCurrentMedia && entry.key == mediaManager.mediaNotificationKey) {
+            return false
+        }
+        if (!showLowPriority && sectionStyleProvider.isSilent(entry)) {
+            return false
+        }
+        if (entry.isRowDismissed && hideDismissed) {
+            return false
+        }
+        if (hideRepliedMessages && entry.isLastMessageFromReply) {
+            return false
+        }
+        // showAmbient == show in shade but not shelf
+        if (!showAmbient && entry.shouldSuppressStatusBar()) {
+            return false
+        }
+        if (
+            hidePulsing &&
+                entry.showingPulsing() &&
+                (!wakeUpCoordinator.notificationsFullyHidden || !entry.isPulseSuppressed)
+        ) {
+            return false
+        }
+        return if (bubblesOptional.isPresent && bubblesOptional.get().isBubbleExpanded(entry.key)) {
+            false
+        } else true
+    }
+
+    private fun updateNotificationIcons() {
+        Trace.beginSection("NotificationIconAreaController.updateNotificationIcons")
+        updateStatusBarIcons()
+        updateShelfIcons()
+        updateAodNotificationIcons()
+        applyNotificationIconsTint()
+        Trace.endSection()
+    }
+
+    private fun updateShelfIcons() {
+        if (shelfIcons == null) {
+            return
+        }
+        updateIconsForLayout(
+            { entry: NotificationEntry -> entry.icons.shelfIcon },
+            shelfIcons,
+            showAmbient = true,
+            showLowPriority = true,
+            hideDismissed = false,
+            hideRepliedMessages = false,
+            hideCurrentMedia = false,
+            hidePulsing = false
+        )
+    }
+
+    /**
+     * Updates the notification icons for a host layout. This will ensure that the notification host
+     * layout will have the same icons like the ones in here.
+     *
+     * @param function A function to look up an icon view based on an entry
+     * @param hostLayout which layout should be updated
+     * @param showAmbient should ambient notification icons be shown
+     * @param showLowPriority should icons from silent notifications be shown
+     * @param hideDismissed should dismissed icons be hidden
+     * @param hideRepliedMessages should messages that have been replied to be hidden
+     * @param hidePulsing should pulsing notifications be hidden
+     */
+    private fun updateIconsForLayout(
+        function: Function<NotificationEntry, StatusBarIconView?>,
+        hostLayout: NotificationIconContainer?,
+        showAmbient: Boolean,
+        showLowPriority: Boolean,
+        hideDismissed: Boolean,
+        hideRepliedMessages: Boolean,
+        hideCurrentMedia: Boolean,
+        hidePulsing: Boolean,
+    ) {
+        val toShow = ArrayList<StatusBarIconView>(notificationEntries.size)
+        // Filter out ambient notifications and notification children.
+        for (i in notificationEntries.indices) {
+            val entry = notificationEntries[i].representativeEntry
+            if (entry != null && entry.row != null) {
+                if (
+                    shouldShowNotificationIcon(
+                        entry,
+                        showAmbient,
+                        showLowPriority,
+                        hideDismissed,
+                        hideRepliedMessages,
+                        hideCurrentMedia,
+                        hidePulsing
+                    )
+                ) {
+                    val iconView = function.apply(entry)
+                    if (iconView != null) {
+                        toShow.add(iconView)
+                    }
+                }
+            }
+        }
+
+        // In case we are changing the suppression of a group, the replacement shouldn't flicker
+        // and it should just be replaced instead. We therefore look for notifications that were
+        // just replaced by the child or vice-versa to suppress this.
+        val replacingIcons = ArrayMap<String, ArrayList<StatusBarIcon>>()
+        val toRemove = ArrayList<View>()
+        for (i in 0 until hostLayout!!.childCount) {
+            val child = hostLayout.getChildAt(i) as? StatusBarIconView ?: continue
+            if (!toShow.contains(child)) {
+                var iconWasReplaced = false
+                val removedGroupKey = child.notification.groupKey
+                for (j in toShow.indices) {
+                    val candidate = toShow[j]
+                    if (
+                        candidate.sourceIcon.sameAs(child.sourceIcon) &&
+                            candidate.notification.groupKey == removedGroupKey
+                    ) {
+                        if (!iconWasReplaced) {
+                            iconWasReplaced = true
+                        } else {
+                            iconWasReplaced = false
+                            break
+                        }
+                    }
+                }
+                if (iconWasReplaced) {
+                    var statusBarIcons = replacingIcons[removedGroupKey]
+                    if (statusBarIcons == null) {
+                        statusBarIcons = ArrayList()
+                        replacingIcons[removedGroupKey] = statusBarIcons
+                    }
+                    statusBarIcons.add(child.statusBarIcon)
+                }
+                toRemove.add(child)
+            }
+        }
+        // removing all duplicates
+        val duplicates = ArrayList<String?>()
+        for (key in replacingIcons.keys) {
+            val statusBarIcons = replacingIcons[key]!!
+            if (statusBarIcons.size != 1) {
+                duplicates.add(key)
+            }
+        }
+        replacingIcons.removeAll(duplicates)
+        hostLayout.setReplacingIcons(replacingIcons)
+        val toRemoveCount = toRemove.size
+        for (i in 0 until toRemoveCount) {
+            hostLayout.removeView(toRemove[i])
+        }
+        val params = generateIconLayoutParams()
+        for (i in toShow.indices) {
+            val v = toShow[i]
+            // The view might still be transiently added if it was just removed and added again
+            hostLayout.removeTransientView(v)
+            if (v.parent == null) {
+                if (hideDismissed) {
+                    v.setOnDismissListener(updateStatusBarIcons)
+                }
+                hostLayout.addView(v, i, params)
+            }
+        }
+        hostLayout.setChangingViewPositions(true)
+        // Re-sort notification icons
+        val childCount = hostLayout.childCount
+        for (i in 0 until childCount) {
+            val actual = hostLayout.getChildAt(i)
+            val expected = toShow[i]
+            if (actual === expected) {
+                continue
+            }
+            hostLayout.removeView(expected)
+            hostLayout.addView(expected, i)
+        }
+        hostLayout.setChangingViewPositions(false)
+        hostLayout.setReplacingIcons(null)
+    }
+
+    /** Applies [.mIconTint] to the notification icons. */
+    private fun applyNotificationIconsTint() {
+        for (i in 0 until notificationIcons!!.childCount) {
+            val iv = notificationIcons!!.getChildAt(i) as StatusBarIconView
+            if (iv.width != 0) {
+                updateTintForIcon(iv, iconTint)
+            } else {
+                iv.executeOnLayout { updateTintForIcon(iv, iconTint) }
+            }
+        }
+        updateAodIconColors()
+    }
+
+    private fun updateTintForIcon(v: StatusBarIconView, tint: Int) {
+        val isPreL = java.lang.Boolean.TRUE == v.getTag(R.id.icon_is_pre_L)
+        var color = StatusBarIconView.NO_COLOR
+        val colorize = !isPreL || NotificationUtils.isGrayscale(v, contrastColorUtil)
+        if (colorize) {
+            color = DarkIconDispatcher.getTint(tintAreas, v, tint)
+        }
+        v.staticDrawableColor = color
+        v.setDecorColor(tint)
+    }
+
+    private fun updateAnimations() {
+        val inShade = statusBarStateController.state == StatusBarState.SHADE
+        if (aodIcons != null) {
+            aodIcons!!.setAnimationsEnabled(animationsEnabled && !inShade)
+        }
+        notificationIcons!!.setAnimationsEnabled(animationsEnabled && inShade)
+    }
+
+    private fun animateInAodIconTranslation() {
+        aodIcons!!
+            .animate()
+            .setInterpolator(Interpolators.DECELERATE_QUINT)
+            .translationY(0f)
+            .setDuration(AOD_ICONS_APPEAR_DURATION)
+            .start()
+    }
+
+    private fun reloadAodColor() {
+        aodIconTint =
+            Utils.getColorAttrDefaultColor(
+                context,
+                R.attr.wallpaperTextColor,
+                DEFAULT_AOD_ICON_COLOR
+            )
+    }
+
+    private fun updateAodIconColors() {
+        if (aodIcons != null) {
+            for (i in 0 until aodIcons!!.childCount) {
+                val iv = aodIcons!!.getChildAt(i) as StatusBarIconView
+                if (iv.width != 0) {
+                    updateTintForIcon(iv, aodIconTint)
+                } else {
+                    iv.executeOnLayout { updateTintForIcon(iv, aodIconTint) }
+                }
+            }
+        }
+    }
+
+    private fun updateAodIconsVisibility(animate: Boolean, forceUpdate: Boolean) {
+        if (aodIcons == null) {
+            return
+        }
+        var visible = (bypassController.bypassEnabled || wakeUpCoordinator.notificationsFullyHidden)
+
+        // Hide the AOD icons if we're not in the KEYGUARD state unless the screen off animation is
+        // playing, in which case we want them to be visible since we're animating in the AOD UI and
+        // will be switching to KEYGUARD shortly.
+        if (
+            statusBarStateController.state != StatusBarState.KEYGUARD &&
+                !screenOffAnimationController.shouldShowAodIconsWhenShade()
+        ) {
+            visible = false
+        }
+        if (visible && wakeUpCoordinator.isPulseExpanding() && !bypassController.bypassEnabled) {
+            visible = false
+        }
+        if (aodIconsVisible != visible || forceUpdate) {
+            aodIconsVisible = visible
+            aodIcons!!.animate().cancel()
+            if (animate) {
+                val wasFullyInvisible = aodIcons!!.visibility != View.VISIBLE
+                if (aodIconsVisible) {
+                    if (wasFullyInvisible) {
+                        // No fading here, let's just appear the icons instead!
+                        aodIcons!!.visibility = View.VISIBLE
+                        aodIcons!!.alpha = 1.0f
+                        appearAodIcons()
+                    } else {
+                        // Let's make sure the icon are translated to 0, since we cancelled it above
+                        animateInAodIconTranslation()
+                        // We were fading out, let's fade in instead
+                        CrossFadeHelper.fadeIn(aodIcons)
+                    }
+                } else {
+                    // Let's make sure the icon are translated to 0, since we cancelled it above
+                    animateInAodIconTranslation()
+                    CrossFadeHelper.fadeOut(aodIcons)
+                }
+            } else {
+                aodIcons!!.alpha = 1.0f
+                aodIcons!!.translationY = 0f
+                aodIcons!!.visibility = if (visible) View.VISIBLE else View.INVISIBLE
+            }
+        }
+    }
+
+    companion object {
+        private const val AOD_ICONS_APPEAR_DURATION: Long = 200
+
+        @ColorInt private val DEFAULT_AOD_ICON_COLOR = -0x1
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewbinder/NotificationIconContainerViewBinder.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewbinder/NotificationIconContainerViewBinder.kt
new file mode 100644
index 0000000..8293bb3
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewbinder/NotificationIconContainerViewBinder.kt
@@ -0,0 +1,33 @@
+/*
+ * 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.icon.ui.viewbinder
+
+import androidx.lifecycle.Lifecycle
+import androidx.lifecycle.repeatOnLifecycle
+import com.android.systemui.lifecycle.repeatWhenAttached
+import com.android.systemui.statusbar.notification.icon.ui.viewmodel.NotificationIconContainerViewModel
+import com.android.systemui.statusbar.phone.NotificationIconContainer
+import kotlinx.coroutines.DisposableHandle
+
+/** Binds a [NotificationIconContainer] to its [view model][NotificationIconContainerViewModel]. */
+object NotificationIconContainerViewBinder {
+    fun bind(
+        view: NotificationIconContainer,
+        viewModel: NotificationIconContainerViewModel,
+    ): DisposableHandle {
+        return view.repeatWhenAttached { repeatOnLifecycle(Lifecycle.State.CREATED) {} }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerAlwaysOnDisplayViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerAlwaysOnDisplayViewModel.kt
new file mode 100644
index 0000000..f68b0ef
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerAlwaysOnDisplayViewModel.kt
@@ -0,0 +1,22 @@
+/*
+ * 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.icon.ui.viewmodel
+
+import javax.inject.Inject
+
+/** View-model for the row of notification icons displayed on the always-on display. */
+class NotificationIconContainerAlwaysOnDisplayViewModel @Inject constructor() :
+    NotificationIconContainerViewModel
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerShelfViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerShelfViewModel.kt
new file mode 100644
index 0000000..933c76f
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerShelfViewModel.kt
@@ -0,0 +1,22 @@
+/*
+ * 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.icon.ui.viewmodel
+
+import javax.inject.Inject
+
+/** View-model for the overflow row of notification icons displayed in the notification shade. */
+class NotificationIconContainerShelfViewModel @Inject constructor() :
+    NotificationIconContainerViewModel
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerStatusBarViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerStatusBarViewModel.kt
new file mode 100644
index 0000000..2217646
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerStatusBarViewModel.kt
@@ -0,0 +1,22 @@
+/*
+ * 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.icon.ui.viewmodel
+
+import javax.inject.Inject
+
+/** View-model for the row of notification icons displayed in the status bar, */
+class NotificationIconContainerStatusBarViewModel @Inject constructor() :
+    NotificationIconContainerViewModel
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerViewModel.kt
new file mode 100644
index 0000000..892b2be
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerViewModel.kt
@@ -0,0 +1,22 @@
+/*
+ * 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.icon.ui.viewmodel
+
+/**
+ * View-model for the row of notification icons displayed in the NotificationShelf, StatusBar, and
+ * AOD.
+ */
+interface NotificationIconContainerViewModel
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/shelf/ui/viewbinder/NotificationShelfViewBinder.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/shelf/ui/viewbinder/NotificationShelfViewBinder.kt
index 22a87a7..b92c51f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/shelf/ui/viewbinder/NotificationShelfViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/shelf/ui/viewbinder/NotificationShelfViewBinder.kt
@@ -64,8 +64,10 @@
 
     override fun setOnClickListener(listener: View.OnClickListener) = unsupported
 
-    private val unsupported: Nothing
-        get() = error("Code path not supported when NOTIFICATION_SHELF_REFACTOR is disabled")
+    companion object {
+        val unsupported: Nothing
+            get() = error("Code path not supported when NOTIFICATION_SHELF_REFACTOR is disabled")
+    }
 }
 
 /** Binds a [NotificationShelf] to its [view model][NotificationShelfViewModel]. */
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
index 4668aa4..6db8df9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
@@ -28,7 +28,6 @@
 import static com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout.ROWS_GENTLE;
 import static com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout.ROWS_HIGH_PRIORITY;
 import static com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout.SelectedRows;
-import static com.android.systemui.statusbar.phone.NotificationIconAreaController.HIGH_PRIORITY;
 import static com.android.systemui.util.kotlin.JavaAdapterKt.collectFlow;
 
 import android.content.res.Configuration;
@@ -150,6 +149,7 @@
 public class NotificationStackScrollLayoutController {
     private static final String TAG = "StackScrollerController";
     private static final boolean DEBUG = Compile.IS_DEBUG && Log.isLoggable(TAG, Log.DEBUG);
+    private static final String HIGH_PRIORITY = "high_priority";
 
     private final boolean mAllowLongPress;
     private final NotificationGutsManager mNotificationGutsManager;
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 5c28be3..af09bf2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfaces.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfaces.java
@@ -25,7 +25,6 @@
 import android.content.pm.PackageManager;
 import android.os.Bundle;
 import android.os.UserHandle;
-import android.view.KeyEvent;
 import android.view.MotionEvent;
 import android.view.RemoteAnimationAdapter;
 import android.view.View;
@@ -276,19 +275,11 @@
 
     void userActivity();
 
-    boolean interceptMediaKey(KeyEvent event);
-
-    boolean dispatchKeyEventPreIme(KeyEvent event);
-
-    boolean onMenuPressed();
-
     void endAffordanceLaunch();
 
     /** Should the keyguard be hidden immediately in response to a back press/gesture. */
     boolean shouldKeyguardHideImmediately();
 
-    boolean onSpacePressed();
-
     void showBouncerWithDimissAndCancelIfKeyguard(OnDismissAction performAction,
             Runnable cancelAction);
 
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 8ffd43a..ccb87bf 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
@@ -89,7 +89,6 @@
 import android.view.Display;
 import android.view.IRemoteAnimationRunner;
 import android.view.IWindowManager;
-import android.view.KeyEvent;
 import android.view.MotionEvent;
 import android.view.ThreadedRenderer;
 import android.view.View;
@@ -2636,44 +2635,6 @@
     }
 
     @Override
-    public boolean interceptMediaKey(KeyEvent event) {
-        return mState == StatusBarState.KEYGUARD
-                && mStatusBarKeyguardViewManager.interceptMediaKey(event);
-    }
-
-    /**
-     * While IME is active and a BACK event is detected, check with
-     * {@link StatusBarKeyguardViewManager#dispatchBackKeyEventPreIme()} to see if the event
-     * should be handled before routing to IME, in order to prevent the user having to hit back
-     * twice to exit bouncer.
-     */
-    @Override
-    public boolean dispatchKeyEventPreIme(KeyEvent event) {
-        switch (event.getKeyCode()) {
-            case KeyEvent.KEYCODE_BACK:
-                if (mState == StatusBarState.KEYGUARD
-                        && mStatusBarKeyguardViewManager.dispatchBackKeyEventPreIme()) {
-                    return mBackActionInteractor.onBackRequested();
-                }
-        }
-        return false;
-    }
-
-    protected boolean shouldUnlockOnMenuPressed() {
-        return mDeviceInteractive && mState != StatusBarState.SHADE
-            && mStatusBarKeyguardViewManager.shouldDismissOnMenuPressed();
-    }
-
-    @Override
-    public boolean onMenuPressed() {
-        if (shouldUnlockOnMenuPressed()) {
-            mShadeController.animateCollapseShadeForced();
-            return true;
-        }
-        return false;
-    }
-
-    @Override
     public void endAffordanceLaunch() {
         releaseGestureWakeLock();
         mCameraLauncherLazy.get().setLaunchingAffordance(false);
@@ -2692,15 +2653,6 @@
         return (isScrimmedBouncer || isBouncerOverDream);
     }
 
-    @Override
-    public boolean onSpacePressed() {
-        if (mDeviceInteractive && mState != StatusBarState.SHADE) {
-            mShadeController.animateCollapseShadeForced();
-            return true;
-        }
-        return false;
-    }
-
     private void showBouncerOrLockScreenIfKeyguard() {
         // If the keyguard is animating away, we aren't really the keyguard anymore and should not
         // show the bouncer/lockscreen.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LegacyNotificationIconAreaControllerImpl.java
similarity index 96%
rename from packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
rename to packages/SystemUI/src/com/android/systemui/statusbar/phone/LegacyNotificationIconAreaControllerImpl.java
index 0bf0f4b..d22ed38 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LegacyNotificationIconAreaControllerImpl.java
@@ -1,3 +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 com.android.systemui.statusbar.phone;
 
 import android.content.Context;
@@ -43,6 +58,8 @@
 import com.android.systemui.statusbar.window.StatusBarWindowController;
 import com.android.wm.shell.bubbles.Bubbles;
 
+import org.jetbrains.annotations.NotNull;
+
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Optional;
@@ -55,13 +72,13 @@
  * normally reserved for notifications.
  */
 @SysUISingleton
-public class NotificationIconAreaController implements
+public class LegacyNotificationIconAreaControllerImpl implements
+        NotificationIconAreaController,
         DarkReceiver,
         StatusBarStateController.StateListener,
         NotificationWakeUpCoordinator.WakeUpListener,
         DemoMode {
 
-    public static final String HIGH_PRIORITY = "high_priority";
     private static final long AOD_ICONS_APPEAR_DURATION = 200;
     @ColorInt
     private static final int DEFAULT_AOD_ICON_COLOR = 0xffffffff;
@@ -110,7 +127,7 @@
             };
 
     @Inject
-    public NotificationIconAreaController(
+    public LegacyNotificationIconAreaControllerImpl(
             Context context,
             StatusBarStateController statusBarStateController,
             NotificationWakeUpCoordinator wakeUpCoordinator,
@@ -192,7 +209,7 @@
         }
     }
 
-    public void onDensityOrFontScaleChanged(Context context) {
+    public void onDensityOrFontScaleChanged(@NotNull Context context) {
         updateIconLayoutParams(context);
     }
 
@@ -493,7 +510,7 @@
         mNotificationIcons.showIconIsolated(icon, animated);
     }
 
-    public void setIsolatedIconLocation(Rect iconDrawingRect, boolean requireStateUpdate) {
+    public void setIsolatedIconLocation(@NotNull Rect iconDrawingRect, boolean requireStateUpdate) {
         mNotificationIcons.setIsolatedIconLocation(iconDrawingRect, requireStateUpdate);
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.kt
new file mode 100644
index 0000000..0079f7c
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.kt
@@ -0,0 +1,47 @@
+/*
+ * 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
+
+import android.content.Context
+import android.graphics.Rect
+import android.view.View
+import com.android.systemui.statusbar.NotificationShelfController
+import com.android.systemui.statusbar.StatusBarIconView
+import com.android.systemui.statusbar.notification.collection.ListEntry
+
+/**
+ * A controller for the space in the status bar to the left of the system icons. This area is
+ * normally reserved for notifications.
+ */
+interface NotificationIconAreaController {
+    /** Called by the Keyguard*ViewController whose view contains the aod icons. */
+    fun setupAodIcons(aodIcons: NotificationIconContainer)
+    fun setupShelf(notificationShelfController: NotificationShelfController)
+    fun setShelfIcons(icons: NotificationIconContainer)
+    fun onDensityOrFontScaleChanged(context: Context)
+
+    /** Returns the view that represents the notification area. */
+    fun getNotificationInnerAreaView(): View?
+
+    /** Updates the notifications with the given list of notifications to display. */
+    fun updateNotificationIcons(entries: List<@JvmSuppressWildcards ListEntry>)
+    fun updateAodNotificationIcons()
+    fun showIconIsolated(icon: StatusBarIconView?, animated: Boolean)
+    fun setIsolatedIconLocation(iconDrawingRect: Rect, requireStateUpdate: Boolean)
+    fun setAnimationsEnabled(enabled: Boolean)
+    fun onThemeChanged()
+    fun getHeight(): Int
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaControllerModule.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaControllerModule.kt
new file mode 100644
index 0000000..d1ddd51
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaControllerModule.kt
@@ -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 com.android.systemui.statusbar.phone
+
+import com.android.systemui.flags.FeatureFlags
+import com.android.systemui.flags.Flags
+import com.android.systemui.statusbar.notification.icon.ui.viewbinder.NotificationIconAreaControllerViewBinderWrapperImpl
+import dagger.Module
+import dagger.Provides
+import javax.inject.Provider
+
+@Module
+object NotificationIconAreaControllerModule {
+    @Provides
+    fun provideNotificationIconAreaControllerImpl(
+        featureFlags: FeatureFlags,
+        legacyProvider: Provider<LegacyNotificationIconAreaControllerImpl>,
+        newProvider: Provider<NotificationIconAreaControllerViewBinderWrapperImpl>,
+    ): NotificationIconAreaController =
+        if (featureFlags.isEnabled(Flags.NOTIFICATION_ICON_CONTAINER_REFACTOR)) {
+            newProvider.get()
+        } else {
+            legacyProvider.get()
+        }
+}
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 fc66138..62a8cfd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
@@ -709,6 +709,11 @@
         }
     }
 
+    public void onUnlockAnimationFinished() {
+        mAnimatingPanelExpansionOnUnlock = false;
+        applyAndDispatchState();
+    }
+
     /**
      * Set the amount of progress we are currently in if we're transitioning to the full shade.
      * 0.0f means we're not transitioning yet, while 1 means we're all the way in the full
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarLocation.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarLocation.kt
index 5ace226..32e5c35 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarLocation.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarLocation.kt
@@ -24,4 +24,6 @@
     KEYGUARD,
     /** Quick settings (inside the shade). */
     QS,
+    /** ShadeCarrierGroup (above QS status bar in expanded mode). */
+    SHADE_CARRIER_GROUP,
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallback.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallback.java
index 7fe01825..a6284e3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallback.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallback.java
@@ -32,6 +32,8 @@
 import android.view.View;
 import android.view.ViewParent;
 
+import androidx.annotation.Nullable;
+
 import com.android.systemui.ActivityIntentHelper;
 import com.android.systemui.dagger.SysUISingleton;
 import com.android.systemui.dagger.qualifiers.Main;
@@ -254,16 +256,16 @@
 
     @Override
     public boolean handleRemoteViewClick(View view, PendingIntent pendingIntent,
-            boolean appRequestedAuth,
+            boolean appRequestedAuth, @Nullable Integer actionIndex,
             NotificationRemoteInputManager.ClickHandler defaultHandler) {
         final boolean isActivity = pendingIntent.isActivity();
         if (isActivity || appRequestedAuth) {
-            mActionClickLogger.logWaitingToCloseKeyguard(pendingIntent);
+            mActionClickLogger.logWaitingToCloseKeyguard(pendingIntent, actionIndex);
             final boolean afterKeyguardGone = mActivityIntentHelper
                     .wouldPendingLaunchResolverActivity(pendingIntent,
                             mLockscreenUserManager.getCurrentUserId());
             mActivityStarter.dismissKeyguardThenExecute(() -> {
-                mActionClickLogger.logKeyguardGone(pendingIntent);
+                mActionClickLogger.logKeyguardGone(pendingIntent, actionIndex);
 
                 try {
                     ActivityManager.getService().resumeAppSwitches();
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 1bceb29..cd1afc7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockedScreenOffAnimationController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockedScreenOffAnimationController.kt
@@ -223,10 +223,14 @@
                 }
                 .setCustomInterpolator(View.ALPHA, Interpolators.FAST_OUT_SLOW_IN),
             true /* animate */)
-        interactionJankMonitor.begin(
-                notifShadeWindowControllerLazy.get().windowRootView,
-            CUJ_SCREEN_OFF_SHOW_AOD
-        )
+        val builder = InteractionJankMonitor.Configuration.Builder
+            .withView(
+                    InteractionJankMonitor.CUJ_SCREEN_OFF_SHOW_AOD,
+                    notifShadeWindowControllerLazy.get().windowRootView
+            )
+            .setTag(statusBarStateControllerImpl.getClockId())
+
+        interactionJankMonitor.begin(builder)
     }
 
     override fun onStartedWakingUp() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/StatusBarPipelineFlags.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/StatusBarPipelineFlags.kt
index 6e51ed0..c695773 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/StatusBarPipelineFlags.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/StatusBarPipelineFlags.kt
@@ -18,6 +18,9 @@
 
 import android.content.Context
 import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.flags.FeatureFlags
+import com.android.systemui.flags.Flags
+import com.android.systemui.shade.carrier.ShadeCarrierGroup
 import javax.inject.Inject
 
 /** All flagging methods related to the new status bar pipeline (see b/238425913). */
@@ -26,11 +29,19 @@
 @Inject
 constructor(
     context: Context,
+    private val featureFlags: FeatureFlags,
 ) {
     private val mobileSlot = context.getString(com.android.internal.R.string.status_bar_mobile)
     private val wifiSlot = context.getString(com.android.internal.R.string.status_bar_wifi)
 
     /**
+     * True if we should display the mobile icons in the [ShadeCarrierGroup] using the new status
+     * bar Data pipeline.
+     */
+    fun useNewShadeCarrierGroupMobileIcons(): Boolean =
+        featureFlags.isEnabled(Flags.NEW_SHADE_CARRIER_GROUP_MOBILE_ICONS)
+
+    /**
      * For convenience in the StatusBarIconController, we want to gate some actions based on slot
      * name and the flag together.
      *
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/model/NetworkNameModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/model/NetworkNameModel.kt
index 78231e2..99ed2d9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/model/NetworkNameModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/model/NetworkNameModel.kt
@@ -60,6 +60,19 @@
         }
     }
 
+    /** This name has been derived from SubscriptionModel. see [SubscriptionModel] */
+    data class SubscriptionDerived(override val name: String) : NetworkNameModel {
+        override fun logDiffs(prevVal: NetworkNameModel, row: TableRowLogger) {
+            if (prevVal !is SubscriptionDerived || prevVal.name != name) {
+                row.logChange(COL_NETWORK_NAME, "SubscriptionDerived($name)")
+            }
+        }
+
+        override fun logFull(row: TableRowLogger) {
+            row.logChange(COL_NETWORK_NAME, "SubscriptionDerived($name)")
+        }
+    }
+
     /**
      * This name has been derived from the sim via
      * [android.telephony.TelephonyManager.getSimOperatorName].
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/model/SubscriptionModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/model/SubscriptionModel.kt
index 16c4027..27f6df4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/model/SubscriptionModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/model/SubscriptionModel.kt
@@ -34,4 +34,7 @@
 
     /** Subscriptions in the same group may be filtered or treated as a single subscription */
     val groupUuid: ParcelUuid? = null,
+
+    /** Text representing the name for this connection */
+    val carrierName: String,
 )
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileConnectionRepository.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileConnectionRepository.kt
index c1af6df..a89b1b2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileConnectionRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileConnectionRepository.kt
@@ -115,10 +115,18 @@
      */
     val cdmaRoaming: StateFlow<Boolean>
 
-    /** The service provider name for this network connection, or the default name */
+    /** The service provider name for this network connection, or the default name. */
     val networkName: StateFlow<NetworkNameModel>
 
     /**
+     * The service provider name for this network connection, or the default name.
+     *
+     * TODO(b/296600321): De-duplicate this field with [networkName] after determining the data
+     *   provided is identical
+     */
+    val carrierName: StateFlow<NetworkNameModel>
+
+    /**
      * True if this type of connection is allowed while airplane mode is on, and false otherwise.
      */
     val isAllowedDuringAirplaneMode: StateFlow<Boolean>
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionRepository.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionRepository.kt
index 17d20c2..c576b82 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionRepository.kt
@@ -184,7 +184,10 @@
 
     override val cdmaRoaming = MutableStateFlow(false)
 
-    override val networkName = MutableStateFlow(NetworkNameModel.IntentDerived("demo network"))
+    override val networkName = MutableStateFlow(NetworkNameModel.IntentDerived(DEMO_CARRIER_NAME))
+
+    override val carrierName =
+        MutableStateFlow(NetworkNameModel.SubscriptionDerived(DEMO_CARRIER_NAME))
 
     override val isAllowedDuringAirplaneMode = MutableStateFlow(false)
 
@@ -200,6 +203,7 @@
         // This is always true here, because we split out disabled states at the data-source level
         dataEnabled.value = true
         networkName.value = NetworkNameModel.IntentDerived(event.name)
+        carrierName.value = NetworkNameModel.SubscriptionDerived("${event.name} ${event.subId}")
 
         _carrierId.value = event.carrierId ?: INVALID_SUBSCRIPTION_ID
 
@@ -227,6 +231,7 @@
         // This is always true here, because we split out disabled states at the data-source level
         dataEnabled.value = true
         networkName.value = NetworkNameModel.IntentDerived(CARRIER_MERGED_NAME)
+        carrierName.value = NetworkNameModel.SubscriptionDerived(CARRIER_MERGED_NAME)
         // TODO(b/276943904): is carrierId a thing with carrier merged networks?
         _carrierId.value = INVALID_SUBSCRIPTION_ID
         numberOfLevels.value = event.numberOfLevels
@@ -248,6 +253,7 @@
     }
 
     companion object {
+        private const val DEMO_CARRIER_NAME = "Demo Carrier"
         private const val CARRIER_MERGED_NAME = "Carrier Merged Network"
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionsRepository.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionsRepository.kt
index 0e4ceeb..ee13d93 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionsRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionsRepository.kt
@@ -92,9 +92,12 @@
 
     private fun maybeCreateSubscription(subId: Int) {
         if (!subscriptionInfoCache.containsKey(subId)) {
-            SubscriptionModel(subscriptionId = subId, isOpportunistic = false).also {
-                subscriptionInfoCache[subId] = it
-            }
+            SubscriptionModel(
+                    subscriptionId = subId,
+                    isOpportunistic = false,
+                    carrierName = DEFAULT_CARRIER_NAME,
+                )
+                .also { subscriptionInfoCache[subId] = it }
 
             _subscriptions.value = subscriptionInfoCache.values.toList()
         }
@@ -327,6 +330,7 @@
         private const val TAG = "DemoMobileConnectionsRepo"
 
         private const val DEFAULT_SUB_ID = 1
+        private const val DEFAULT_CARRIER_NAME = "demo carrier"
     }
 }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/CarrierMergedConnectionRepository.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/CarrierMergedConnectionRepository.kt
index 65f4866..28be3be 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/CarrierMergedConnectionRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/CarrierMergedConnectionRepository.kt
@@ -108,6 +108,8 @@
                 NetworkNameModel.SimDerived(telephonyManager.simOperatorName),
             )
 
+    override val carrierName: StateFlow<NetworkNameModel> = networkName
+
     override val numberOfLevels: StateFlow<Int> =
         wifiRepository.wifiNetwork
             .map {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/FullMobileConnectionRepository.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/FullMobileConnectionRepository.kt
index 8ba7d21..ee11c06 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/FullMobileConnectionRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/FullMobileConnectionRepository.kt
@@ -22,6 +22,7 @@
 import com.android.systemui.log.table.TableLogBufferFactory
 import com.android.systemui.log.table.logDiffsForTable
 import com.android.systemui.statusbar.pipeline.mobile.data.model.NetworkNameModel
+import com.android.systemui.statusbar.pipeline.mobile.data.model.SubscriptionModel
 import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionRepository
 import javax.inject.Inject
 import kotlinx.coroutines.CoroutineScope
@@ -47,6 +48,7 @@
     override val subId: Int,
     startingIsCarrierMerged: Boolean,
     override val tableLogBuffer: TableLogBuffer,
+    subscriptionModel: StateFlow<SubscriptionModel?>,
     private val defaultNetworkName: NetworkNameModel,
     private val networkNameSeparator: String,
     @Application scope: CoroutineScope,
@@ -80,6 +82,7 @@
         mobileRepoFactory.build(
             subId,
             tableLogBuffer,
+            subscriptionModel,
             defaultNetworkName,
             networkNameSeparator,
         )
@@ -287,6 +290,16 @@
             )
             .stateIn(scope, SharingStarted.WhileSubscribed(), activeRepo.value.networkName.value)
 
+    override val carrierName =
+        activeRepo
+            .flatMapLatest { it.carrierName }
+            .logDiffsForTable(
+                tableLogBuffer,
+                columnPrefix = "",
+                initialValue = activeRepo.value.carrierName.value,
+            )
+            .stateIn(scope, SharingStarted.WhileSubscribed(), activeRepo.value.carrierName.value)
+
     override val isAllowedDuringAirplaneMode =
         activeRepo
             .flatMapLatest { it.isAllowedDuringAirplaneMode }
@@ -307,6 +320,7 @@
         fun build(
             subId: Int,
             startingIsCarrierMerged: Boolean,
+            subscriptionModel: StateFlow<SubscriptionModel?>,
             defaultNetworkName: NetworkNameModel,
             networkNameSeparator: String,
         ): FullMobileConnectionRepository {
@@ -317,6 +331,7 @@
                 subId,
                 startingIsCarrierMerged,
                 mobileLogger,
+                subscriptionModel,
                 defaultNetworkName,
                 networkNameSeparator,
                 scope,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryImpl.kt
index aadc975..1f1ac92 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryImpl.kt
@@ -43,6 +43,7 @@
 import com.android.systemui.statusbar.pipeline.mobile.data.model.ResolvedNetworkType.DefaultNetworkType
 import com.android.systemui.statusbar.pipeline.mobile.data.model.ResolvedNetworkType.OverrideNetworkType
 import com.android.systemui.statusbar.pipeline.mobile.data.model.ResolvedNetworkType.UnknownNetworkType
+import com.android.systemui.statusbar.pipeline.mobile.data.model.SubscriptionModel
 import com.android.systemui.statusbar.pipeline.mobile.data.model.SystemUiCarrierConfig
 import com.android.systemui.statusbar.pipeline.mobile.data.model.toDataConnectionType
 import com.android.systemui.statusbar.pipeline.mobile.data.model.toNetworkNameModel
@@ -80,6 +81,7 @@
 @OptIn(ExperimentalCoroutinesApi::class)
 class MobileConnectionRepositoryImpl(
     override val subId: Int,
+    subscriptionModel: StateFlow<SubscriptionModel?>,
     defaultNetworkName: NetworkNameModel,
     networkNameSeparator: String,
     private val telephonyManager: TelephonyManager,
@@ -281,6 +283,14 @@
             }
             .stateIn(scope, SharingStarted.WhileSubscribed(), DEFAULT_NUM_LEVELS)
 
+    override val carrierName =
+        subscriptionModel
+            .map {
+                it?.let { model -> NetworkNameModel.SubscriptionDerived(model.carrierName) }
+                    ?: defaultNetworkName
+            }
+            .stateIn(scope, SharingStarted.WhileSubscribed(), defaultNetworkName)
+
     /**
      * There are a few cases where we will need to poll [TelephonyManager] so we can update some
      * internal state where callbacks aren't provided. Any of those events should be merged into
@@ -350,11 +360,13 @@
         fun build(
             subId: Int,
             mobileLogger: TableLogBuffer,
+            subscriptionModel: StateFlow<SubscriptionModel?>,
             defaultNetworkName: NetworkNameModel,
             networkNameSeparator: String,
         ): MobileConnectionRepository {
             return MobileConnectionRepositoryImpl(
                 subId,
+                subscriptionModel,
                 defaultNetworkName,
                 networkNameSeparator,
                 telephonyManager.createForSubscriptionId(subId),
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryImpl.kt
index 54948a4..67b04db 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryImpl.kt
@@ -319,10 +319,17 @@
 
     @VisibleForTesting fun getSubIdRepoCache() = subIdRepositoryCache
 
+    private fun subscriptionModelForSubId(subId: Int): StateFlow<SubscriptionModel?> {
+        return subscriptions
+            .map { list -> list.firstOrNull { model -> model.subscriptionId == subId } }
+            .stateIn(scope, SharingStarted.WhileSubscribed(), null)
+    }
+
     private fun createRepositoryForSubId(subId: Int): FullMobileConnectionRepository {
         return fullMobileRepoFactory.build(
             subId,
             isCarrierMerged(subId),
+            subscriptionModelForSubId(subId),
             defaultNetworkName,
             networkNameSeparator,
         )
@@ -373,6 +380,7 @@
             subscriptionId = subscriptionId,
             isOpportunistic = isOpportunistic,
             groupUuid = groupUuid,
+            carrierName = carrierName.toString(),
         )
 
     companion object {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractor.kt
index 1a13827..4cfde5b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractor.kt
@@ -92,6 +92,22 @@
      */
     val networkName: StateFlow<NetworkNameModel>
 
+    /**
+     * Provider name for this network connection. The name can be one of 3 values:
+     * 1. The default network name, if one is configured
+     * 2. A name provided by the [SubscriptionModel] of this network connection
+     * 3. Or, in the case where the repository sends us the default network name, we check for an
+     *    override in [connectionInfo.operatorAlphaShort], a value that is derived from
+     *    [ServiceState]
+     *
+     * TODO(b/296600321): De-duplicate this field with [networkName] after determining the data
+     *   provided is identical
+     */
+    val carrierName: StateFlow<String>
+
+    /** True if there is only one active subscription. */
+    val isSingleCarrier: StateFlow<Boolean>
+
     /** True if this line of service is emergency-only */
     val isEmergencyOnly: StateFlow<Boolean>
 
@@ -126,6 +142,7 @@
     defaultSubscriptionHasDataEnabled: StateFlow<Boolean>,
     override val alwaysShowDataRatIcon: StateFlow<Boolean>,
     override val alwaysUseCdmaLevel: StateFlow<Boolean>,
+    override val isSingleCarrier: StateFlow<Boolean>,
     override val mobileIsDefault: StateFlow<Boolean>,
     defaultMobileIconMapping: StateFlow<Map<String, MobileIconGroup>>,
     defaultMobileIconGroup: StateFlow<MobileIconGroup>,
@@ -171,6 +188,22 @@
                 connectionRepository.networkName.value
             )
 
+    override val carrierName =
+        combine(connectionRepository.operatorAlphaShort, connectionRepository.carrierName) {
+                operatorAlphaShort,
+                networkName ->
+                if (networkName is NetworkNameModel.Default && operatorAlphaShort != null) {
+                    operatorAlphaShort
+                } else {
+                    networkName.name
+                }
+            }
+            .stateIn(
+                scope,
+                SharingStarted.WhileSubscribed(),
+                connectionRepository.carrierName.value.name
+            )
+
     /** What the mobile icon would be before carrierId overrides */
     private val defaultNetworkType: StateFlow<MobileIconGroup> =
         combine(
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractor.kt
index e90f40c7..d08808b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractor.kt
@@ -76,6 +76,9 @@
     /** True if the CDMA level should be preferred over the primary level. */
     val alwaysUseCdmaLevel: StateFlow<Boolean>
 
+    /** True if there is only one active subscription. */
+    val isSingleCarrier: StateFlow<Boolean>
+
     /** The icon mapping from network type to [MobileIconGroup] for the default subscription */
     val defaultMobileIconMapping: StateFlow<Map<String, MobileIconGroup>>
 
@@ -252,6 +255,17 @@
             .mapLatest { it.alwaysShowCdmaRssi }
             .stateIn(scope, SharingStarted.WhileSubscribed(), false)
 
+    override val isSingleCarrier: StateFlow<Boolean> =
+        mobileConnectionsRepo.subscriptions
+            .map { it.size == 1 }
+            .logDiffsForTable(
+                tableLogger,
+                columnPrefix = LOGGING_PREFIX,
+                columnName = "isSingleCarrier",
+                initialValue = false,
+            )
+            .stateIn(scope, SharingStarted.WhileSubscribed(), false)
+
     /** If there is no mapping in [defaultMobileIconMapping], then use this default icon group */
     override val defaultMobileIconGroup: StateFlow<MobileIconGroup> =
         mobileConnectionsRepo.defaultMobileIconGroup.stateIn(
@@ -298,6 +312,7 @@
             activeDataConnectionHasDataEnabled,
             alwaysShowDataRatIcon,
             alwaysUseCdmaLevel,
+            isSingleCarrier,
             mobileIsDefault,
             defaultMobileIconMapping,
             defaultMobileIconGroup,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/MobileUiAdapter.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/MobileUiAdapter.kt
index d7fcf48..02e50a0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/MobileUiAdapter.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/MobileUiAdapter.kt
@@ -19,6 +19,7 @@
 import com.android.systemui.CoreStartable
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.shade.carrier.ShadeCarrierGroupController
 import com.android.systemui.statusbar.phone.StatusBarIconController
 import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.MobileIconsInteractor
 import com.android.systemui.statusbar.pipeline.mobile.ui.viewmodel.MobileIconsViewModel
@@ -49,6 +50,8 @@
     private var isCollecting: Boolean = false
     private var lastValue: List<Int>? = null
 
+    private var shadeCarrierGroupController: ShadeCarrierGroupController? = null
+
     override fun start() {
         // Start notifying the icon controller of subscriptions
         scope.launch {
@@ -57,10 +60,16 @@
                 logger.logUiAdapterSubIdsSentToIconController(it)
                 lastValue = it
                 iconController.setNewMobileIconSubIds(it)
+                shadeCarrierGroupController?.updateModernMobileIcons(it)
             }
         }
     }
 
+    /** Set the [ShadeCarrierGroupController] to notify of subscription updates */
+    fun setShadeCarrierGroupController(controller: ShadeCarrierGroupController) {
+        shadeCarrierGroupController = controller
+    }
+
     override fun dump(pw: PrintWriter, args: Array<out String>) {
         pw.println("isCollecting=$isCollecting")
         pw.println("Last values sent to icon controller: $lastValue")
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/MobileViewLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/MobileViewLogger.kt
index cea6654..2af6795b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/MobileViewLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/MobileViewLogger.kt
@@ -57,7 +57,7 @@
             {
                 str1 = view.getIdForLogging()
                 str2 = viewModel.getIdForLogging()
-                str3 = viewModel.locationName
+                str3 = viewModel.location.name
             },
             { "New view binding. viewId=$str1, viewModelId=$str2, viewModelLocation=$str3" },
         )
@@ -71,7 +71,7 @@
             {
                 str1 = view.getIdForLogging()
                 str2 = viewModel.getIdForLogging()
-                str3 = viewModel.locationName
+                str3 = viewModel.location.name
             },
             { "Collection started. viewId=$str1, viewModelId=$str2, viewModelLocation=$str3" },
         )
@@ -85,7 +85,7 @@
             {
                 str1 = view.getIdForLogging()
                 str2 = viewModel.getIdForLogging()
-                str3 = viewModel.locationName
+                str3 = viewModel.location.name
             },
             { "Collection stopped. viewId=$str1, viewModelId=$str2, viewModelLocation=$str3" },
         )
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/binder/MobileIconBinder.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/binder/MobileIconBinder.kt
index 55bc8d5..4b2fb43 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/binder/MobileIconBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/binder/MobileIconBinder.kt
@@ -50,6 +50,7 @@
     fun bind(
         view: ViewGroup,
         viewModel: LocationBasedMobileViewModel,
+        @StatusBarIconView.VisibleState initialVisibilityState: Int = STATE_HIDDEN,
         logger: MobileViewLogger,
     ): ModernStatusBarViewBinding {
         val mobileGroupView = view.requireViewById<ViewGroup>(R.id.mobile_group)
@@ -68,12 +69,12 @@
 
         // TODO(b/238425913): We should log this visibility state.
         @StatusBarIconView.VisibleState
-        val visibilityState: MutableStateFlow<Int> = MutableStateFlow(STATE_HIDDEN)
+        val visibilityState: MutableStateFlow<Int> = MutableStateFlow(initialVisibilityState)
 
         val iconTint: MutableStateFlow<Int> = MutableStateFlow(viewModel.defaultColor)
         val decorTint: MutableStateFlow<Int> = MutableStateFlow(viewModel.defaultColor)
 
-        var isCollecting: Boolean = false
+        var isCollecting = false
 
         view.repeatWhenAttached {
             repeatOnLifecycle(Lifecycle.State.STARTED) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/binder/ShadeCarrierBinder.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/binder/ShadeCarrierBinder.kt
new file mode 100644
index 0000000..081e101
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/binder/ShadeCarrierBinder.kt
@@ -0,0 +1,42 @@
+/*
+ * 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.pipeline.mobile.ui.binder
+
+import androidx.core.view.isVisible
+import androidx.lifecycle.Lifecycle
+import androidx.lifecycle.repeatOnLifecycle
+import com.android.systemui.lifecycle.repeatWhenAttached
+import com.android.systemui.statusbar.pipeline.mobile.ui.viewmodel.ShadeCarrierGroupMobileIconViewModel
+import com.android.systemui.util.AutoMarqueeTextView
+import kotlinx.coroutines.launch
+
+object ShadeCarrierBinder {
+    /** Binds the view to the view-model, continuing to update the former based on the latter */
+    @JvmStatic
+    fun bind(
+        carrierTextView: AutoMarqueeTextView,
+        viewModel: ShadeCarrierGroupMobileIconViewModel,
+    ) {
+        carrierTextView.isVisible = true
+
+        carrierTextView.repeatWhenAttached {
+            repeatOnLifecycle(Lifecycle.State.STARTED) {
+                launch { viewModel.carrierName.collect { carrierTextView.text = it } }
+            }
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/view/ModernShadeCarrierGroupMobileView.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/view/ModernShadeCarrierGroupMobileView.kt
new file mode 100644
index 0000000..f407127
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/view/ModernShadeCarrierGroupMobileView.kt
@@ -0,0 +1,77 @@
+/*
+ * 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.pipeline.mobile.ui.view
+
+import android.content.Context
+import android.util.AttributeSet
+import android.view.LayoutInflater
+import android.widget.LinearLayout
+import com.android.systemui.R
+import com.android.systemui.statusbar.StatusBarIconView.STATE_ICON
+import com.android.systemui.statusbar.pipeline.mobile.ui.MobileViewLogger
+import com.android.systemui.statusbar.pipeline.mobile.ui.binder.MobileIconBinder
+import com.android.systemui.statusbar.pipeline.mobile.ui.binder.ShadeCarrierBinder
+import com.android.systemui.statusbar.pipeline.mobile.ui.viewmodel.ShadeCarrierGroupMobileIconViewModel
+import com.android.systemui.util.AutoMarqueeTextView
+
+/**
+ * ViewGroup containing a mobile carrier name and icon in the Shade Header. Can be multiple
+ * instances as children under [ShadeCarrierGroup]
+ */
+class ModernShadeCarrierGroupMobileView(
+    context: Context,
+    attrs: AttributeSet?,
+) : LinearLayout(context, attrs) {
+
+    var subId: Int = -1
+
+    override fun toString(): String {
+        return "ModernShadeCarrierGroupMobileView(" +
+            "subId=$subId, " +
+            "viewString=${super.toString()}"
+    }
+
+    companion object {
+
+        /**
+         * Inflates a new instance of [ModernShadeCarrierGroupMobileView], binds it to [viewModel],
+         * and returns it.
+         */
+        @JvmStatic
+        fun constructAndBind(
+            context: Context,
+            logger: MobileViewLogger,
+            slot: String,
+            viewModel: ShadeCarrierGroupMobileIconViewModel,
+        ): ModernShadeCarrierGroupMobileView {
+            return (LayoutInflater.from(context).inflate(R.layout.shade_carrier_new, null)
+                    as ModernShadeCarrierGroupMobileView)
+                .also {
+                    it.subId = viewModel.subscriptionId
+
+                    val iconView = it.requireViewById<ModernStatusBarMobileView>(R.id.mobile_combo)
+                    iconView.initView(slot) {
+                        MobileIconBinder.bind(iconView, viewModel, STATE_ICON, logger)
+                    }
+                    logger.logNewViewBinding(it, viewModel)
+
+                    val textView = it.requireViewById<AutoMarqueeTextView>(R.id.mobile_carrier_text)
+                    ShadeCarrierBinder.bind(textView, viewModel)
+                }
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/view/ModernStatusBarMobileView.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/view/ModernStatusBarMobileView.kt
index 4144293d..68d02de 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/view/ModernStatusBarMobileView.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/view/ModernStatusBarMobileView.kt
@@ -60,7 +60,9 @@
                     as ModernStatusBarMobileView)
                 .also {
                     it.subId = viewModel.subscriptionId
-                    it.initView(slot) { MobileIconBinder.bind(it, viewModel, logger) }
+                    it.initView(slot) {
+                        MobileIconBinder.bind(view = it, viewModel = viewModel, logger = logger)
+                    }
                     logger.logNewViewBinding(it, viewModel)
                 }
         }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/LocationBasedMobileViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/LocationBasedMobileViewModel.kt
index a51982c..e7c311d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/LocationBasedMobileViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/LocationBasedMobileViewModel.kt
@@ -18,7 +18,13 @@
 
 import android.graphics.Color
 import com.android.systemui.statusbar.phone.StatusBarLocation
+import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.MobileIconInteractor
 import com.android.systemui.statusbar.pipeline.mobile.ui.VerboseMobileViewLogger
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.flow.SharingStarted
+import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.flow.stateIn
 
 /**
  * A view model for an individual mobile icon that embeds the notion of a [StatusBarLocation]. This
@@ -26,12 +32,12 @@
  *
  * @param commonImpl for convenience, this class wraps a base interface that can provides all of the
  *   common implementations between locations. See [MobileIconViewModel]
- * @property locationName the name of the location of this VM, used for logging.
+ * @property location the [StatusBarLocation] of this VM.
  * @property verboseLogger an optional logger to log extremely verbose view updates.
  */
 abstract class LocationBasedMobileViewModel(
     val commonImpl: MobileIconViewModelCommon,
-    val locationName: String,
+    val location: StatusBarLocation,
     val verboseLogger: VerboseMobileViewLogger?,
 ) : MobileIconViewModelCommon by commonImpl {
     val defaultColor: Int = Color.WHITE
@@ -39,10 +45,12 @@
     companion object {
         fun viewModelForLocation(
             commonImpl: MobileIconViewModelCommon,
+            interactor: MobileIconInteractor,
             verboseMobileViewLogger: VerboseMobileViewLogger,
-            loc: StatusBarLocation,
+            location: StatusBarLocation,
+            scope: CoroutineScope,
         ): LocationBasedMobileViewModel =
-            when (loc) {
+            when (location) {
                 StatusBarLocation.HOME ->
                     HomeMobileIconViewModel(
                         commonImpl,
@@ -50,6 +58,12 @@
                     )
                 StatusBarLocation.KEYGUARD -> KeyguardMobileIconViewModel(commonImpl)
                 StatusBarLocation.QS -> QsMobileIconViewModel(commonImpl)
+                StatusBarLocation.SHADE_CARRIER_GROUP ->
+                    ShadeCarrierGroupMobileIconViewModel(
+                        commonImpl,
+                        interactor,
+                        scope,
+                    )
             }
     }
 }
@@ -61,7 +75,7 @@
     MobileIconViewModelCommon,
     LocationBasedMobileViewModel(
         commonImpl,
-        locationName = "Home",
+        location = StatusBarLocation.HOME,
         verboseMobileViewLogger,
     )
 
@@ -71,18 +85,40 @@
     MobileIconViewModelCommon,
     LocationBasedMobileViewModel(
         commonImpl,
-        locationName = "QS",
+        location = StatusBarLocation.QS,
         // Only do verbose logging for the Home location.
         verboseLogger = null,
     )
 
+class ShadeCarrierGroupMobileIconViewModel(
+    commonImpl: MobileIconViewModelCommon,
+    interactor: MobileIconInteractor,
+    scope: CoroutineScope,
+) :
+    MobileIconViewModelCommon,
+    LocationBasedMobileViewModel(
+        commonImpl,
+        location = StatusBarLocation.SHADE_CARRIER_GROUP,
+        // Only do verbose logging for the Home location.
+        verboseLogger = null,
+    ) {
+    private val isSingleCarrier = interactor.isSingleCarrier
+    val carrierName = interactor.carrierName
+
+    override val isVisible: StateFlow<Boolean> =
+        combine(super.isVisible, isSingleCarrier) { isVisible, isSingleCarrier ->
+                if (isSingleCarrier) false else isVisible
+            }
+            .stateIn(scope, SharingStarted.WhileSubscribed(), super.isVisible.value)
+}
+
 class KeyguardMobileIconViewModel(
     commonImpl: MobileIconViewModelCommon,
 ) :
     MobileIconViewModelCommon,
     LocationBasedMobileViewModel(
         commonImpl,
-        locationName = "Keyguard",
+        location = StatusBarLocation.KEYGUARD,
         // Only do verbose logging for the Home location.
         verboseLogger = null,
     )
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconsViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconsViewModel.kt
index 5cf887e..216afb9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconsViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconsViewModel.kt
@@ -22,6 +22,7 @@
 import com.android.systemui.statusbar.phone.StatusBarLocation
 import com.android.systemui.statusbar.pipeline.StatusBarPipelineFlags
 import com.android.systemui.statusbar.pipeline.airplane.domain.interactor.AirplaneModeInteractor
+import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.MobileIconInteractor
 import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.MobileIconsInteractor
 import com.android.systemui.statusbar.pipeline.mobile.ui.MobileViewLogger
 import com.android.systemui.statusbar.pipeline.mobile.ui.VerboseMobileViewLogger
@@ -58,6 +59,8 @@
     private val statusBarPipelineFlags: StatusBarPipelineFlags,
 ) {
     @VisibleForTesting val mobileIconSubIdCache = mutableMapOf<Int, MobileIconViewModel>()
+    @VisibleForTesting
+    val mobileIconInteractorSubIdCache = mutableMapOf<Int, MobileIconInteractor>()
 
     val subscriptionIdsFlow: StateFlow<List<Int>> =
         interactor.filteredSubscriptions
@@ -91,15 +94,17 @@
             .stateIn(scope, SharingStarted.WhileSubscribed(), false)
 
     init {
-        scope.launch { subscriptionIdsFlow.collect { removeInvalidModelsFromCache(it) } }
+        scope.launch { subscriptionIdsFlow.collect { invalidateCaches(it) } }
     }
 
     fun viewModelForSub(subId: Int, location: StatusBarLocation): LocationBasedMobileViewModel {
         val common = commonViewModelForSub(subId)
         return LocationBasedMobileViewModel.viewModelForLocation(
             common,
+            mobileIconInteractorForSub(subId),
             verboseLogger,
             location,
+            scope,
         )
     }
 
@@ -107,7 +112,7 @@
         return mobileIconSubIdCache[subId]
             ?: MobileIconViewModel(
                     subId,
-                    interactor.createMobileConnectionInteractorForSubId(subId),
+                    mobileIconInteractorForSub(subId),
                     airplaneModeInteractor,
                     constants,
                     scope,
@@ -115,8 +120,20 @@
                 .also { mobileIconSubIdCache[subId] = it }
     }
 
-    private fun removeInvalidModelsFromCache(subIds: List<Int>) {
+    @VisibleForTesting
+    fun mobileIconInteractorForSub(subId: Int): MobileIconInteractor {
+        return mobileIconInteractorSubIdCache[subId]
+            ?: interactor.createMobileConnectionInteractorForSubId(subId).also {
+                mobileIconInteractorSubIdCache[subId] = it
+            }
+    }
+
+    private fun invalidateCaches(subIds: List<Int>) {
         val subIdsToRemove = mobileIconSubIdCache.keys.filter { !subIds.contains(it) }
         subIdsToRemove.forEach { mobileIconSubIdCache.remove(it) }
+
+        mobileIconInteractorSubIdCache.keys
+            .filter { !subIds.contains(it) }
+            .forEach { subId -> mobileIconInteractorSubIdCache.remove(subId) }
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/LocationBasedWifiViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/LocationBasedWifiViewModel.kt
index cd5b92c..00bd616 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/LocationBasedWifiViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/LocationBasedWifiViewModel.kt
@@ -18,6 +18,7 @@
 
 import android.graphics.Color
 import com.android.systemui.statusbar.phone.StatusBarLocation
+import java.lang.IllegalArgumentException
 
 /**
  * A view model for a wifi icon in a specific location. This allows us to control parameters that
@@ -43,6 +44,8 @@
                 StatusBarLocation.HOME -> HomeWifiViewModel(commonImpl)
                 StatusBarLocation.KEYGUARD -> KeyguardWifiViewModel(commonImpl)
                 StatusBarLocation.QS -> QsWifiViewModel(commonImpl)
+                StatusBarLocation.SHADE_CARRIER_GROUP ->
+                    throw IllegalArgumentException("invalid location for WifiViewModel: $location")
             }
     }
 }
@@ -64,3 +67,11 @@
 class QsWifiViewModel(
     commonImpl: WifiViewModelCommon,
 ) : WifiViewModelCommon, LocationBasedWifiViewModel(commonImpl)
+
+/**
+ * A view model for the wifi icon in the shade carrier group (visible when quick settings is fully
+ * expanded, and in large screen shade). Currently unused.
+ */
+class ShadeCarrierGroupWifiViewModel(
+    commonImpl: WifiViewModelCommon,
+) : WifiViewModelCommon, LocationBasedWifiViewModel(commonImpl)
diff --git a/packages/SystemUI/src/com/android/systemui/wallpapers/ImageWallpaper.java b/packages/SystemUI/src/com/android/systemui/wallpapers/ImageWallpaper.java
index 091a54f..316b54e 100644
--- a/packages/SystemUI/src/com/android/systemui/wallpapers/ImageWallpaper.java
+++ b/packages/SystemUI/src/com/android/systemui/wallpapers/ImageWallpaper.java
@@ -109,7 +109,6 @@
         private WallpaperManager mWallpaperManager;
         private final WallpaperLocalColorExtractor mWallpaperLocalColorExtractor;
         private SurfaceHolder mSurfaceHolder;
-        private boolean mDrawn = false;
         @VisibleForTesting
         static final int MIN_SURFACE_WIDTH = 128;
         @VisibleForTesting
@@ -239,7 +238,6 @@
 
         private void drawFrameSynchronized() {
             synchronized (mLock) {
-                if (mDrawn) return;
                 drawFrameInternal();
             }
         }
@@ -277,7 +275,6 @@
                 Rect dest = mSurfaceHolder.getSurfaceFrame();
                 try {
                     canvas.drawBitmap(bitmap, null, dest, null);
-                    mDrawn = true;
                 } finally {
                     surface.unlockCanvasAndPost(canvas);
                 }
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.kt
index a9aed2f..b5317fa 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.kt
@@ -620,6 +620,51 @@
         configurationListenerArgumentCaptor.value.onUiModeChanged()
         verify(view).reloadColors()
     }
+    @Test
+    fun onOrientationChanged_landscapeKeyguardFlagDisabled_blockReinflate() {
+        featureFlags.set(Flags.LOCKSCREEN_ENABLE_LANDSCAPE, false)
+
+        // Run onOrientationChanged
+        val configurationListenerArgumentCaptor =
+            ArgumentCaptor.forClass(ConfigurationController.ConfigurationListener::class.java)
+        underTest.onViewAttached()
+        verify(configurationController).addCallback(configurationListenerArgumentCaptor.capture())
+        clearInvocations(viewFlipperController)
+        configurationListenerArgumentCaptor.value.onOrientationChanged(
+            Configuration.ORIENTATION_LANDSCAPE
+        )
+        // Verify view is reinflated when flag is on
+        verify(viewFlipperController, never()).clearViews()
+        verify(viewFlipperController, never())
+            .asynchronouslyInflateView(
+                eq(SecurityMode.PIN),
+                any(),
+                onViewInflatedCallbackArgumentCaptor.capture()
+            )
+    }
+
+    @Test
+    fun onOrientationChanged_landscapeKeyguardFlagEnabled_doesReinflate() {
+        featureFlags.set(Flags.LOCKSCREEN_ENABLE_LANDSCAPE, true)
+
+        // Run onOrientationChanged
+        val configurationListenerArgumentCaptor =
+            ArgumentCaptor.forClass(ConfigurationController.ConfigurationListener::class.java)
+        underTest.onViewAttached()
+        verify(configurationController).addCallback(configurationListenerArgumentCaptor.capture())
+        clearInvocations(viewFlipperController)
+        configurationListenerArgumentCaptor.value.onOrientationChanged(
+            Configuration.ORIENTATION_LANDSCAPE
+        )
+        // Verify view is reinflated when flag is on
+        verify(viewFlipperController).clearViews()
+        verify(viewFlipperController)
+            .asynchronouslyInflateView(
+                eq(SecurityMode.PIN),
+                any(),
+                onViewInflatedCallbackArgumentCaptor.capture()
+            )
+    }
 
     @Test
     fun hasDismissActions() {
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewControllerTest.java
index 7d23c80..b8b0198 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewControllerTest.java
@@ -77,7 +77,7 @@
     public void updatePosition_primaryClockAnimation() {
         ClockController mockClock = mock(ClockController.class);
         when(mKeyguardClockSwitchController.getClock()).thenReturn(mockClock);
-        when(mockClock.getConfig()).thenReturn(new ClockConfig(false, true));
+        when(mockClock.getConfig()).thenReturn(new ClockConfig("MOCK", false, true));
 
         mController.updatePosition(10, 15, 20f, true);
 
@@ -92,7 +92,7 @@
     public void updatePosition_alternateClockAnimation() {
         ClockController mockClock = mock(ClockController.class);
         when(mKeyguardClockSwitchController.getClock()).thenReturn(mockClock);
-        when(mockClock.getConfig()).thenReturn(new ClockConfig(true, true));
+        when(mockClock.getConfig()).thenReturn(new ClockConfig("MOCK", true, true));
 
         mController.updatePosition(10, 15, 20f, true);
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/LightRevealScrimRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/LightRevealScrimRepositoryTest.kt
index dcaafe8..6fcf54c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/LightRevealScrimRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/LightRevealScrimRepositoryTest.kt
@@ -17,8 +17,8 @@
 package com.android.systemui.keyguard.data.repository
 
 import android.graphics.Point
-import android.testing.AndroidTestingRunner
 import android.testing.TestableLooper
+import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.systemui.RoboPilotTest
 import com.android.systemui.SysuiTestCase
@@ -47,7 +47,7 @@
 @SmallTest
 @RoboPilotTest
 @OptIn(ExperimentalCoroutinesApi::class)
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
 class LightRevealScrimRepositoryTest : SysuiTestCase() {
     private lateinit var fakeKeyguardRepository: FakeKeyguardRepository
     private lateinit var underTest: LightRevealScrimRepositoryImpl
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardKeyEventInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardKeyEventInteractorTest.kt
index a3f7fc5..e0ae0c3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardKeyEventInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardKeyEventInteractorTest.kt
@@ -131,14 +131,12 @@
     }
 
     @Test
-    fun dispatchKeyEvent_menuActionUp_interactiveKeyguard_collapsesShade() {
+    fun dispatchKeyEvent_menuActionUp_interactiveKeyguard_showsPrimaryBouncer() {
         keyguardInteractorWithDependencies.repository.setWakefulnessModel(awakeWakefulnessMode)
         whenever(statusBarStateController.state).thenReturn(StatusBarState.KEYGUARD)
         whenever(statusBarKeyguardViewManager.shouldDismissOnMenuPressed()).thenReturn(true)
 
-        val actionUpMenuKeyEvent = KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_MENU)
-        assertThat(underTest.dispatchKeyEvent(actionUpMenuKeyEvent)).isTrue()
-        verify(shadeController).animateCollapseShadeForced()
+        verifyActionUpShowsPrimaryBouncer(KeyEvent.KEYCODE_MENU)
     }
 
     @Test
@@ -147,42 +145,48 @@
         whenever(statusBarStateController.state).thenReturn(StatusBarState.SHADE_LOCKED)
         whenever(statusBarKeyguardViewManager.shouldDismissOnMenuPressed()).thenReturn(true)
 
-        // action down: does NOT collapse the shade
-        val actionDownMenuKeyEvent = KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_MENU)
-        assertThat(underTest.dispatchKeyEvent(actionDownMenuKeyEvent)).isFalse()
-        verify(shadeController, never()).animateCollapseShadeForced()
-
-        // action up: collapses the shade
-        val actionUpMenuKeyEvent = KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_MENU)
-        assertThat(underTest.dispatchKeyEvent(actionUpMenuKeyEvent)).isTrue()
-        verify(shadeController).animateCollapseShadeForced()
+        verifyActionUpCollapsesTheShade(KeyEvent.KEYCODE_MENU)
     }
 
     @Test
-    fun dispatchKeyEvent_menuActionUp_nonInteractiveKeyguard_neverCollapsesShade() {
+    fun dispatchKeyEvent_menuActionUp_nonInteractiveKeyguard_doNothing() {
         keyguardInteractorWithDependencies.repository.setWakefulnessModel(asleepWakefulnessMode)
         whenever(statusBarStateController.state).thenReturn(StatusBarState.KEYGUARD)
         whenever(statusBarKeyguardViewManager.shouldDismissOnMenuPressed()).thenReturn(true)
 
-        val actionUpMenuKeyEvent = KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_MENU)
-        assertThat(underTest.dispatchKeyEvent(actionUpMenuKeyEvent)).isFalse()
-        verify(shadeController, never()).animateCollapseShadeForced()
+        verifyActionsDoNothing(KeyEvent.KEYCODE_MENU)
     }
 
     @Test
-    fun dispatchKeyEvent_spaceActionUp_interactiveKeyguard_collapsesShade() {
+    fun dispatchKeyEvent_spaceActionUp_interactiveKeyguard_showsPrimaryBouncer() {
         keyguardInteractorWithDependencies.repository.setWakefulnessModel(awakeWakefulnessMode)
         whenever(statusBarStateController.state).thenReturn(StatusBarState.KEYGUARD)
 
-        // action down: does NOT collapse the shade
-        val actionDownMenuKeyEvent = KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_SPACE)
-        assertThat(underTest.dispatchKeyEvent(actionDownMenuKeyEvent)).isFalse()
-        verify(shadeController, never()).animateCollapseShadeForced()
+        verifyActionUpShowsPrimaryBouncer(KeyEvent.KEYCODE_SPACE)
+    }
 
-        // action up: collapses the shade
-        val actionUpMenuKeyEvent = KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_SPACE)
-        assertThat(underTest.dispatchKeyEvent(actionUpMenuKeyEvent)).isTrue()
-        verify(shadeController).animateCollapseShadeForced()
+    @Test
+    fun dispatchKeyEvent_spaceActionUp_shadeLocked_collapsesShade() {
+        keyguardInteractorWithDependencies.repository.setWakefulnessModel(awakeWakefulnessMode)
+        whenever(statusBarStateController.state).thenReturn(StatusBarState.SHADE_LOCKED)
+
+        verifyActionUpCollapsesTheShade(KeyEvent.KEYCODE_SPACE)
+    }
+
+    @Test
+    fun dispatchKeyEvent_enterActionUp_interactiveKeyguard_showsPrimaryBouncer() {
+        keyguardInteractorWithDependencies.repository.setWakefulnessModel(awakeWakefulnessMode)
+        whenever(statusBarStateController.state).thenReturn(StatusBarState.KEYGUARD)
+
+        verifyActionUpShowsPrimaryBouncer(KeyEvent.KEYCODE_ENTER)
+    }
+
+    @Test
+    fun dispatchKeyEvent_enterActionUp_shadeLocked_collapsesShade() {
+        keyguardInteractorWithDependencies.repository.setWakefulnessModel(awakeWakefulnessMode)
+        whenever(statusBarStateController.state).thenReturn(StatusBarState.SHADE_LOCKED)
+
+        verifyActionUpCollapsesTheShade(KeyEvent.KEYCODE_ENTER)
     }
 
     @Test
@@ -252,4 +256,42 @@
             .isFalse()
         verify(statusBarKeyguardViewManager, never()).interceptMediaKey(any())
     }
+
+    private fun verifyActionUpCollapsesTheShade(keycode: Int) {
+        // action down: does NOT collapse the shade
+        val actionDownMenuKeyEvent = KeyEvent(KeyEvent.ACTION_DOWN, keycode)
+        assertThat(underTest.dispatchKeyEvent(actionDownMenuKeyEvent)).isFalse()
+        verify(shadeController, never()).animateCollapseShadeForced()
+
+        // action up: collapses the shade
+        val actionUpMenuKeyEvent = KeyEvent(KeyEvent.ACTION_UP, keycode)
+        assertThat(underTest.dispatchKeyEvent(actionUpMenuKeyEvent)).isTrue()
+        verify(shadeController).animateCollapseShadeForced()
+    }
+
+    private fun verifyActionUpShowsPrimaryBouncer(keycode: Int) {
+        // action down: does NOT collapse the shade
+        val actionDownMenuKeyEvent = KeyEvent(KeyEvent.ACTION_DOWN, keycode)
+        assertThat(underTest.dispatchKeyEvent(actionDownMenuKeyEvent)).isFalse()
+        verify(statusBarKeyguardViewManager, never()).showPrimaryBouncer(any())
+
+        // action up: collapses the shade
+        val actionUpMenuKeyEvent = KeyEvent(KeyEvent.ACTION_UP, keycode)
+        assertThat(underTest.dispatchKeyEvent(actionUpMenuKeyEvent)).isTrue()
+        verify(statusBarKeyguardViewManager).showPrimaryBouncer(eq(true))
+    }
+
+    private fun verifyActionsDoNothing(keycode: Int) {
+        // action down: does nothing
+        val actionDownMenuKeyEvent = KeyEvent(KeyEvent.ACTION_DOWN, keycode)
+        assertThat(underTest.dispatchKeyEvent(actionDownMenuKeyEvent)).isFalse()
+        verify(shadeController, never()).animateCollapseShadeForced()
+        verify(statusBarKeyguardViewManager, never()).showPrimaryBouncer(any())
+
+        // action up: doesNothing
+        val actionUpMenuKeyEvent = KeyEvent(KeyEvent.ACTION_UP, keycode)
+        assertThat(underTest.dispatchKeyEvent(actionUpMenuKeyEvent)).isFalse()
+        verify(shadeController, never()).animateCollapseShadeForced()
+        verify(statusBarKeyguardViewManager, never()).showPrimaryBouncer(any())
+    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerTest.java
index eb4ae1a..7aeafeb 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerTest.java
@@ -539,6 +539,23 @@
     }
 
     @Test
+    public void onKeyguardStatusViewHeightChange_animatesNextTopPaddingChangeForNSSL() {
+        ArgumentCaptor<View.OnLayoutChangeListener> captor =
+                ArgumentCaptor.forClass(View.OnLayoutChangeListener.class);
+        verify(mKeyguardStatusView).addOnLayoutChangeListener(captor.capture());
+        View.OnLayoutChangeListener listener = captor.getValue();
+
+        clearInvocations(mNotificationStackScrollLayoutController);
+
+        when(mKeyguardStatusView.getHeight()).thenReturn(0);
+        listener.onLayoutChange(mKeyguardStatusView, /* left= */ 0, /* top= */ 0, /* right= */
+                0, /* bottom= */ 0, /* oldLeft= */ 0, /* oldTop= */ 0, /* oldRight= */
+                0, /* oldBottom = */ 200);
+
+        verify(mNotificationStackScrollLayoutController).animateNextTopPaddingChange();
+    }
+
+    @Test
     public void testCanCollapsePanelOnTouch_trueForKeyGuard() {
         mStatusBarStateController.setState(KEYGUARD);
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt
index 1edeeff..3cce423 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt
@@ -18,6 +18,7 @@
 
 import android.testing.AndroidTestingRunner
 import android.testing.TestableLooper.RunWithLooper
+import android.view.KeyEvent
 import android.view.MotionEvent
 import android.view.ViewGroup
 import androidx.test.filters.SmallTest
@@ -38,6 +39,7 @@
 import com.android.systemui.dump.logcatLogBuffer
 import com.android.systemui.flags.FakeFeatureFlags
 import com.android.systemui.flags.Flags
+import com.android.systemui.keyevent.domain.interactor.KeyEventInteractor
 import com.android.systemui.keyguard.KeyguardUnlockAnimationController
 import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
 import com.android.systemui.keyguard.shared.model.TransitionStep
@@ -118,8 +120,10 @@
     @Mock lateinit var keyguardTransitionInteractor: KeyguardTransitionInteractor
     @Mock
     lateinit var primaryBouncerToGoneTransitionViewModel: PrimaryBouncerToGoneTransitionViewModel
+    @Mock lateinit var keyEventInteractor: KeyEventInteractor
     private val notificationExpansionRepository = NotificationExpansionRepository()
 
+    private lateinit var fakeClock: FakeSystemClock
     private lateinit var interactionEventHandlerCaptor: ArgumentCaptor<InteractionEventHandler>
     private lateinit var interactionEventHandler: InteractionEventHandler
 
@@ -148,6 +152,7 @@
         featureFlags.set(Flags.LOCKSCREEN_WALLPAPER_DREAM_ENABLED, false)
 
         testScope = TestScope()
+        fakeClock = FakeSystemClock()
         underTest =
             NotificationShadeWindowViewController(
                     lockscreenShadeTransitionController,
@@ -180,7 +185,7 @@
                     primaryBouncerToGoneTransitionViewModel,
                     notificationExpansionRepository,
                     featureFlags,
-                    FakeSystemClock(),
+                    fakeClock,
                     BouncerMessageInteractor(
                         FakeBouncerMessageRepository(),
                         mock(BouncerMessageFactory::class.java),
@@ -188,7 +193,8 @@
                         CountDownTimerUtil(),
                         featureFlags
                     ),
-                    BouncerLogger(logcatLogBuffer("BouncerLog"))
+                    BouncerLogger(logcatLogBuffer("BouncerLog")),
+                    keyEventInteractor,
             )
         underTest.setupExpandedStatusBar()
 
@@ -328,6 +334,33 @@
         }
 
     @Test
+    fun handleDispatchTouchEvent_launchAnimationRunningTimesOut() =
+        testScope.runTest {
+            // GIVEN touch dispatcher in a state that returns true
+            underTest.setStatusBarViewController(phoneStatusBarViewController)
+            whenever(keyguardUnlockAnimationController.isPlayingCannedUnlockAnimation()).thenReturn(
+                true
+            )
+            assertThat(interactionEventHandler.handleDispatchTouchEvent(DOWN_EVENT)).isTrue()
+
+            // WHEN launch animation is running for 2 seconds
+            fakeClock.setUptimeMillis(10000)
+            underTest.setExpandAnimationRunning(true)
+            fakeClock.advanceTime(2000)
+
+            // THEN touch is ignored
+            assertThat(interactionEventHandler.handleDispatchTouchEvent(DOWN_EVENT)).isFalse()
+
+            // WHEN Launch animation is running for 6 seconds
+            fakeClock.advanceTime(4000)
+
+            // THEN move is ignored, down is handled, and window is notified
+            assertThat(interactionEventHandler.handleDispatchTouchEvent(MOVE_EVENT)).isFalse()
+            assertThat(interactionEventHandler.handleDispatchTouchEvent(DOWN_EVENT)).isTrue()
+            verify(notificationShadeWindowController).setLaunchingActivity(false)
+        }
+
+    @Test
     fun shouldInterceptTouchEvent_statusBarKeyguardViewManagerShouldIntercept() {
         // down event should be intercepted by keyguardViewManager
         whenever(statusBarKeyguardViewManager.shouldInterceptTouchEvent(DOWN_EVENT))
@@ -345,8 +378,30 @@
             verify(view).findViewById<ViewGroup>(R.id.keyguard_message_area)
         }
 
+    @Test
+    fun forwardsDispatchKeyEvent() {
+        val keyEvent = KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_B)
+        interactionEventHandler.dispatchKeyEvent(keyEvent)
+        verify(keyEventInteractor).dispatchKeyEvent(keyEvent)
+    }
+
+    @Test
+    fun forwardsDispatchKeyEventPreIme() {
+        val keyEvent = KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_B)
+        interactionEventHandler.dispatchKeyEventPreIme(keyEvent)
+        verify(keyEventInteractor).dispatchKeyEventPreIme(keyEvent)
+    }
+
+    @Test
+    fun forwardsInterceptMediaKey() {
+        val keyEvent = KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_VOLUME_UP)
+        interactionEventHandler.interceptMediaKey(keyEvent)
+        verify(keyEventInteractor).interceptMediaKey(keyEvent)
+    }
+
     companion object {
         private val DOWN_EVENT = MotionEvent.obtain(0L, 0L, MotionEvent.ACTION_DOWN, 0f, 0f, 0)
+        private val MOVE_EVENT = MotionEvent.obtain(0L, 0L, MotionEvent.ACTION_MOVE, 0f, 0f, 0)
         private const val VIEW_BOTTOM = 100
     }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewTest.kt
index 829184c..66d48d6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewTest.kt
@@ -38,6 +38,7 @@
 import com.android.systemui.dump.logcatLogBuffer
 import com.android.systemui.flags.FakeFeatureFlags
 import com.android.systemui.flags.Flags
+import com.android.systemui.keyevent.domain.interactor.KeyEventInteractor
 import com.android.systemui.keyguard.KeyguardUnlockAnimationController
 import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
 import com.android.systemui.keyguard.ui.viewmodel.PrimaryBouncerToGoneTransitionViewModel
@@ -198,7 +199,8 @@
                     CountDownTimerUtil(),
                     featureFlags
                 ),
-                BouncerLogger(logcatLogBuffer("BouncerLog"))
+                BouncerLogger(logcatLogBuffer("BouncerLog")),
+                Mockito.mock(KeyEventInteractor::class.java),
             )
 
         controller.setupExpandedStatusBar()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/carrier/ShadeCarrierGroupControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/shade/carrier/ShadeCarrierGroupControllerTest.java
index 31bfa3fd..5fa6b3a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/carrier/ShadeCarrierGroupControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/carrier/ShadeCarrierGroupControllerTest.java
@@ -29,6 +29,7 @@
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.reset;
+import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.verifyZeroInteractions;
 import static org.mockito.Mockito.when;
@@ -50,6 +51,12 @@
 import com.android.systemui.statusbar.connectivity.MobileDataIndicators;
 import com.android.systemui.statusbar.connectivity.NetworkController;
 import com.android.systemui.statusbar.connectivity.SignalCallback;
+import com.android.systemui.statusbar.connectivity.ui.MobileContextProvider;
+import com.android.systemui.statusbar.pipeline.StatusBarPipelineFlags;
+import com.android.systemui.statusbar.pipeline.mobile.ui.MobileUiAdapter;
+import com.android.systemui.statusbar.pipeline.mobile.ui.MobileViewLogger;
+import com.android.systemui.statusbar.pipeline.mobile.ui.viewmodel.MobileIconsViewModel;
+import com.android.systemui.statusbar.pipeline.mobile.ui.viewmodel.ShadeCarrierGroupMobileIconViewModel;
 import com.android.systemui.util.CarrierConfigTracker;
 import com.android.systemui.utils.leaks.LeakCheckedTest;
 import com.android.systemui.utils.os.FakeHandler;
@@ -61,6 +68,10 @@
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
 @RunWith(AndroidTestingRunner.class)
 @TestableLooper.RunWithLooper
 @SmallTest
@@ -95,6 +106,18 @@
     private TestableLooper mTestableLooper;
     @Mock
     private ShadeCarrierGroupController.OnSingleCarrierChangedListener mOnSingleCarrierChangedListener;
+    @Mock
+    private MobileUiAdapter mMobileUiAdapter;
+    @Mock
+    private MobileIconsViewModel mMobileIconsViewModel;
+    @Mock
+    private ShadeCarrierGroupMobileIconViewModel mShadeCarrierGroupMobileIconViewModel;
+    @Mock
+    private MobileViewLogger mMobileViewLogger;
+    @Mock
+    private MobileContextProvider mMobileContextProvider;
+    @Mock
+    private StatusBarPipelineFlags mStatusBarPipelineFlags;
 
     private FakeSlotIndexResolver mSlotIndexResolver;
     private ClickListenerTextView mNoCarrierTextView;
@@ -133,16 +156,35 @@
 
         mSlotIndexResolver = new FakeSlotIndexResolver();
 
+        when(mMobileUiAdapter.getMobileIconsViewModel()).thenReturn(mMobileIconsViewModel);
+
         mShadeCarrierGroupController = new ShadeCarrierGroupController.Builder(
-                mActivityStarter, handler, TestableLooper.get(this).getLooper(),
-                mNetworkController, mCarrierTextControllerBuilder, mContext, mCarrierConfigTracker,
-                mSlotIndexResolver)
+                mActivityStarter,
+                handler,
+                TestableLooper.get(this).getLooper(),
+                mNetworkController,
+                mCarrierTextControllerBuilder,
+                mContext,
+                mCarrierConfigTracker,
+                mSlotIndexResolver,
+                mMobileUiAdapter,
+                mMobileContextProvider,
+                mStatusBarPipelineFlags
+            )
                 .setShadeCarrierGroup(mShadeCarrierGroup)
                 .build();
 
         mShadeCarrierGroupController.setListening(true);
     }
 
+    private void setupWithNewPipeline() {
+        when(mStatusBarPipelineFlags.useNewShadeCarrierGroupMobileIcons()).thenReturn(true);
+        when(mMobileContextProvider.getMobileContextForSub(anyInt(), any())).thenReturn(mContext);
+        when(mMobileIconsViewModel.getLogger()).thenReturn(mMobileViewLogger);
+        when(mMobileIconsViewModel.viewModelForSub(anyInt(), any()))
+                .thenReturn(mShadeCarrierGroupMobileIconViewModel);
+    }
+
     @Test
     public void testInitiallyMultiCarrier() {
         assertFalse(mShadeCarrierGroupController.isSingleCarrier());
@@ -406,6 +448,129 @@
         verify(mOnSingleCarrierChangedListener, never()).onSingleCarrierChanged(anyBoolean());
     }
 
+    @TestableLooper.RunWithLooper(setAsMainLooper = true)
+    @Test
+    public void testUpdateModernMobileIcons_addSubscription() {
+        setupWithNewPipeline();
+
+        mShadeCarrier1.setVisibility(View.GONE);
+        mShadeCarrier2.setVisibility(View.GONE);
+        mShadeCarrier3.setVisibility(View.GONE);
+
+        List<Integer> subIds = new ArrayList<>();
+        subIds.add(0);
+        mShadeCarrierGroupController.updateModernMobileIcons(subIds);
+
+        verify(mShadeCarrier1).addModernMobileView(any());
+        verify(mShadeCarrier2, never()).addModernMobileView(any());
+        verify(mShadeCarrier3, never()).addModernMobileView(any());
+
+        resetShadeCarriers();
+
+        subIds.add(1);
+        mShadeCarrierGroupController.updateModernMobileIcons(subIds);
+
+        verify(mShadeCarrier1, times(1)).removeModernMobileView();
+
+        verify(mShadeCarrier1).addModernMobileView(any());
+        verify(mShadeCarrier2).addModernMobileView(any());
+        verify(mShadeCarrier3, never()).addModernMobileView(any());
+    }
+
+    @TestableLooper.RunWithLooper(setAsMainLooper = true)
+    @Test
+    public void testUpdateModernMobileIcons_removeSubscription() {
+        setupWithNewPipeline();
+
+        List<Integer> subIds = new ArrayList<>();
+        subIds.add(0);
+        subIds.add(1);
+        mShadeCarrierGroupController.updateModernMobileIcons(subIds);
+
+        verify(mShadeCarrier1).addModernMobileView(any());
+        verify(mShadeCarrier2).addModernMobileView(any());
+        verify(mShadeCarrier3, never()).addModernMobileView(any());
+
+        resetShadeCarriers();
+
+        subIds.remove(1);
+        mShadeCarrierGroupController.updateModernMobileIcons(subIds);
+
+        verify(mShadeCarrier1, times(1)).removeModernMobileView();
+        verify(mShadeCarrier2, times(1)).removeModernMobileView();
+
+        verify(mShadeCarrier1).addModernMobileView(any());
+        verify(mShadeCarrier2, never()).addModernMobileView(any());
+        verify(mShadeCarrier3, never()).addModernMobileView(any());
+    }
+
+    @TestableLooper.RunWithLooper(setAsMainLooper = true)
+    @Test
+    public void testUpdateModernMobileIcons_removeSubscriptionOutOfOrder() {
+        setupWithNewPipeline();
+
+        List<Integer> subIds = new ArrayList<>();
+        subIds.add(0);
+        subIds.add(1);
+        subIds.add(2);
+        mShadeCarrierGroupController.updateModernMobileIcons(subIds);
+
+        verify(mShadeCarrier1).addModernMobileView(any());
+        verify(mShadeCarrier2).addModernMobileView(any());
+        verify(mShadeCarrier3).addModernMobileView(any());
+
+        resetShadeCarriers();
+
+        subIds.remove(1);
+        mShadeCarrierGroupController.updateModernMobileIcons(subIds);
+
+        verify(mShadeCarrier1).removeModernMobileView();
+        verify(mShadeCarrier2).removeModernMobileView();
+        verify(mShadeCarrier3).removeModernMobileView();
+
+        verify(mShadeCarrier1).addModernMobileView(any());
+        verify(mShadeCarrier2, never()).addModernMobileView(any());
+        verify(mShadeCarrier3).addModernMobileView(any());
+    }
+
+    @TestableLooper.RunWithLooper(setAsMainLooper = true)
+    @Test
+    public void testProcessSubIdList_moreSubsThanSimSlots_listLimitedToMax() {
+        setupWithNewPipeline();
+
+        List<Integer> subIds = Arrays.asList(0, 1, 2, 2);
+
+        assertThat(mShadeCarrierGroupController.processSubIdList(subIds).size()).isEqualTo(3);
+    }
+
+    @TestableLooper.RunWithLooper(setAsMainLooper = true)
+    @Test
+    public void testProcessSubIdList_invalidSimSlotIndexFilteredOut() {
+        setupWithNewPipeline();
+
+        List<Integer> subIds = Arrays.asList(0, 1, -1);
+
+        List<ShadeCarrierGroupController.IconData> processedSubs =
+                mShadeCarrierGroupController.processSubIdList(subIds);
+        assertThat(processedSubs).hasSize(2);
+        assertThat(processedSubs.get(0).subId).isNotEqualTo(-1);
+        assertThat(processedSubs.get(1).subId).isNotEqualTo(-1);
+    }
+
+    @TestableLooper.RunWithLooper(setAsMainLooper = true)
+    @Test
+    public void testProcessSubIdList_indexGreaterThanSimSlotsFilteredOut() {
+        setupWithNewPipeline();
+
+        List<Integer> subIds = Arrays.asList(0, 4);
+
+        List<ShadeCarrierGroupController.IconData> processedSubs =
+                mShadeCarrierGroupController.processSubIdList(subIds);
+        assertThat(processedSubs).hasSize(1);
+        assertThat(processedSubs.get(0).subId).isNotEqualTo(4);
+    }
+
+
     @Test
     public void testOnlyInternalViewsHaveClickableListener() {
         ArgumentCaptor<View.OnClickListener> captor =
@@ -447,6 +612,12 @@
                 .isEqualTo(Settings.ACTION_WIRELESS_SETTINGS);
     }
 
+    private void resetShadeCarriers() {
+        reset(mShadeCarrier1);
+        reset(mShadeCarrier2);
+        reset(mShadeCarrier3);
+    }
+
     private class FakeSlotIndexResolver implements ShadeCarrierGroupController.SlotIndexResolver {
         public boolean overrideInvalid;
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shared/clocks/ClockRegistryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shared/clocks/ClockRegistryTest.kt
index 9495fdd..ecaf137 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shared/clocks/ClockRegistryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shared/clocks/ClockRegistryTest.kt
@@ -227,6 +227,25 @@
     }
 
     @Test
+    fun activeClockId_changeAfterPluginConnected() {
+        val plugin1 = FakeClockPlugin()
+            .addClock("clock_1", "clock 1")
+            .addClock("clock_2", "clock 2")
+
+        val plugin2 = FakeClockPlugin()
+            .addClock("clock_3", "clock 3", { mockClock })
+            .addClock("clock_4", "clock 4")
+
+        registry.applySettings(ClockSettings("clock_3", null))
+
+        pluginListener.onPluginLoaded(plugin1, mockContext, mockPluginLifecycle)
+        assertEquals(DEFAULT_CLOCK_ID, registry.activeClockId)
+
+        pluginListener.onPluginLoaded(plugin2, mockContext, mockPluginLifecycle)
+        assertEquals("clock_3", registry.activeClockId)
+    }
+
+    @Test
     fun createDefaultClock_pluginDisconnected() {
         val plugin1 = FakeClockPlugin()
             .addClock("clock_1", "clock 1")
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/icon/ui/viewbinder/NotificationIconAreaControllerViewBinderWrapperImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/icon/ui/viewbinder/NotificationIconAreaControllerViewBinderWrapperImplTest.kt
new file mode 100644
index 0000000..b8792a8
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/icon/ui/viewbinder/NotificationIconAreaControllerViewBinderWrapperImplTest.kt
@@ -0,0 +1,120 @@
+/*
+ * 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.icon.ui.viewbinder
+
+import android.testing.AndroidTestingRunner
+import android.testing.TestableLooper.RunWithLooper
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.demomode.DemoModeController
+import com.android.systemui.flags.FeatureFlags
+import com.android.systemui.plugins.DarkIconDispatcher
+import com.android.systemui.plugins.statusbar.StatusBarStateController
+import com.android.systemui.statusbar.NotificationListener
+import com.android.systemui.statusbar.NotificationMediaManager
+import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator
+import com.android.systemui.statusbar.notification.collection.provider.SectionStyleProvider
+import com.android.systemui.statusbar.notification.icon.ui.viewmodel.NotificationIconContainerAlwaysOnDisplayViewModel
+import com.android.systemui.statusbar.notification.icon.ui.viewmodel.NotificationIconContainerShelfViewModel
+import com.android.systemui.statusbar.notification.icon.ui.viewmodel.NotificationIconContainerStatusBarViewModel
+import com.android.systemui.statusbar.phone.DozeParameters
+import com.android.systemui.statusbar.phone.KeyguardBypassController
+import com.android.systemui.statusbar.phone.NotificationIconContainer
+import com.android.systemui.statusbar.phone.ScreenOffAnimationController
+import com.android.systemui.statusbar.window.StatusBarWindowController
+import com.android.systemui.util.mockito.whenever
+import com.android.wm.shell.bubbles.Bubbles
+import java.util.Optional
+import org.junit.Assert.assertFalse
+import org.junit.Assert.assertTrue
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mock
+import org.mockito.Mockito.verify
+import org.mockito.MockitoAnnotations
+
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+@RunWithLooper(setAsMainLooper = true)
+class NotificationIconAreaControllerViewBinderWrapperImplTest : SysuiTestCase() {
+    @Mock private lateinit var notifListener: NotificationListener
+    @Mock private lateinit var statusBarStateController: StatusBarStateController
+    @Mock private lateinit var wakeUpCoordinator: NotificationWakeUpCoordinator
+    @Mock private lateinit var keyguardBypassController: KeyguardBypassController
+    @Mock private lateinit var notifMediaManager: NotificationMediaManager
+    @Mock private lateinit var dozeParams: DozeParameters
+    @Mock private lateinit var sectionStyleProvider: SectionStyleProvider
+    @Mock private lateinit var darkIconDispatcher: DarkIconDispatcher
+    @Mock private lateinit var statusBarWindowController: StatusBarWindowController
+    @Mock private lateinit var screenOffAnimController: ScreenOffAnimationController
+    @Mock private lateinit var bubbles: Bubbles
+    @Mock private lateinit var demoModeController: DemoModeController
+    @Mock private lateinit var aodIcons: NotificationIconContainer
+    @Mock private lateinit var featureFlags: FeatureFlags
+
+    private val shelfViewModel = NotificationIconContainerShelfViewModel()
+    private val statusBarViewModel = NotificationIconContainerStatusBarViewModel()
+    private val aodViewModel = NotificationIconContainerAlwaysOnDisplayViewModel()
+
+    private lateinit var underTest: NotificationIconAreaControllerViewBinderWrapperImpl
+
+    @Before
+    fun setup() {
+        MockitoAnnotations.initMocks(this)
+        underTest =
+            NotificationIconAreaControllerViewBinderWrapperImpl(
+                mContext,
+                statusBarStateController,
+                wakeUpCoordinator,
+                keyguardBypassController,
+                notifMediaManager,
+                notifListener,
+                dozeParams,
+                sectionStyleProvider,
+                Optional.of(bubbles),
+                demoModeController,
+                darkIconDispatcher,
+                featureFlags,
+                statusBarWindowController,
+                screenOffAnimController,
+                shelfViewModel,
+                statusBarViewModel,
+                aodViewModel,
+            )
+    }
+
+    @Test
+    fun testNotificationIcons_settingHideIcons() {
+        underTest.settingsListener.onStatusBarIconsBehaviorChanged(true)
+        assertFalse(underTest.shouldShowLowPriorityIcons())
+    }
+
+    @Test
+    fun testNotificationIcons_settingShowIcons() {
+        underTest.settingsListener.onStatusBarIconsBehaviorChanged(false)
+        assertTrue(underTest.shouldShowLowPriorityIcons())
+    }
+
+    @Test
+    fun testAppearResetsTranslation() {
+        underTest.setupAodIcons(aodIcons)
+        whenever(dozeParams.shouldControlScreenOff()).thenReturn(false)
+        underTest.appearAodIcons()
+        verify(aodIcons).translationY = 0f
+        verify(aodIcons).alpha = 1.0f
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationIconAreaControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LegacyNotificationIconAreaControllerImplTest.java
similarity index 94%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationIconAreaControllerTest.java
rename to packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LegacyNotificationIconAreaControllerImplTest.java
index 8e1dcf0..1b8cfd4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationIconAreaControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LegacyNotificationIconAreaControllerImplTest.java
@@ -48,7 +48,7 @@
 @SmallTest
 @RunWith(AndroidTestingRunner.class)
 @TestableLooper.RunWithLooper
-public class NotificationIconAreaControllerTest extends SysuiTestCase {
+public class LegacyNotificationIconAreaControllerImplTest extends SysuiTestCase {
 
     @Mock
     private NotificationListener mListener;
@@ -70,7 +70,7 @@
     StatusBarWindowController mStatusBarWindowController;
     @Mock
     ScreenOffAnimationController mScreenOffAnimationController;
-    private NotificationIconAreaController mController;
+    private LegacyNotificationIconAreaControllerImpl mController;
     @Mock
     private Bubbles mBubbles;
     @Mock private DemoModeController mDemoModeController;
@@ -82,7 +82,7 @@
     @Before
     public void setup() {
         MockitoAnnotations.initMocks(this);
-        mController = new NotificationIconAreaController(
+        mController = new LegacyNotificationIconAreaControllerImpl(
                 mContext,
                 mStatusBarStateController,
                 mWakeUpCoordinator,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
index 0dc1d9a..6b3bd22 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
@@ -1802,6 +1802,15 @@
         assertFalse(ScrimState.UNLOCKED.mAnimateChange);
     }
 
+    @Test
+    public void testNotifScrimAlpha_1f_afterUnlockFinishedAndExpanded() {
+        mScrimController.transitionTo(ScrimState.KEYGUARD);
+        when(mKeyguardUnlockAnimationController.isPlayingCannedUnlockAnimation()).thenReturn(true);
+        mScrimController.transitionTo(ScrimState.UNLOCKED);
+        mScrimController.onUnlockAnimationFinished();
+        assertAlphaAfterExpansion(mNotificationsScrim, 1f, 1f);
+    }
+
     private void assertAlphaAfterExpansion(ScrimView scrim, float expectedAlpha, float expansion) {
         mScrimController.setRawPanelExpansionFraction(expansion);
         finishAnimationsImmediately();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/FakeMobileConnectionRepository.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/FakeMobileConnectionRepository.kt
index 50ee6a3..ff28753 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/FakeMobileConnectionRepository.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/FakeMobileConnectionRepository.kt
@@ -52,12 +52,19 @@
 
     override val cdmaRoaming = MutableStateFlow(false)
 
-    override val networkName =
-        MutableStateFlow<NetworkNameModel>(NetworkNameModel.Default("default"))
+    override val networkName: MutableStateFlow<NetworkNameModel> =
+        MutableStateFlow(NetworkNameModel.Default(DEFAULT_NETWORK_NAME))
+
+    override val carrierName: MutableStateFlow<NetworkNameModel> =
+        MutableStateFlow(NetworkNameModel.Default(DEFAULT_NETWORK_NAME))
 
     override val isAllowedDuringAirplaneMode = MutableStateFlow(false)
 
     fun setDataEnabled(enabled: Boolean) {
         _dataEnabled.value = enabled
     }
+
+    companion object {
+        const val DEFAULT_NETWORK_NAME = "default name"
+    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/FakeMobileConnectionsRepository.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/FakeMobileConnectionsRepository.kt
index 3591c17..99e4030 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/FakeMobileConnectionsRepository.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/FakeMobileConnectionsRepository.kt
@@ -75,7 +75,11 @@
 
     override fun getRepoForSubId(subId: Int): MobileConnectionRepository {
         return subIdRepos[subId]
-            ?: FakeMobileConnectionRepository(subId, tableLogBuffer).also { subIdRepos[subId] = it }
+            ?: FakeMobileConnectionRepository(
+                    subId,
+                    tableLogBuffer,
+                )
+                .also { subIdRepos[subId] = it }
     }
 
     override val defaultDataSubRatConfig = MutableStateFlow(MobileMappings.Config())
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileRepositorySwitcherTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileRepositorySwitcherTest.kt
index 5a887eb..d005972 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileRepositorySwitcherTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileRepositorySwitcherTest.kt
@@ -243,13 +243,29 @@
         private val IMMEDIATE = Dispatchers.Main.immediate
 
         private const val SUB_1_ID = 1
+        private const val SUB_1_NAME = "Carrier $SUB_1_ID"
         private val SUB_1 =
-            mock<SubscriptionInfo>().also { whenever(it.subscriptionId).thenReturn(SUB_1_ID) }
-        private val MODEL_1 = SubscriptionModel(subscriptionId = SUB_1_ID)
+            mock<SubscriptionInfo>().also {
+                whenever(it.subscriptionId).thenReturn(SUB_1_ID)
+                whenever(it.carrierName).thenReturn(SUB_1_NAME)
+            }
+        private val MODEL_1 =
+            SubscriptionModel(
+                subscriptionId = SUB_1_ID,
+                carrierName = SUB_1_NAME,
+            )
 
         private const val SUB_2_ID = 2
+        private const val SUB_2_NAME = "Carrier $SUB_2_ID"
         private val SUB_2 =
-            mock<SubscriptionInfo>().also { whenever(it.subscriptionId).thenReturn(SUB_2_ID) }
-        private val MODEL_2 = SubscriptionModel(subscriptionId = SUB_2_ID)
+            mock<SubscriptionInfo>().also {
+                whenever(it.subscriptionId).thenReturn(SUB_2_ID)
+                whenever(it.carrierName).thenReturn(SUB_2_NAME)
+            }
+        private val MODEL_2 =
+            SubscriptionModel(
+                subscriptionId = SUB_2_ID,
+                carrierName = SUB_2_NAME,
+            )
     }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionParameterizedTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionParameterizedTest.kt
index 7573b28..57f97ec 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionParameterizedTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionParameterizedTest.kt
@@ -38,7 +38,6 @@
 import kotlinx.coroutines.Job
 import kotlinx.coroutines.cancel
 import kotlinx.coroutines.flow.MutableStateFlow
-import kotlinx.coroutines.flow.collect
 import kotlinx.coroutines.launch
 import kotlinx.coroutines.test.TestScope
 import kotlinx.coroutines.test.UnconfinedTestDispatcher
@@ -140,6 +139,7 @@
             launch { conn.carrierNetworkChangeActive.collect {} }
             launch { conn.isRoaming.collect {} }
             launch { conn.networkName.collect {} }
+            launch { conn.carrierName.collect {} }
             launch { conn.isEmergencyOnly.collect {} }
             launch { conn.dataConnectionState.collect {} }
         }
@@ -163,6 +163,8 @@
                 assertThat(conn.isRoaming.value).isEqualTo(model.roaming)
                 assertThat(conn.networkName.value)
                     .isEqualTo(NetworkNameModel.IntentDerived(model.name))
+                assertThat(conn.carrierName.value)
+                    .isEqualTo(NetworkNameModel.SubscriptionDerived("${model.name} ${model.subId}"))
 
                 // TODO(b/261029387): check these once we start handling them
                 assertThat(conn.isEmergencyOnly.value).isFalse()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionsRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionsRepositoryTest.kt
index efaf152..2712b70 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionsRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionsRepositoryTest.kt
@@ -546,6 +546,7 @@
             launch { conn.carrierNetworkChangeActive.collect {} }
             launch { conn.isRoaming.collect {} }
             launch { conn.networkName.collect {} }
+            launch { conn.carrierName.collect {} }
             launch { conn.isEmergencyOnly.collect {} }
             launch { conn.dataConnectionState.collect {} }
         }
@@ -571,6 +572,8 @@
                 assertThat(conn.isRoaming.value).isEqualTo(model.roaming)
                 assertThat(conn.networkName.value)
                     .isEqualTo(NetworkNameModel.IntentDerived(model.name))
+                assertThat(conn.carrierName.value)
+                    .isEqualTo(NetworkNameModel.SubscriptionDerived("${model.name} ${model.subId}"))
 
                 // TODO(b/261029387) check these once we start handling them
                 assertThat(conn.isEmergencyOnly.value).isFalse()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/FullMobileConnectionRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/FullMobileConnectionRepositoryTest.kt
index 3dd2eaf..9c0cb17 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/FullMobileConnectionRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/FullMobileConnectionRepositoryTest.kt
@@ -26,6 +26,7 @@
 import com.android.systemui.log.table.TableLogBuffer
 import com.android.systemui.log.table.TableLogBufferFactory
 import com.android.systemui.statusbar.pipeline.mobile.data.model.NetworkNameModel
+import com.android.systemui.statusbar.pipeline.mobile.data.model.SubscriptionModel
 import com.android.systemui.statusbar.pipeline.mobile.data.repository.FakeMobileConnectionRepository
 import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionRepository
 import com.android.systemui.statusbar.pipeline.mobile.data.repository.prod.FullMobileConnectionRepository.Companion.COL_EMERGENCY
@@ -43,6 +44,7 @@
 import java.io.PrintWriter
 import java.io.StringWriter
 import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.flow.MutableStateFlow
 import kotlinx.coroutines.flow.launchIn
 import kotlinx.coroutines.flow.onEach
 import kotlinx.coroutines.test.TestScope
@@ -79,28 +81,51 @@
     private val mobileFactory = mock<MobileConnectionRepositoryImpl.Factory>()
     private val carrierMergedFactory = mock<CarrierMergedConnectionRepository.Factory>()
 
+    private val subscriptionModel =
+        MutableStateFlow(
+            SubscriptionModel(
+                subscriptionId = SUB_ID,
+                carrierName = DEFAULT_NAME,
+            )
+        )
+
     private lateinit var mobileRepo: FakeMobileConnectionRepository
     private lateinit var carrierMergedRepo: FakeMobileConnectionRepository
 
     @Before
     fun setUp() {
-        mobileRepo = FakeMobileConnectionRepository(SUB_ID, tableLogBuffer)
+        mobileRepo =
+            FakeMobileConnectionRepository(
+                SUB_ID,
+                tableLogBuffer,
+            )
         carrierMergedRepo =
-            FakeMobileConnectionRepository(SUB_ID, tableLogBuffer).apply {
-                // Mimicks the real carrier merged repository
-                this.isAllowedDuringAirplaneMode.value = true
-            }
+            FakeMobileConnectionRepository(
+                    SUB_ID,
+                    tableLogBuffer,
+                )
+                .apply {
+                    // Mimicks the real carrier merged repository
+                    this.isAllowedDuringAirplaneMode.value = true
+                }
 
         whenever(
                 mobileFactory.build(
                     eq(SUB_ID),
                     any(),
-                    eq(DEFAULT_NAME),
+                    any(),
+                    eq(DEFAULT_NAME_MODEL),
                     eq(SEP),
                 )
             )
             .thenReturn(mobileRepo)
-        whenever(carrierMergedFactory.build(eq(SUB_ID), any())).thenReturn(carrierMergedRepo)
+        whenever(
+                carrierMergedFactory.build(
+                    eq(SUB_ID),
+                    any(),
+                )
+            )
+            .thenReturn(carrierMergedRepo)
     }
 
     @Test
@@ -120,7 +145,8 @@
                 .build(
                     SUB_ID,
                     tableLogBuffer,
-                    DEFAULT_NAME,
+                    subscriptionModel,
+                    DEFAULT_NAME_MODEL,
                     SEP,
                 )
         }
@@ -138,7 +164,11 @@
 
             assertThat(underTest.activeRepo.value).isEqualTo(mobileRepo)
             assertThat(underTest.operatorAlphaShort.value).isEqualTo(nonCarrierMergedName)
-            verify(carrierMergedFactory, never()).build(SUB_ID, tableLogBuffer)
+            verify(carrierMergedFactory, never())
+                .build(
+                    SUB_ID,
+                    tableLogBuffer,
+                )
         }
 
     @Test
@@ -348,7 +378,8 @@
                 factory.build(
                     SUB_ID,
                     startingIsCarrierMerged = false,
-                    DEFAULT_NAME,
+                    subscriptionModel,
+                    DEFAULT_NAME_MODEL,
                     SEP,
                 )
 
@@ -356,7 +387,8 @@
                 factory.build(
                     SUB_ID,
                     startingIsCarrierMerged = false,
-                    DEFAULT_NAME,
+                    subscriptionModel,
+                    DEFAULT_NAME_MODEL,
                     SEP,
                 )
 
@@ -388,7 +420,8 @@
                 factory.build(
                     SUB_ID,
                     startingIsCarrierMerged = false,
-                    DEFAULT_NAME,
+                    subscriptionModel,
+                    DEFAULT_NAME_MODEL,
                     SEP,
                 )
 
@@ -397,7 +430,8 @@
                 factory.build(
                     SUB_ID,
                     startingIsCarrierMerged = true,
-                    DEFAULT_NAME,
+                    subscriptionModel,
+                    DEFAULT_NAME_MODEL,
                     SEP,
                 )
 
@@ -623,7 +657,8 @@
                 SUB_ID,
                 startingIsCarrierMerged,
                 tableLogBuffer,
-                DEFAULT_NAME,
+                subscriptionModel,
+                DEFAULT_NAME_MODEL,
                 SEP,
                 testScope.backgroundScope,
                 mobileFactory,
@@ -639,8 +674,9 @@
         val realRepo =
             MobileConnectionRepositoryImpl(
                 SUB_ID,
-                defaultNetworkName = NetworkNameModel.Default("default"),
-                networkNameSeparator = SEP,
+                subscriptionModel,
+                DEFAULT_NAME_MODEL,
+                SEP,
                 telephonyManager,
                 systemUiCarrierConfig = mock(),
                 fakeBroadcastDispatcher,
@@ -654,7 +690,8 @@
                 mobileFactory.build(
                     eq(SUB_ID),
                     any(),
-                    eq(DEFAULT_NAME),
+                    any(),
+                    eq(DEFAULT_NAME_MODEL),
                     eq(SEP),
                 )
             )
@@ -677,7 +714,13 @@
                 testScope.backgroundScope,
                 wifiRepository,
             )
-        whenever(carrierMergedFactory.build(eq(SUB_ID), any())).thenReturn(realRepo)
+        whenever(
+                carrierMergedFactory.build(
+                    eq(SUB_ID),
+                    any(),
+                )
+            )
+            .thenReturn(realRepo)
 
         return realRepo
     }
@@ -690,7 +733,8 @@
 
     private companion object {
         const val SUB_ID = 42
-        private val DEFAULT_NAME = NetworkNameModel.Default("default name")
+        private val DEFAULT_NAME = "default name"
+        private val DEFAULT_NAME_MODEL = NetworkNameModel.Default(DEFAULT_NAME)
         private const val SEP = "-"
         private const val BUFFER_SEPARATOR = "|"
     }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryTest.kt
index 1ff737b..e50e5e3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryTest.kt
@@ -62,6 +62,7 @@
 import com.android.systemui.statusbar.pipeline.mobile.data.model.ResolvedNetworkType.DefaultNetworkType
 import com.android.systemui.statusbar.pipeline.mobile.data.model.ResolvedNetworkType.OverrideNetworkType
 import com.android.systemui.statusbar.pipeline.mobile.data.model.ResolvedNetworkType.UnknownNetworkType
+import com.android.systemui.statusbar.pipeline.mobile.data.model.SubscriptionModel
 import com.android.systemui.statusbar.pipeline.mobile.data.model.SystemUiCarrierConfig
 import com.android.systemui.statusbar.pipeline.mobile.data.model.SystemUiCarrierConfigTest.Companion.configWithOverride
 import com.android.systemui.statusbar.pipeline.mobile.data.model.SystemUiCarrierConfigTest.Companion.createTestConfig
@@ -78,6 +79,7 @@
 import com.android.systemui.util.mockito.whenever
 import com.google.common.truth.Truth.assertThat
 import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.flow.MutableStateFlow
 import kotlinx.coroutines.flow.launchIn
 import kotlinx.coroutines.flow.onEach
 import kotlinx.coroutines.test.TestScope
@@ -109,6 +111,14 @@
     private val testDispatcher = UnconfinedTestDispatcher()
     private val testScope = TestScope(testDispatcher)
 
+    private val subscriptionModel: MutableStateFlow<SubscriptionModel?> =
+        MutableStateFlow(
+            SubscriptionModel(
+                subscriptionId = SUB_1_ID,
+                carrierName = DEFAULT_NAME,
+            )
+        )
+
     @Before
     fun setUp() {
         MockitoAnnotations.initMocks(this)
@@ -119,7 +129,8 @@
         underTest =
             MobileConnectionRepositoryImpl(
                 SUB_1_ID,
-                DEFAULT_NAME,
+                subscriptionModel,
+                DEFAULT_NAME_MODEL,
                 SEP,
                 telephonyManager,
                 systemUiCarrierConfig,
@@ -179,6 +190,7 @@
 
             // gsmLevel updates, no change to cdmaLevel
             strength = signalStrength(gsmLevel = 3, cdmaLevel = 2, isGsm = true)
+            callback.onSignalStrengthsChanged(strength)
 
             assertThat(latest).isEqualTo(2)
 
@@ -638,12 +650,51 @@
         }
 
     @Test
+    fun networkNameForSubId_updates() =
+        testScope.runTest {
+            var latest: NetworkNameModel? = null
+            val job = underTest.carrierName.onEach { latest = it }.launchIn(this)
+
+            subscriptionModel.value =
+                SubscriptionModel(
+                    subscriptionId = SUB_1_ID,
+                    carrierName = DEFAULT_NAME,
+                )
+
+            assertThat(latest?.name).isEqualTo(DEFAULT_NAME)
+
+            val updatedName = "Derived Carrier"
+            subscriptionModel.value =
+                SubscriptionModel(
+                    subscriptionId = SUB_1_ID,
+                    carrierName = updatedName,
+                )
+
+            assertThat(latest?.name).isEqualTo(updatedName)
+
+            job.cancel()
+        }
+
+    @Test
+    fun networkNameForSubId_defaultWhenSubscriptionModelNull() =
+        testScope.runTest {
+            var latest: NetworkNameModel? = null
+            val job = underTest.carrierName.onEach { latest = it }.launchIn(this)
+
+            subscriptionModel.value = null
+
+            assertThat(latest?.name).isEqualTo(DEFAULT_NAME)
+
+            job.cancel()
+        }
+
+    @Test
     fun networkName_default() =
         testScope.runTest {
             var latest: NetworkNameModel? = null
             val job = underTest.networkName.onEach { latest = it }.launchIn(this)
 
-            assertThat(latest).isEqualTo(DEFAULT_NAME)
+            assertThat(latest).isEqualTo(DEFAULT_NAME_MODEL)
 
             job.cancel()
         }
@@ -701,7 +752,7 @@
 
             fakeBroadcastDispatcher.sendIntentToMatchingReceiversOnly(context, intentWithoutInfo)
 
-            assertThat(latest).isEqualTo(DEFAULT_NAME)
+            assertThat(latest).isEqualTo(DEFAULT_NAME_MODEL)
 
             job.cancel()
         }
@@ -852,8 +903,9 @@
     companion object {
         private const val SUB_1_ID = 1
 
-        private val DEFAULT_NAME = NetworkNameModel.Default("default name")
-        private const val SEP = "-"
+        private val DEFAULT_NAME = "Fake Mobile Network"
+        private val DEFAULT_NAME_MODEL = NetworkNameModel.Default(DEFAULT_NAME)
+        private val SEP = "-"
 
         private const val SPN = "testSpn"
         private const val PLMN = "testPlmn"
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionTelephonySmokeTests.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionTelephonySmokeTests.kt
index 4f15aed..ea60aa7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionTelephonySmokeTests.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionTelephonySmokeTests.kt
@@ -36,6 +36,7 @@
 import com.android.systemui.statusbar.pipeline.mobile.data.model.DataConnectionState
 import com.android.systemui.statusbar.pipeline.mobile.data.model.NetworkNameModel
 import com.android.systemui.statusbar.pipeline.mobile.data.model.ResolvedNetworkType
+import com.android.systemui.statusbar.pipeline.mobile.data.model.SubscriptionModel
 import com.android.systemui.statusbar.pipeline.mobile.data.model.SystemUiCarrierConfig
 import com.android.systemui.statusbar.pipeline.mobile.data.model.SystemUiCarrierConfigTest
 import com.android.systemui.statusbar.pipeline.mobile.data.repository.FakeMobileConnectionsRepository
@@ -47,6 +48,7 @@
 import com.android.systemui.util.mockito.whenever
 import com.google.common.truth.Truth.assertThat
 import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.flow.StateFlow
 import kotlinx.coroutines.flow.launchIn
 import kotlinx.coroutines.flow.onEach
 import kotlinx.coroutines.test.TestScope
@@ -97,6 +99,7 @@
     @Mock private lateinit var telephonyManager: TelephonyManager
     @Mock private lateinit var logger: MobileInputLogger
     @Mock private lateinit var tableLogger: TableLogBuffer
+    @Mock private lateinit var subscriptionModel: StateFlow<SubscriptionModel?>
 
     private val mobileMappings = FakeMobileMappingsProxy()
     private val systemUiCarrierConfig =
@@ -113,11 +116,16 @@
         MockitoAnnotations.initMocks(this)
         whenever(telephonyManager.subscriptionId).thenReturn(SUB_1_ID)
 
-        connectionsRepo = FakeMobileConnectionsRepository(mobileMappings, tableLogger)
+        connectionsRepo =
+            FakeMobileConnectionsRepository(
+                mobileMappings,
+                tableLogger,
+            )
 
         underTest =
             MobileConnectionRepositoryImpl(
                 SUB_1_ID,
+                subscriptionModel,
                 DEFAULT_NAME,
                 SEP,
                 telephonyManager,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryTest.kt
index c8b6f13d..fd05cc4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryTest.kt
@@ -1190,30 +1190,36 @@
     companion object {
         // Subscription 1
         private const val SUB_1_ID = 1
+        private const val SUB_1_NAME = "Carrier $SUB_1_ID"
         private val GROUP_1 = ParcelUuid(UUID.randomUUID())
         private val SUB_1 =
             mock<SubscriptionInfo>().also {
                 whenever(it.subscriptionId).thenReturn(SUB_1_ID)
                 whenever(it.groupUuid).thenReturn(GROUP_1)
+                whenever(it.carrierName).thenReturn(SUB_1_NAME)
             }
         private val MODEL_1 =
             SubscriptionModel(
                 subscriptionId = SUB_1_ID,
                 groupUuid = GROUP_1,
+                carrierName = SUB_1_NAME,
             )
 
         // Subscription 2
         private const val SUB_2_ID = 2
+        private const val SUB_2_NAME = "Carrier $SUB_2_ID"
         private val GROUP_2 = ParcelUuid(UUID.randomUUID())
         private val SUB_2 =
             mock<SubscriptionInfo>().also {
                 whenever(it.subscriptionId).thenReturn(SUB_2_ID)
                 whenever(it.groupUuid).thenReturn(GROUP_2)
+                whenever(it.carrierName).thenReturn(SUB_2_NAME)
             }
         private val MODEL_2 =
             SubscriptionModel(
                 subscriptionId = SUB_2_ID,
                 groupUuid = GROUP_2,
+                carrierName = SUB_2_NAME,
             )
 
         // Subs 3 and 4 are considered to be in the same group ------------------------------------
@@ -1242,9 +1248,14 @@
 
         // Carrier merged subscription
         private const val SUB_CM_ID = 5
+        private const val SUB_CM_NAME = "Carrier $SUB_CM_ID"
         private val SUB_CM =
-            mock<SubscriptionInfo>().also { whenever(it.subscriptionId).thenReturn(SUB_CM_ID) }
-        private val MODEL_CM = SubscriptionModel(subscriptionId = SUB_CM_ID)
+            mock<SubscriptionInfo>().also {
+                whenever(it.subscriptionId).thenReturn(SUB_CM_ID)
+                whenever(it.carrierName).thenReturn(SUB_CM_NAME)
+            }
+        private val MODEL_CM =
+            SubscriptionModel(subscriptionId = SUB_CM_ID, carrierName = SUB_CM_NAME)
 
         private val WIFI_INFO_CM =
             mock<WifiInfo>().apply {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/FakeMobileIconInteractor.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/FakeMobileIconInteractor.kt
index 8d1da69..a3df785 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/FakeMobileIconInteractor.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/FakeMobileIconInteractor.kt
@@ -44,6 +44,8 @@
 
     override val mobileIsDefault = MutableStateFlow(true)
 
+    override val isSingleCarrier = MutableStateFlow(true)
+
     override val networkTypeIconGroup =
         MutableStateFlow<NetworkTypeIconModel>(
             NetworkTypeIconModel.DefaultIcon(TelephonyIcons.THREE_G)
@@ -51,6 +53,8 @@
 
     override val networkName = MutableStateFlow(NetworkNameModel.IntentDerived("demo mode"))
 
+    override val carrierName = MutableStateFlow("demo mode")
+
     private val _isEmergencyOnly = MutableStateFlow(false)
     override val isEmergencyOnly = _isEmergencyOnly
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/FakeMobileIconsInteractor.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/FakeMobileIconsInteractor.kt
index b2bbcfd..82b7ec4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/FakeMobileIconsInteractor.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/FakeMobileIconsInteractor.kt
@@ -64,6 +64,8 @@
 
     override val mobileIsDefault = MutableStateFlow(false)
 
+    override val isSingleCarrier = MutableStateFlow(true)
+
     private val _defaultMobileIconMapping = MutableStateFlow(TEST_MAPPING)
     override val defaultMobileIconMapping = _defaultMobileIconMapping
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractorTest.kt
index 58d3804..e3c59ad 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractorTest.kt
@@ -29,6 +29,7 @@
 import com.android.systemui.statusbar.pipeline.mobile.data.model.ResolvedNetworkType.CarrierMergedNetworkType
 import com.android.systemui.statusbar.pipeline.mobile.data.model.ResolvedNetworkType.DefaultNetworkType
 import com.android.systemui.statusbar.pipeline.mobile.data.model.ResolvedNetworkType.OverrideNetworkType
+import com.android.systemui.statusbar.pipeline.mobile.data.model.SubscriptionModel
 import com.android.systemui.statusbar.pipeline.mobile.data.repository.FakeMobileConnectionRepository
 import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.FakeMobileIconsInteractor.Companion.FIVE_G_OVERRIDE
 import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.FakeMobileIconsInteractor.Companion.FOUR_G
@@ -40,6 +41,7 @@
 import com.android.systemui.util.mockito.whenever
 import com.google.common.truth.Truth.assertThat
 import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.flow.MutableStateFlow
 import kotlinx.coroutines.flow.launchIn
 import kotlinx.coroutines.flow.onEach
 import kotlinx.coroutines.test.TestScope
@@ -56,6 +58,15 @@
     private lateinit var underTest: MobileIconInteractor
     private val mobileMappingsProxy = FakeMobileMappingsProxy()
     private val mobileIconsInteractor = FakeMobileIconsInteractor(mobileMappingsProxy, mock())
+
+    private val subscriptionModel =
+        MutableStateFlow(
+            SubscriptionModel(
+                subscriptionId = SUB_1_ID,
+                carrierName = DEFAULT_NAME,
+            )
+        )
+
     private val connectionRepository = FakeMobileConnectionRepository(SUB_1_ID, mock())
 
     private val testDispatcher = UnconfinedTestDispatcher()
@@ -432,7 +443,7 @@
         }
 
     @Test
-    fun networkName_usesOperatorAlphaShotWhenNonNullAndRepoIsDefault() =
+    fun networkName_usesOperatorAlphaShortWhenNonNullAndRepoIsDefault() =
         testScope.runTest {
             var latest: NetworkNameModel? = null
             val job = underTest.networkName.onEach { latest = it }.launchIn(this)
@@ -440,7 +451,7 @@
             val testOperatorName = "operatorAlphaShort"
 
             // Default network name, operator name is non-null, uses the operator name
-            connectionRepository.networkName.value = DEFAULT_NAME
+            connectionRepository.networkName.value = DEFAULT_NAME_MODEL
             connectionRepository.operatorAlphaShort.value = testOperatorName
 
             assertThat(latest).isEqualTo(NetworkNameModel.IntentDerived(testOperatorName))
@@ -448,10 +459,39 @@
             // Default network name, operator name is null, uses the default
             connectionRepository.operatorAlphaShort.value = null
 
+            assertThat(latest).isEqualTo(DEFAULT_NAME_MODEL)
+
+            // Derived network name, operator name non-null, uses the derived name
+            connectionRepository.networkName.value = DERIVED_NAME_MODEL
+            connectionRepository.operatorAlphaShort.value = testOperatorName
+
+            assertThat(latest).isEqualTo(DERIVED_NAME_MODEL)
+
+            job.cancel()
+        }
+
+    @Test
+    fun networkNameForSubId_usesOperatorAlphaShortWhenNonNullAndRepoIsDefault() =
+        testScope.runTest {
+            var latest: String? = null
+            val job = underTest.carrierName.onEach { latest = it }.launchIn(this)
+
+            val testOperatorName = "operatorAlphaShort"
+
+            // Default network name, operator name is non-null, uses the operator name
+            connectionRepository.carrierName.value = DEFAULT_NAME_MODEL
+            connectionRepository.operatorAlphaShort.value = testOperatorName
+
+            assertThat(latest).isEqualTo(testOperatorName)
+
+            // Default network name, operator name is null, uses the default
+            connectionRepository.operatorAlphaShort.value = null
+
             assertThat(latest).isEqualTo(DEFAULT_NAME)
 
             // Derived network name, operator name non-null, uses the derived name
-            connectionRepository.networkName.value = DERIVED_NAME
+            connectionRepository.carrierName.value =
+                NetworkNameModel.SubscriptionDerived(DERIVED_NAME)
             connectionRepository.operatorAlphaShort.value = testOperatorName
 
             assertThat(latest).isEqualTo(DERIVED_NAME)
@@ -460,6 +500,21 @@
         }
 
     @Test
+    fun isSingleCarrier_matchesParent() =
+        testScope.runTest {
+            var latest: Boolean? = null
+            val job = underTest.isSingleCarrier.onEach { latest = it }.launchIn(this)
+
+            mobileIconsInteractor.isSingleCarrier.value = true
+            assertThat(latest).isTrue()
+
+            mobileIconsInteractor.isSingleCarrier.value = false
+            assertThat(latest).isFalse()
+
+            job.cancel()
+        }
+
+    @Test
     fun isForceHidden_matchesParent() =
         testScope.runTest {
             var latest: Boolean? = null
@@ -494,6 +549,7 @@
             mobileIconsInteractor.activeDataConnectionHasDataEnabled,
             mobileIconsInteractor.alwaysShowDataRatIcon,
             mobileIconsInteractor.alwaysUseCdmaLevel,
+            mobileIconsInteractor.isSingleCarrier,
             mobileIconsInteractor.mobileIsDefault,
             mobileIconsInteractor.defaultMobileIconMapping,
             mobileIconsInteractor.defaultMobileIconGroup,
@@ -510,7 +566,9 @@
 
         private const val SUB_1_ID = 1
 
-        private val DEFAULT_NAME = NetworkNameModel.Default("test default name")
-        private val DERIVED_NAME = NetworkNameModel.IntentDerived("test derived name")
+        private val DEFAULT_NAME = "test default name"
+        private val DEFAULT_NAME_MODEL = NetworkNameModel.Default(DEFAULT_NAME)
+        private val DERIVED_NAME = "test derived name"
+        private val DERIVED_NAME_MODEL = NetworkNameModel.IntentDerived(DERIVED_NAME)
     }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractorTest.kt
index 1fb76b0..3e6f909 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractorTest.kt
@@ -527,6 +527,57 @@
         }
 
     @Test
+    fun isSingleCarrier_zeroSubscriptions_false() =
+        testScope.runTest {
+            var latest: Boolean? = true
+            val job = underTest.isSingleCarrier.onEach { latest = it }.launchIn(this)
+
+            connectionsRepository.setSubscriptions(emptyList())
+            assertThat(latest).isFalse()
+
+            job.cancel()
+        }
+
+    @Test
+    fun isSingleCarrier_oneSubscription_true() =
+        testScope.runTest {
+            var latest: Boolean? = false
+            val job = underTest.isSingleCarrier.onEach { latest = it }.launchIn(this)
+
+            connectionsRepository.setSubscriptions(listOf(SUB_1))
+            assertThat(latest).isTrue()
+
+            job.cancel()
+        }
+
+    @Test
+    fun isSingleCarrier_twoSubscriptions_false() =
+        testScope.runTest {
+            var latest: Boolean? = true
+            val job = underTest.isSingleCarrier.onEach { latest = it }.launchIn(this)
+
+            connectionsRepository.setSubscriptions(listOf(SUB_1, SUB_2))
+            assertThat(latest).isFalse()
+
+            job.cancel()
+        }
+
+    @Test
+    fun isSingleCarrier_updates() =
+        testScope.runTest {
+            var latest: Boolean? = false
+            val job = underTest.isSingleCarrier.onEach { latest = it }.launchIn(this)
+
+            connectionsRepository.setSubscriptions(listOf(SUB_1))
+            assertThat(latest).isTrue()
+
+            connectionsRepository.setSubscriptions(listOf(SUB_1, SUB_2))
+            assertThat(latest).isFalse()
+
+            job.cancel()
+        }
+
+    @Test
     fun mobileIsDefault_mobileFalseAndCarrierMergedFalse_false() =
         testScope.runTest {
             var latest: Boolean? = null
@@ -745,6 +796,7 @@
                 subscriptionId = subscriptionIds.first,
                 isOpportunistic = opportunistic.first,
                 groupUuid = groupUuid,
+                carrierName = "Carrier ${subscriptionIds.first}"
             )
 
         val sub2 =
@@ -752,6 +804,7 @@
                 subscriptionId = subscriptionIds.second,
                 isOpportunistic = opportunistic.second,
                 groupUuid = groupUuid,
+                carrierName = "Carrier ${opportunistic.second}"
             )
 
         return Pair(sub1, sub2)
@@ -760,11 +813,13 @@
     companion object {
 
         private const val SUB_1_ID = 1
-        private val SUB_1 = SubscriptionModel(subscriptionId = SUB_1_ID)
+        private val SUB_1 =
+            SubscriptionModel(subscriptionId = SUB_1_ID, carrierName = "Carrier $SUB_1_ID")
         private val CONNECTION_1 = FakeMobileConnectionRepository(SUB_1_ID, mock())
 
         private const val SUB_2_ID = 2
-        private val SUB_2 = SubscriptionModel(subscriptionId = SUB_2_ID)
+        private val SUB_2 =
+            SubscriptionModel(subscriptionId = SUB_2_ID, carrierName = "Carrier $SUB_2_ID")
         private val CONNECTION_2 = FakeMobileConnectionRepository(SUB_2_ID, mock())
 
         private const val SUB_3_ID = 3
@@ -773,6 +828,7 @@
                 subscriptionId = SUB_3_ID,
                 isOpportunistic = true,
                 groupUuid = ParcelUuid(UUID.randomUUID()),
+                carrierName = "Carrier $SUB_3_ID"
             )
         private val CONNECTION_3 = FakeMobileConnectionRepository(SUB_3_ID, mock())
 
@@ -782,6 +838,7 @@
                 subscriptionId = SUB_4_ID,
                 isOpportunistic = true,
                 groupUuid = ParcelUuid(UUID.randomUUID()),
+                carrierName = "Carrier $SUB_4_ID"
             )
         private val CONNECTION_4 = FakeMobileConnectionRepository(SUB_4_ID, mock())
     }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconsViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconsViewModelTest.kt
index f0458fa..065dfba 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconsViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconsViewModelTest.kt
@@ -92,15 +92,31 @@
 
             interactor.filteredSubscriptions.value =
                 listOf(
-                    SubscriptionModel(subscriptionId = 1, isOpportunistic = false),
+                    SubscriptionModel(
+                        subscriptionId = 1,
+                        isOpportunistic = false,
+                        carrierName = "Carrier 1",
+                    ),
                 )
             assertThat(latest).isEqualTo(listOf(1))
 
             interactor.filteredSubscriptions.value =
                 listOf(
-                    SubscriptionModel(subscriptionId = 2, isOpportunistic = false),
-                    SubscriptionModel(subscriptionId = 5, isOpportunistic = true),
-                    SubscriptionModel(subscriptionId = 7, isOpportunistic = true),
+                    SubscriptionModel(
+                        subscriptionId = 2,
+                        isOpportunistic = false,
+                        carrierName = "Carrier 2",
+                    ),
+                    SubscriptionModel(
+                        subscriptionId = 5,
+                        isOpportunistic = true,
+                        carrierName = "Carrier 5",
+                    ),
+                    SubscriptionModel(
+                        subscriptionId = 7,
+                        isOpportunistic = true,
+                        carrierName = "Carrier 7",
+                    ),
                 )
             assertThat(latest).isEqualTo(listOf(2, 5, 7))
 
@@ -138,6 +154,33 @@
         }
 
     @Test
+    fun caching_mobileIconInteractorIsReusedForSameSubId() =
+        testScope.runTest {
+            val interactor1 = underTest.mobileIconInteractorForSub(1)
+            val interactor2 = underTest.mobileIconInteractorForSub(1)
+
+            assertThat(interactor1).isSameInstanceAs(interactor2)
+        }
+
+    @Test
+    fun caching_invalidInteractorssAreRemovedFromCacheWhenSubDisappears() =
+        testScope.runTest {
+            // Retrieve interactors to trigger caching
+            val interactor1 = underTest.mobileIconInteractorForSub(1)
+            val interactor2 = underTest.mobileIconInteractorForSub(2)
+
+            // Both impls are cached
+            assertThat(underTest.mobileIconInteractorSubIdCache)
+                .containsExactly(1, interactor1, 2, interactor2)
+
+            // SUB_1 is removed from the list...
+            interactor.filteredSubscriptions.value = listOf(SUB_2)
+
+            // ... and dropped from the cache
+            assertThat(underTest.mobileIconInteractorSubIdCache).containsExactly(2, interactor2)
+        }
+
+    @Test
     fun firstMobileSubShowingNetworkTypeIcon_noSubs_false() =
         testScope.runTest {
             var latest: Boolean? = null
@@ -308,8 +351,23 @@
         }
 
     companion object {
-        private val SUB_1 = SubscriptionModel(subscriptionId = 1, isOpportunistic = false)
-        private val SUB_2 = SubscriptionModel(subscriptionId = 2, isOpportunistic = false)
-        private val SUB_3 = SubscriptionModel(subscriptionId = 3, isOpportunistic = false)
+        private val SUB_1 =
+            SubscriptionModel(
+                subscriptionId = 1,
+                isOpportunistic = false,
+                carrierName = "Carrier 1",
+            )
+        private val SUB_2 =
+            SubscriptionModel(
+                subscriptionId = 2,
+                isOpportunistic = false,
+                carrierName = "Carrier 2",
+            )
+        private val SUB_3 =
+            SubscriptionModel(
+                subscriptionId = 3,
+                isOpportunistic = false,
+                carrierName = "Carrier 3",
+            )
     }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogImplTest.java
index 21e4f5a..a6a2761 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogImplTest.java
@@ -32,7 +32,6 @@
 import static org.junit.Assume.assumeNotNull;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.reset;
 import static org.mockito.Mockito.times;
@@ -480,123 +479,45 @@
 
     @Test
     public void ifPortraitHalfOpen_drawVerticallyTop() {
-        DevicePostureController devicePostureController = mock(DevicePostureController.class);
-        when(devicePostureController.getDevicePosture())
-                .thenReturn(DevicePostureController.DEVICE_POSTURE_CLOSED);
-
-        VolumeDialogImpl dialog = new VolumeDialogImpl(
-                getContext(),
-                mVolumeDialogController,
-                mAccessibilityMgr,
-                mDeviceProvisionedController,
-                mConfigurationController,
-                mMediaOutputDialogFactory,
-                mVolumePanelFactory,
-                mActivityStarter,
-                mInteractionJankMonitor,
-                false,
-                mCsdWarningDialogFactory,
-                devicePostureController,
-                mTestableLooper.getLooper(),
-                mDumpManager,
-                mFeatureFlags
-        );
-        dialog.init(0 , null);
-
-        verify(devicePostureController).addCallback(any());
-        dialog.onPostureChanged(DevicePostureController.DEVICE_POSTURE_HALF_OPENED);
+        mDialog.onPostureChanged(DevicePostureController.DEVICE_POSTURE_HALF_OPENED);
         mTestableLooper.processAllMessages(); // let dismiss() finish
 
         setOrientation(Configuration.ORIENTATION_PORTRAIT);
 
         // Call show() to trigger layout updates before verifying position
-        dialog.show(SHOW_REASON_UNKNOWN);
+        mDialog.show(SHOW_REASON_UNKNOWN);
         mTestableLooper.processAllMessages(); // let show() finish before assessing its side-effect
 
-        int gravity = dialog.getWindowGravity();
+        int gravity = mDialog.getWindowGravity();
         assertEquals(Gravity.TOP, gravity & Gravity.VERTICAL_GRAVITY_MASK);
-
-        cleanUp(dialog);
     }
 
     @Test
     public void ifPortraitAndOpen_drawCenterVertically() {
-        DevicePostureController devicePostureController = mock(DevicePostureController.class);
-        when(devicePostureController.getDevicePosture())
-                .thenReturn(DevicePostureController.DEVICE_POSTURE_CLOSED);
-
-        VolumeDialogImpl dialog = new VolumeDialogImpl(
-                getContext(),
-                mVolumeDialogController,
-                mAccessibilityMgr,
-                mDeviceProvisionedController,
-                mConfigurationController,
-                mMediaOutputDialogFactory,
-                mVolumePanelFactory,
-                mActivityStarter,
-                mInteractionJankMonitor,
-                false,
-                mCsdWarningDialogFactory,
-                devicePostureController,
-                mTestableLooper.getLooper(),
-                mDumpManager,
-                mFeatureFlags
-        );
-        dialog.init(0, null);
-
-        verify(devicePostureController).addCallback(any());
-        dialog.onPostureChanged(DevicePostureController.DEVICE_POSTURE_OPENED);
+        mDialog.onPostureChanged(DevicePostureController.DEVICE_POSTURE_OPENED);
         mTestableLooper.processAllMessages(); // let dismiss() finish
 
         setOrientation(Configuration.ORIENTATION_PORTRAIT);
 
-        dialog.show(SHOW_REASON_UNKNOWN);
+        mDialog.show(SHOW_REASON_UNKNOWN);
         mTestableLooper.processAllMessages(); // let show() finish before assessing its side-effect
 
-        int gravity = dialog.getWindowGravity();
+        int gravity = mDialog.getWindowGravity();
         assertEquals(Gravity.CENTER_VERTICAL, gravity & Gravity.VERTICAL_GRAVITY_MASK);
-
-        cleanUp(dialog);
     }
 
     @Test
     public void ifLandscapeAndHalfOpen_drawCenterVertically() {
-        DevicePostureController devicePostureController = mock(DevicePostureController.class);
-        when(devicePostureController.getDevicePosture())
-                .thenReturn(DevicePostureController.DEVICE_POSTURE_CLOSED);
-
-        VolumeDialogImpl dialog = new VolumeDialogImpl(
-                getContext(),
-                mVolumeDialogController,
-                mAccessibilityMgr,
-                mDeviceProvisionedController,
-                mConfigurationController,
-                mMediaOutputDialogFactory,
-                mVolumePanelFactory,
-                mActivityStarter,
-                mInteractionJankMonitor,
-                false,
-                mCsdWarningDialogFactory,
-                devicePostureController,
-                mTestableLooper.getLooper(),
-                mDumpManager,
-                mFeatureFlags
-        );
-        dialog.init(0, null);
-
-        verify(devicePostureController).addCallback(any());
-        dialog.onPostureChanged(DevicePostureController.DEVICE_POSTURE_HALF_OPENED);
+        mDialog.onPostureChanged(DevicePostureController.DEVICE_POSTURE_HALF_OPENED);
         mTestableLooper.processAllMessages(); // let dismiss() finish
 
         setOrientation(Configuration.ORIENTATION_LANDSCAPE);
 
-        dialog.show(SHOW_REASON_UNKNOWN);
+        mDialog.show(SHOW_REASON_UNKNOWN);
         mTestableLooper.processAllMessages(); // let show() finish before assessing its side-effect
 
-        int gravity = dialog.getWindowGravity();
+        int gravity = mDialog.getWindowGravity();
         assertEquals(Gravity.CENTER_VERTICAL, gravity & Gravity.VERTICAL_GRAVITY_MASK);
-
-        cleanUp(dialog);
     }
 
     @Test
@@ -607,31 +528,9 @@
 
     @Test
     public void dialogDestroy_removesPostureControllerCallback() {
-        VolumeDialogImpl dialog = new VolumeDialogImpl(
-                getContext(),
-                mVolumeDialogController,
-                mAccessibilityMgr,
-                mDeviceProvisionedController,
-                mConfigurationController,
-                mMediaOutputDialogFactory,
-                mVolumePanelFactory,
-                mActivityStarter,
-                mInteractionJankMonitor,
-                false,
-                mCsdWarningDialogFactory,
-                mPostureController,
-                mTestableLooper.getLooper(),
-                mDumpManager,
-                mFeatureFlags
-        );
-        dialog.init(0, null);
-
         verify(mPostureController, never()).removeCallback(any());
-        dialog.destroy();
-
+        mDialog.destroy();
         verify(mPostureController).removeCallback(any());
-
-        cleanUp(dialog);
     }
 
     private void setOrientation(int orientation) {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubbleEducationControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubbleEducationControllerTest.kt
new file mode 100644
index 0000000..94ed608
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubbleEducationControllerTest.kt
@@ -0,0 +1,118 @@
+/*
+ * 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.wmshell
+
+import android.content.ContentResolver
+import android.content.Context
+import android.content.SharedPreferences
+import android.testing.AndroidTestingRunner
+import android.testing.TestableLooper
+import androidx.test.filters.SmallTest
+import com.android.systemui.model.SysUiStateTest
+import com.android.wm.shell.bubbles.Bubble
+import com.android.wm.shell.bubbles.BubbleEducationController
+import com.android.wm.shell.bubbles.PREF_MANAGED_EDUCATION
+import com.android.wm.shell.bubbles.PREF_STACK_EDUCATION
+import org.junit.Assert.assertEquals
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.ArgumentMatchers.anyBoolean
+import org.mockito.ArgumentMatchers.anyInt
+import org.mockito.ArgumentMatchers.anyString
+import org.mockito.Mockito
+
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+@TestableLooper.RunWithLooper(setAsMainLooper = true)
+class BubbleEducationControllerTest : SysUiStateTest() {
+    private val sharedPrefsEditor = Mockito.mock(SharedPreferences.Editor::class.java)
+    private val sharedPrefs = Mockito.mock(SharedPreferences::class.java)
+    private val context = Mockito.mock(Context::class.java)
+    private lateinit var sut: BubbleEducationController
+
+    @Before
+    fun setUp() {
+        Mockito.`when`(context.packageName).thenReturn("packageName")
+        Mockito.`when`(context.getSharedPreferences(anyString(), anyInt())).thenReturn(sharedPrefs)
+        Mockito.`when`(context.contentResolver)
+            .thenReturn(Mockito.mock(ContentResolver::class.java))
+        Mockito.`when`(sharedPrefs.edit()).thenReturn(sharedPrefsEditor)
+        sut = BubbleEducationController(context)
+    }
+
+    @Test
+    fun testSeenStackEducation_read() {
+        Mockito.`when`(sharedPrefs.getBoolean(anyString(), anyBoolean())).thenReturn(true)
+        assertEquals(sut.hasSeenStackEducation, true)
+        Mockito.verify(sharedPrefs).getBoolean(PREF_STACK_EDUCATION, false)
+    }
+
+    @Test
+    fun testSeenStackEducation_write() {
+        sut.hasSeenStackEducation = true
+        Mockito.verify(sharedPrefsEditor).putBoolean(PREF_STACK_EDUCATION, true)
+    }
+
+    @Test
+    fun testSeenManageEducation_read() {
+        Mockito.`when`(sharedPrefs.getBoolean(anyString(), anyBoolean())).thenReturn(true)
+        assertEquals(sut.hasSeenManageEducation, true)
+        Mockito.verify(sharedPrefs).getBoolean(PREF_MANAGED_EDUCATION, false)
+    }
+
+    @Test
+    fun testSeenManageEducation_write() {
+        sut.hasSeenManageEducation = true
+        Mockito.verify(sharedPrefsEditor).putBoolean(PREF_MANAGED_EDUCATION, true)
+    }
+
+    @Test
+    fun testShouldShowStackEducation() {
+        val bubble = Mockito.mock(Bubble::class.java)
+        // When bubble is null
+        assertEquals(sut.shouldShowStackEducation(null), false)
+        // When bubble is not conversation
+        Mockito.`when`(bubble.isConversation).thenReturn(false)
+        assertEquals(sut.shouldShowStackEducation(bubble), false)
+        // When bubble is conversation and has seen stack edu
+        Mockito.`when`(bubble.isConversation).thenReturn(true)
+        Mockito.`when`(sharedPrefs.getBoolean(anyString(), anyBoolean())).thenReturn(true)
+        assertEquals(sut.shouldShowStackEducation(bubble), false)
+        // When bubble is conversation and has not seen stack edu
+        Mockito.`when`(bubble.isConversation).thenReturn(true)
+        Mockito.`when`(sharedPrefs.getBoolean(anyString(), anyBoolean())).thenReturn(false)
+        assertEquals(sut.shouldShowStackEducation(bubble), true)
+    }
+
+    @Test
+    fun testShouldShowManageEducation() {
+        val bubble = Mockito.mock(Bubble::class.java)
+        // When bubble is null
+        assertEquals(sut.shouldShowManageEducation(null), false)
+        // When bubble is not conversation
+        Mockito.`when`(bubble.isConversation).thenReturn(false)
+        assertEquals(sut.shouldShowManageEducation(bubble), false)
+        // When bubble is conversation and has seen stack edu
+        Mockito.`when`(bubble.isConversation).thenReturn(true)
+        Mockito.`when`(sharedPrefs.getBoolean(anyString(), anyBoolean())).thenReturn(true)
+        assertEquals(sut.shouldShowManageEducation(bubble), false)
+        // When bubble is conversation and has not seen stack edu
+        Mockito.`when`(bubble.isConversation).thenReturn(true)
+        Mockito.`when`(sharedPrefs.getBoolean(anyString(), anyBoolean())).thenReturn(false)
+        assertEquals(sut.shouldShowManageEducation(bubble), true)
+    }
+}
diff --git a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
index 2d60716..a98cacd 100644
--- a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
+++ b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
@@ -3987,14 +3987,14 @@
                 mContext.enforceCallingOrSelfPermission(
                         android.Manifest.permission.BIND_APPWIDGET, null);
             } catch (SecurityException se) {
-                if (!isCallerBindAppWidgetWhiteListedLocked(packageName)) {
+                if (!isCallerBindAppWidgetAllowListedLocked(packageName)) {
                     return false;
                 }
             }
             return true;
         }
 
-        private boolean isCallerBindAppWidgetWhiteListedLocked(String packageName) {
+        private boolean isCallerBindAppWidgetAllowListedLocked(String packageName) {
             final int userId = UserHandle.getCallingUserId();
             final int packageUid = getUidForPackage(packageName, userId);
             if (packageUid < 0) {
diff --git a/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java b/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java
index 315972c..f594170 100644
--- a/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java
+++ b/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java
@@ -1225,15 +1225,13 @@
         public ContentCaptureOptions getOptions(@UserIdInt int userId,
                 @NonNull String packageName) {
             boolean isContentCaptureReceiverEnabled;
-            boolean isContentProtectionReceiverEnabled;
+            boolean isContentProtectionReceiverEnabled =
+                    isContentProtectionReceiverEnabled(userId, packageName);
             ArraySet<ComponentName> whitelistedComponents = null;
 
             synchronized (mGlobalWhitelistStateLock) {
                 isContentCaptureReceiverEnabled =
                         isContentCaptureReceiverEnabled(userId, packageName);
-                isContentProtectionReceiverEnabled =
-                        isContentProtectionReceiverEnabled(userId, packageName);
-
                 if (!isContentCaptureReceiverEnabled) {
                     // Full package is not allowlisted: check individual components next
                     whitelistedComponents = getWhitelistedComponents(userId, packageName);
diff --git a/services/core/java/com/android/server/EventLogTags.logtags b/services/core/java/com/android/server/EventLogTags.logtags
index b67e627..d47a399 100644
--- a/services/core/java/com/android/server/EventLogTags.logtags
+++ b/services/core/java/com/android/server/EventLogTags.logtags
@@ -81,7 +81,7 @@
 # when a notification has been clicked
 27520 notification_clicked (key|3),(lifespan|1),(freshness|1),(exposure|1),(rank|1),(count|1)
 # when a notification action button has been clicked
-27521 notification_action_clicked (key|3),(action_index|1),(lifespan|1),(freshness|1),(exposure|1),(rank|1),(count|1)
+27521 notification_action_clicked (key|3),(piIdentifier|3),(pendingIntent|3),(action_index|1),(lifespan|1),(freshness|1),(exposure|1),(rank|1),(count|1)
 # when a notification has been canceled
 27530 notification_canceled (key|3),(reason|1),(lifespan|1),(freshness|1),(exposure|1),(rank|1),(count|1),(listener|3)
 # replaces 27510 with a row per notification
diff --git a/services/core/java/com/android/server/VcnManagementService.java b/services/core/java/com/android/server/VcnManagementService.java
index c6e9a7d..7acca19 100644
--- a/services/core/java/com/android/server/VcnManagementService.java
+++ b/services/core/java/com/android/server/VcnManagementService.java
@@ -456,7 +456,13 @@
         final List<SubscriptionInfo> subscriptionInfos = new ArrayList<>();
         Binder.withCleanCallingIdentity(
                 () -> {
-                    subscriptionInfos.addAll(subMgr.getSubscriptionsInGroup(subscriptionGroup));
+                    List<SubscriptionInfo> subsInGroup =
+                            subMgr.getSubscriptionsInGroup(subscriptionGroup);
+                    if (subsInGroup == null) {
+                        logWtf("Received null from getSubscriptionsInGroup");
+                        subsInGroup = Collections.emptyList();
+                    }
+                    subscriptionInfos.addAll(subsInGroup);
                 });
 
         for (SubscriptionInfo info : subscriptionInfos) {
diff --git a/services/core/java/com/android/server/audio/AudioDeviceBroker.java b/services/core/java/com/android/server/audio/AudioDeviceBroker.java
index 1982784..1d670664 100644
--- a/services/core/java/com/android/server/audio/AudioDeviceBroker.java
+++ b/services/core/java/com/android/server/audio/AudioDeviceBroker.java
@@ -391,7 +391,6 @@
         final boolean wasBtScoRequested = isBluetoothScoRequested();
         CommunicationRouteClient client;
 
-
         // Save previous client route in case of failure to start BT SCO audio
         AudioDeviceAttributes prevClientDevice = null;
         boolean prevPrivileged = false;
@@ -1043,7 +1042,7 @@
         synchronized (mBluetoothAudioStateLock) {
             mBluetoothScoOn = on;
             updateAudioHalBluetoothState();
-            postUpdateCommunicationRouteClient(eventSource);
+            postUpdateCommunicationRouteClient(isBluetoothScoRequested(), eventSource);
         }
     }
 
@@ -1395,8 +1394,10 @@
                 MSG_I_SAVE_CLEAR_PREF_DEVICES_FOR_CAPTURE_PRESET, SENDMSG_QUEUE, capturePreset);
     }
 
-    /*package*/ void postUpdateCommunicationRouteClient(String eventSource) {
-        sendLMsgNoDelay(MSG_L_UPDATE_COMMUNICATION_ROUTE_CLIENT, SENDMSG_QUEUE, eventSource);
+    /*package*/ void postUpdateCommunicationRouteClient(
+            boolean wasBtScoRequested, String eventSource) {
+        sendILMsgNoDelay(MSG_IL_UPDATE_COMMUNICATION_ROUTE_CLIENT, SENDMSG_QUEUE,
+                wasBtScoRequested ? 1 : 0, eventSource);
     }
 
     /*package*/ void postSetCommunicationDeviceForClient(CommunicationDeviceInfo info) {
@@ -1708,7 +1709,8 @@
                                             : AudioSystem.STREAM_DEFAULT);
                             if (btInfo.mProfile == BluetoothProfile.LE_AUDIO
                                     || btInfo.mProfile == BluetoothProfile.HEARING_AID) {
-                                onUpdateCommunicationRouteClient("setBluetoothActiveDevice");
+                                onUpdateCommunicationRouteClient(isBluetoothScoRequested(),
+                                        "setBluetoothActiveDevice");
                             }
                         }
                     }
@@ -1762,9 +1764,11 @@
                 case MSG_I_SET_MODE_OWNER:
                     synchronized (mSetModeLock) {
                         synchronized (mDeviceStateLock) {
+                            boolean wasBtScoRequested = isBluetoothScoRequested();
                             mAudioModeOwner = (AudioModeInfo) msg.obj;
                             if (mAudioModeOwner.mMode != AudioSystem.MODE_RINGTONE) {
-                                onUpdateCommunicationRouteClient("setNewModeOwner");
+                                onUpdateCommunicationRouteClient(
+                                        wasBtScoRequested, "setNewModeOwner");
                             }
                         }
                     }
@@ -1787,10 +1791,10 @@
                     }
                     break;
 
-                case MSG_L_UPDATE_COMMUNICATION_ROUTE_CLIENT:
+                case MSG_IL_UPDATE_COMMUNICATION_ROUTE_CLIENT:
                     synchronized (mSetModeLock) {
                         synchronized (mDeviceStateLock) {
-                            onUpdateCommunicationRouteClient((String) msg.obj);
+                            onUpdateCommunicationRouteClient(msg.arg1 == 1, (String) msg.obj);
                         }
                     }
                     break;
@@ -1973,7 +1977,7 @@
     private static final int MSG_I_SAVE_CLEAR_PREF_DEVICES_FOR_CAPTURE_PRESET = 38;
 
     private static final int MSG_L_SET_COMMUNICATION_DEVICE_FOR_CLIENT = 42;
-    private static final int MSG_L_UPDATE_COMMUNICATION_ROUTE_CLIENT = 43;
+    private static final int MSG_IL_UPDATE_COMMUNICATION_ROUTE_CLIENT = 43;
     private static final int MSG_I_SCO_AUDIO_STATE_CHANGED = 44;
 
     private static final int MSG_L_BT_ACTIVE_DEVICE_CHANGE_EXT = 45;
@@ -2330,16 +2334,20 @@
      */
     // @GuardedBy("mSetModeLock")
     @GuardedBy("mDeviceStateLock")
-    private void onUpdateCommunicationRouteClient(String eventSource) {
-        updateCommunicationRoute(eventSource);
+    private void onUpdateCommunicationRouteClient(boolean wasBtScoRequested, String eventSource) {
         CommunicationRouteClient crc = topCommunicationRouteClient();
         if (AudioService.DEBUG_COMM_RTE) {
-            Log.v(TAG, "onUpdateCommunicationRouteClient, crc: "
-                    + crc + " eventSource: " + eventSource);
+            Log.v(TAG, "onUpdateCommunicationRouteClient, crc: " + crc
+                    + " wasBtScoRequested: " + wasBtScoRequested + " eventSource: " + eventSource);
         }
         if (crc != null) {
             setCommunicationRouteForClient(crc.getBinder(), crc.getUid(), crc.getDevice(),
                     BtHelper.SCO_MODE_UNDEFINED, crc.isPrivileged(), eventSource);
+        } else {
+            if (!isBluetoothScoRequested() && wasBtScoRequested) {
+                mBtHelper.stopBluetoothSco(eventSource);
+            }
+            updateCommunicationRoute(eventSource);
         }
     }
 
@@ -2403,7 +2411,11 @@
     }
 
     @GuardedBy("mDeviceStateLock")
-    private boolean communnicationDeviceCompatOn() {
+    // LE Audio: For system server (Telecom) and APKs targeting S and above, we let the audio
+    // policy routing rules select the default communication device.
+    // For older APKs, we force LE Audio headset when connected as those APKs cannot select a LE
+    // Audiodevice explicitly.
+    private boolean communnicationDeviceLeAudioCompatOn() {
         return mAudioModeOwner.mMode == AudioSystem.MODE_IN_COMMUNICATION
                 && !(CompatChanges.isChangeEnabled(
                         USE_SET_COMMUNICATION_DEVICE, mAudioModeOwner.mUid)
@@ -2411,19 +2423,25 @@
     }
 
     @GuardedBy("mDeviceStateLock")
+    // Hearing Aid: For system server (Telecom) and IN_CALL mode we let the audio
+    // policy routing rules select the default communication device.
+    // For 3p apps and IN_COMMUNICATION mode we force Hearing aid when connected to maintain
+    // backwards compatibility
+    private boolean communnicationDeviceHaCompatOn() {
+        return mAudioModeOwner.mMode == AudioSystem.MODE_IN_COMMUNICATION
+                && !(mAudioModeOwner.mUid == android.os.Process.SYSTEM_UID);
+    }
+
+    @GuardedBy("mDeviceStateLock")
     AudioDeviceAttributes getDefaultCommunicationDevice() {
-        // For system server (Telecom) and APKs targeting S and above, we let the audio
-        // policy routing rules select the default communication device.
-        // For older APKs, we force Hearing Aid or LE Audio headset when connected as
-        // those APKs cannot select a LE Audio or Hearing Aid device explicitly.
         AudioDeviceAttributes device = null;
-        if (communnicationDeviceCompatOn()) {
-            // If both LE and Hearing Aid are active (thie should not happen),
-            // priority to Hearing Aid.
+        // If both LE and Hearing Aid are active (thie should not happen),
+        // priority to Hearing Aid.
+        if (communnicationDeviceHaCompatOn()) {
             device = mDeviceInventory.getDeviceOfType(AudioSystem.DEVICE_OUT_HEARING_AID);
-            if (device == null) {
-                device = mDeviceInventory.getDeviceOfType(AudioSystem.DEVICE_OUT_BLE_HEADSET);
-            }
+        }
+        if (device == null && communnicationDeviceLeAudioCompatOn()) {
+            device = mDeviceInventory.getDeviceOfType(AudioSystem.DEVICE_OUT_BLE_HEADSET);
         }
         return device;
     }
@@ -2433,6 +2451,7 @@
             List<AudioRecordingConfiguration> recordConfigs) {
         synchronized (mSetModeLock) {
             synchronized (mDeviceStateLock) {
+                final boolean wasBtScoRequested = isBluetoothScoRequested();
                 boolean updateCommunicationRoute = false;
                 for (CommunicationRouteClient crc : mCommunicationRouteClients) {
                     boolean wasActive = crc.isActive();
@@ -2461,7 +2480,8 @@
                     }
                 }
                 if (updateCommunicationRoute) {
-                    postUpdateCommunicationRouteClient("updateCommunicationRouteClientsActivity");
+                    postUpdateCommunicationRouteClient(
+                            wasBtScoRequested, "updateCommunicationRouteClientsActivity");
                 }
             }
         }
diff --git a/services/core/java/com/android/server/audio/BtHelper.java b/services/core/java/com/android/server/audio/BtHelper.java
index 3560797..a4d26d3 100644
--- a/services/core/java/com/android/server/audio/BtHelper.java
+++ b/services/core/java/com/android/server/audio/BtHelper.java
@@ -329,7 +329,7 @@
             default:
                 break;
         }
-        if(broadcast) {
+        if (broadcast) {
             broadcastScoConnectionState(scoAudioState);
             //FIXME: this is to maintain compatibility with deprecated intent
             // AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED. Remove when appropriate.
@@ -718,8 +718,10 @@
         checkScoAudioState();
         if (state == BluetoothHeadset.STATE_AUDIO_CONNECTED) {
             // Make sure that the state transitions to CONNECTING even if we cannot initiate
-            // the connection.
-            broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_CONNECTING);
+            // the connection except if already connected internally
+            if (mScoAudioState != SCO_STATE_ACTIVE_INTERNAL) {
+                broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_CONNECTING);
+            }
             switch (mScoAudioState) {
                 case SCO_STATE_INACTIVE:
                     mScoAudioMode = scoAudioMode;
@@ -775,7 +777,7 @@
                     broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_CONNECTED);
                     break;
                 case SCO_STATE_ACTIVE_INTERNAL:
-                    Log.w(TAG, "requestScoState: already in ACTIVE mode, simply return");
+                    // Already in ACTIVE mode, simply return
                     break;
                 case SCO_STATE_ACTIVE_EXTERNAL:
                     /* Confirm SCO Audio connection to requesting app as it is already connected
diff --git a/services/core/java/com/android/server/display/DisplayDevice.java b/services/core/java/com/android/server/display/DisplayDevice.java
index d57dc47..8642fb8 100644
--- a/services/core/java/com/android/server/display/DisplayDevice.java
+++ b/services/core/java/com/android/server/display/DisplayDevice.java
@@ -16,6 +16,9 @@
 
 package com.android.server.display;
 
+import static android.view.Surface.ROTATION_270;
+import static android.view.Surface.ROTATION_90;
+
 import android.annotation.Nullable;
 import android.content.Context;
 import android.graphics.Point;
@@ -132,12 +135,15 @@
     /**
      * Returns the default size of the surface associated with the display, or null if the surface
      * is not provided for layer mirroring by SurfaceFlinger. For non virtual displays, this will
-     * be the actual display device's size.
+     * be the actual display device's size, reflecting the current rotation.
      */
     @Nullable
     public Point getDisplaySurfaceDefaultSizeLocked() {
         DisplayDeviceInfo displayDeviceInfo = getDisplayDeviceInfoLocked();
-        return new Point(displayDeviceInfo.width, displayDeviceInfo.height);
+        final boolean isRotated = mCurrentOrientation == ROTATION_90
+                || mCurrentOrientation == ROTATION_270;
+        return isRotated ? new Point(displayDeviceInfo.height, displayDeviceInfo.width)
+                : new Point(displayDeviceInfo.width, displayDeviceInfo.height);
     }
 
     /**
@@ -358,7 +364,7 @@
         }
 
         boolean isRotated = (mCurrentOrientation == Surface.ROTATION_90
-                || mCurrentOrientation == Surface.ROTATION_270);
+                || mCurrentOrientation == ROTATION_270);
         DisplayDeviceInfo info = getDisplayDeviceInfoLocked();
         viewport.deviceWidth = isRotated ? info.height : info.width;
         viewport.deviceHeight = isRotated ? info.width : info.height;
diff --git a/services/core/java/com/android/server/display/DisplayDeviceConfig.java b/services/core/java/com/android/server/display/DisplayDeviceConfig.java
index e5965ef..486cd28 100644
--- a/services/core/java/com/android/server/display/DisplayDeviceConfig.java
+++ b/services/core/java/com/android/server/display/DisplayDeviceConfig.java
@@ -2080,7 +2080,7 @@
 
     /** Loads the refresh rate profiles. */
     private void loadRefreshRateZoneProfiles(RefreshRateConfigs refreshRateConfigs) {
-        if (refreshRateConfigs == null) {
+        if (refreshRateConfigs == null || refreshRateConfigs.getRefreshRateZoneProfiles() == null) {
             return;
         }
         for (RefreshRateZone zone :
diff --git a/services/core/java/com/android/server/display/LogicalDisplay.java b/services/core/java/com/android/server/display/LogicalDisplay.java
index 4edc8bc..9c271ff5 100644
--- a/services/core/java/com/android/server/display/LogicalDisplay.java
+++ b/services/core/java/com/android/server/display/LogicalDisplay.java
@@ -441,6 +441,9 @@
             if ((deviceInfo.flags & DisplayDeviceInfo.FLAG_ALWAYS_UNLOCKED) != 0) {
                 mBaseDisplayInfo.flags |= Display.FLAG_ALWAYS_UNLOCKED;
             }
+            if ((deviceInfo.flags & DisplayDeviceInfo.FLAG_ROTATES_WITH_CONTENT) != 0) {
+                mBaseDisplayInfo.flags |= Display.FLAG_ROTATES_WITH_CONTENT;
+            }
             if ((deviceInfo.flags & DisplayDeviceInfo.FLAG_TOUCH_FEEDBACK_DISABLED) != 0) {
                 mBaseDisplayInfo.flags |= Display.FLAG_TOUCH_FEEDBACK_DISABLED;
             }
diff --git a/services/core/java/com/android/server/location/gnss/GnssListenerMultiplexer.java b/services/core/java/com/android/server/location/gnss/GnssListenerMultiplexer.java
index 567d8ac..f21a9fe 100644
--- a/services/core/java/com/android/server/location/gnss/GnssListenerMultiplexer.java
+++ b/services/core/java/com/android/server/location/gnss/GnssListenerMultiplexer.java
@@ -201,10 +201,10 @@
             this::onProviderEnabledChanged;
     private final SettingsHelper.GlobalSettingChangedListener
             mBackgroundThrottlePackageWhitelistChangedListener =
-            this::onBackgroundThrottlePackageWhitelistChanged;
+            this::onBackgroundThrottlePackageAllowlistChanged;
     private final SettingsHelper.UserSettingChangedListener
             mLocationPackageBlacklistChangedListener =
-            this::onLocationPackageBlacklistChanged;
+            this::onLocationPackageDenylistChanged;
     private final LocationPermissionsHelper.LocationPermissionsListener
             mLocationPermissionsListener =
             new LocationPermissionsHelper.LocationPermissionsListener() {
@@ -407,11 +407,11 @@
         updateRegistrations(registration -> registration.getIdentity().getUserId() == userId);
     }
 
-    private void onBackgroundThrottlePackageWhitelistChanged() {
+    private void onBackgroundThrottlePackageAllowlistChanged() {
         updateRegistrations(registration -> true);
     }
 
-    private void onLocationPackageBlacklistChanged(int userId) {
+    private void onLocationPackageDenylistChanged(int userId) {
         updateRegistrations(registration -> registration.getIdentity().getUserId() == userId);
     }
 
diff --git a/services/core/java/com/android/server/location/injector/SettingsHelper.java b/services/core/java/com/android/server/location/injector/SettingsHelper.java
index 490bfe1..32cbff8 100644
--- a/services/core/java/com/android/server/location/injector/SettingsHelper.java
+++ b/services/core/java/com/android/server/location/injector/SettingsHelper.java
@@ -93,37 +93,37 @@
             GlobalSettingChangedListener listener);
 
     /**
-     * Check if the given package is blacklisted for location access.
+     * Check if the given package is denylisted for location access.
      */
     public abstract boolean isLocationPackageBlacklisted(int userId, String packageName);
 
     /**
-     * Add a listener for changes to the location package blacklist. Callbacks occur on an
+     * Add a listener for changes to the location package denylist. Callbacks occur on an
      * unspecified thread.
      */
     public abstract void addOnLocationPackageBlacklistChangedListener(
             UserSettingChangedListener listener);
 
     /**
-     * Remove a listener for changes to the location package blacklist.
+     * Remove a listener for changes to the location package denylist.
      */
     public abstract void removeOnLocationPackageBlacklistChangedListener(
             UserSettingChangedListener listener);
 
     /**
-     * Retrieve the background throttle package whitelist.
+     * Retrieve the background throttle package allowlist.
      */
     public abstract Set<String> getBackgroundThrottlePackageWhitelist();
 
     /**
-     * Add a listener for changes to the background throttle package whitelist. Callbacks occur on
+     * Add a listener for changes to the background throttle package allowlist. Callbacks occur on
      * an unspecified thread.
      */
     public abstract void addOnBackgroundThrottlePackageWhitelistChangedListener(
             GlobalSettingChangedListener listener);
 
     /**
-     * Remove a listener for changes to the background throttle package whitelist.
+     * Remove a listener for changes to the background throttle package allowlist.
      */
     public abstract void removeOnBackgroundThrottlePackageWhitelistChangedListener(
             GlobalSettingChangedListener listener);
@@ -134,14 +134,14 @@
     public abstract boolean isGnssMeasurementsFullTrackingEnabled();
 
     /**
-     * Add a listener for changes to the background throttle package whitelist. Callbacks occur on
+     * Add a listener for changes to the background throttle package allowlist. Callbacks occur on
      * an unspecified thread.
      */
     public abstract void addOnGnssMeasurementsFullTrackingEnabledChangedListener(
             GlobalSettingChangedListener listener);
 
     /**
-     * Remove a listener for changes to the background throttle package whitelist.
+     * Remove a listener for changes to the background throttle package allowlist.
      */
     public abstract void removeOnGnssMeasurementsFullTrackingEnabledChangedListener(
             GlobalSettingChangedListener listener);
@@ -166,14 +166,14 @@
     public abstract PackageTagsList getIgnoreSettingsAllowlist();
 
     /**
-     * Add a listener for changes to the ignore settings package whitelist. Callbacks occur on an
+     * Add a listener for changes to the ignore settings package allowlist. Callbacks occur on an
      * unspecified thread.
      */
     public abstract void addIgnoreSettingsAllowlistChangedListener(
             GlobalSettingChangedListener listener);
 
     /**
-     * Remove a listener for changes to the ignore settings package whitelist.
+     * Remove a listener for changes to the ignore settings package allowlist.
      */
     public abstract void removeIgnoreSettingsAllowlistChangedListener(
             GlobalSettingChangedListener listener);
diff --git a/services/core/java/com/android/server/location/injector/SystemSettingsHelper.java b/services/core/java/com/android/server/location/injector/SystemSettingsHelper.java
index 777683e..8bb184c 100644
--- a/services/core/java/com/android/server/location/injector/SystemSettingsHelper.java
+++ b/services/core/java/com/android/server/location/injector/SystemSettingsHelper.java
@@ -65,8 +65,8 @@
  */
 public class SystemSettingsHelper extends SettingsHelper {
 
-    private static final String LOCATION_PACKAGE_BLACKLIST = "locationPackagePrefixBlacklist";
-    private static final String LOCATION_PACKAGE_WHITELIST = "locationPackagePrefixWhitelist";
+    private static final String LOCATION_PACKAGE_DENYLIST = "locationPackagePrefixBlacklist";
+    private static final String LOCATION_PACKAGE_ALLOWLIST = "locationPackagePrefixWhitelist";
 
     private static final long DEFAULT_BACKGROUND_THROTTLE_INTERVAL_MS = 30 * 60 * 1000;
     private static final long DEFAULT_BACKGROUND_THROTTLE_PROXIMITY_ALERT_INTERVAL_MS =
@@ -93,9 +93,9 @@
         mGnssMeasurementFullTracking = new BooleanGlobalSetting(context,
                 ENABLE_GNSS_RAW_MEAS_FULL_TRACKING, FgThread.getHandler());
         mLocationPackageBlacklist = new StringListCachedSecureSetting(context,
-                LOCATION_PACKAGE_BLACKLIST, FgThread.getHandler());
+                LOCATION_PACKAGE_DENYLIST, FgThread.getHandler());
         mLocationPackageWhitelist = new StringListCachedSecureSetting(context,
-                LOCATION_PACKAGE_WHITELIST, FgThread.getHandler());
+                LOCATION_PACKAGE_ALLOWLIST, FgThread.getHandler());
         mBackgroundThrottlePackageWhitelist = new StringSetCachedGlobalSetting(context,
                 LOCATION_BACKGROUND_THROTTLE_PACKAGE_WHITELIST,
                 () -> SystemConfig.getInstance().getAllowUnthrottledLocation(),
diff --git a/services/core/java/com/android/server/net/NetworkPolicyLogger.java b/services/core/java/com/android/server/net/NetworkPolicyLogger.java
index dc8fcb0..85731651 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyLogger.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyLogger.java
@@ -338,8 +338,8 @@
         return "App idle state of uid " + uid + ": " + idle;
     }
 
-    private static String getAppIdleWlChangedLog(int uid, boolean isWhitelisted) {
-        return "App idle whitelist state of uid " + uid + ": " + isWhitelisted;
+    private static String getAppIdleWlChangedLog(int uid, boolean isAllowlisted) {
+        return "App idle whitelist state of uid " + uid + ": " + isAllowlisted;
     }
 
     private static String getParoleStateChanged(boolean paroleOn) {
@@ -519,14 +519,14 @@
             data.timeStamp = System.currentTimeMillis();
         }
 
-        public void appIdleWlChanged(int uid, boolean isWhitelisted) {
+        public void appIdleWlChanged(int uid, boolean isAllowlisted) {
             final Data data = getNextSlot();
             if (data == null) return;
 
             data.reset();
             data.type = EVENT_APP_IDLE_WL_CHANGED;
             data.ifield1 = uid;
-            data.bfield1 = isWhitelisted;
+            data.bfield1 = isAllowlisted;
             data.timeStamp = System.currentTimeMillis();
         }
 
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
index c506469..52734a4 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -364,7 +364,7 @@
     private static final String TAG_NETWORK_POLICY = "network-policy";
     private static final String TAG_UID_POLICY = "uid-policy";
     private static final String TAG_APP_POLICY = "app-policy";
-    private static final String TAG_WHITELIST = "whitelist";
+    private static final String TAG_ALLOWLIST = "whitelist";
     private static final String TAG_RESTRICT_BACKGROUND = "restrict-background";
     private static final String TAG_REVOKED_RESTRICT_BACKGROUND = "revoked-restrict-background";
     private static final String TAG_XML_UTILS_INT_ARRAY = "int-array";
@@ -858,7 +858,7 @@
     }
 
     @GuardedBy("mUidRulesFirstLock")
-    private void updatePowerSaveWhitelistUL() {
+    private void updatePowerSaveAllowlistUL() {
         int[] whitelist = mPowerWhitelistManager.getWhitelistedAppIds(/* includingIdle */ false);
         mPowerSaveWhitelistExceptIdleAppIds.clear();
         for (int uid : whitelist) {
@@ -949,7 +949,7 @@
 
             synchronized (mUidRulesFirstLock) {
                 synchronized (mNetworkPoliciesSecondLock) {
-                    updatePowerSaveWhitelistUL();
+                    updatePowerSaveAllowlistUL();
                     mPowerManagerInternal = LocalServices.getService(PowerManagerInternal.class);
                     mPowerManagerInternal.registerLowPowerModeObserver(
                             new PowerManagerInternal.LowPowerModeListener() {
@@ -1193,7 +1193,7 @@
         public void onReceive(Context context, Intent intent) {
             // on background handler thread, and POWER_SAVE_WHITELIST_CHANGED is protected
             synchronized (mUidRulesFirstLock) {
-                updatePowerSaveWhitelistUL();
+                updatePowerSaveAllowlistUL();
                 updateRulesForRestrictPowerUL();
                 updateRulesForAppIdleUL();
             }
@@ -2683,7 +2683,7 @@
                         } else {
                             Slog.w(TAG, "unable to apply policy to UID " + uid + "; ignoring");
                         }
-                    } else if (TAG_WHITELIST.equals(tag)) {
+                    } else if (TAG_ALLOWLIST.equals(tag)) {
                         insideAllowlist = true;
                     } else if (TAG_RESTRICT_BACKGROUND.equals(tag) && insideAllowlist) {
                         final int uid = readIntAttribute(in, ATTR_UID);
@@ -2693,7 +2693,7 @@
                         mRestrictBackgroundAllowlistRevokedUids.put(uid, true);
                     }
                 } else if (type == END_TAG) {
-                    if (TAG_WHITELIST.equals(tag)) {
+                    if (TAG_ALLOWLIST.equals(tag)) {
                         insideAllowlist = false;
                     }
 
@@ -2869,7 +2869,7 @@
             out.endTag(null, TAG_POLICY_LIST);
 
             // write all allowlists
-            out.startTag(null, TAG_WHITELIST);
+            out.startTag(null, TAG_ALLOWLIST);
 
             // revoked restrict background allowlist
             int size = mRestrictBackgroundAllowlistRevokedUids.size();
@@ -2880,7 +2880,7 @@
                 out.endTag(null, TAG_REVOKED_RESTRICT_BACKGROUND);
             }
 
-            out.endTag(null, TAG_WHITELIST);
+            out.endTag(null, TAG_ALLOWLIST);
 
             out.endDocument();
 
@@ -4382,7 +4382,7 @@
     void updateRulesForPowerSaveUL() {
         Trace.traceBegin(Trace.TRACE_TAG_NETWORK, "updateRulesForPowerSaveUL");
         try {
-            updateRulesForWhitelistedPowerSaveUL(mRestrictPower, FIREWALL_CHAIN_POWERSAVE,
+            updateRulesForAllowlistedPowerSaveUL(mRestrictPower, FIREWALL_CHAIN_POWERSAVE,
                     mUidFirewallPowerSaveRules);
         } finally {
             Trace.traceEnd(Trace.TRACE_TAG_NETWORK);
@@ -4391,14 +4391,14 @@
 
     @GuardedBy("mUidRulesFirstLock")
     void updateRuleForRestrictPowerUL(int uid) {
-        updateRulesForWhitelistedPowerSaveUL(uid, mRestrictPower, FIREWALL_CHAIN_POWERSAVE);
+        updateRulesForAllowlistedPowerSaveUL(uid, mRestrictPower, FIREWALL_CHAIN_POWERSAVE);
     }
 
     @GuardedBy("mUidRulesFirstLock")
     void updateRulesForDeviceIdleUL() {
         Trace.traceBegin(Trace.TRACE_TAG_NETWORK, "updateRulesForDeviceIdleUL");
         try {
-            updateRulesForWhitelistedPowerSaveUL(mDeviceIdleMode, FIREWALL_CHAIN_DOZABLE,
+            updateRulesForAllowlistedPowerSaveUL(mDeviceIdleMode, FIREWALL_CHAIN_DOZABLE,
                     mUidFirewallDozableRules);
         } finally {
             Trace.traceEnd(Trace.TRACE_TAG_NETWORK);
@@ -4407,26 +4407,26 @@
 
     @GuardedBy("mUidRulesFirstLock")
     void updateRuleForDeviceIdleUL(int uid) {
-        updateRulesForWhitelistedPowerSaveUL(uid, mDeviceIdleMode, FIREWALL_CHAIN_DOZABLE);
+        updateRulesForAllowlistedPowerSaveUL(uid, mDeviceIdleMode, FIREWALL_CHAIN_DOZABLE);
     }
 
     // NOTE: since both fw_dozable and fw_powersave uses the same map
     // (mPowerSaveTempWhitelistAppIds) for allowlisting, we can reuse their logic in this method.
     @GuardedBy("mUidRulesFirstLock")
-    private void updateRulesForWhitelistedPowerSaveUL(boolean enabled, int chain,
+    private void updateRulesForAllowlistedPowerSaveUL(boolean enabled, int chain,
             SparseIntArray rules) {
         if (enabled) {
-            // Sync the whitelists before enabling the chain.  We don't care about the rules if
+            // Sync the allowlists before enabling the chain.  We don't care about the rules if
             // we are disabling the chain.
             final SparseIntArray uidRules = rules;
             uidRules.clear();
             final List<UserInfo> users = mUserManager.getUsers();
             for (int ui = users.size() - 1; ui >= 0; ui--) {
                 UserInfo user = users.get(ui);
-                updateRulesForWhitelistedAppIds(uidRules, mPowerSaveTempWhitelistAppIds, user.id);
-                updateRulesForWhitelistedAppIds(uidRules, mPowerSaveWhitelistAppIds, user.id);
+                updateRulesForAllowlistedAppIds(uidRules, mPowerSaveTempWhitelistAppIds, user.id);
+                updateRulesForAllowlistedAppIds(uidRules, mPowerSaveWhitelistAppIds, user.id);
                 if (chain == FIREWALL_CHAIN_POWERSAVE) {
-                    updateRulesForWhitelistedAppIds(uidRules,
+                    updateRulesForAllowlistedAppIds(uidRules,
                             mPowerSaveWhitelistExceptIdleAppIds, user.id);
                 }
             }
@@ -4441,7 +4441,7 @@
         }
     }
 
-    private void updateRulesForWhitelistedAppIds(final SparseIntArray uidRules,
+    private void updateRulesForAllowlistedAppIds(final SparseIntArray uidRules,
             final SparseBooleanArray whitelistedAppIds, int userId) {
         for (int i = whitelistedAppIds.size() - 1; i >= 0; --i) {
             if (whitelistedAppIds.valueAt(i)) {
@@ -4502,12 +4502,12 @@
      *        allowlisted.
      */
     @GuardedBy("mUidRulesFirstLock")
-    private boolean isWhitelistedFromPowerSaveUL(int uid, boolean deviceIdleMode) {
+    private boolean isAllowlistedFromPowerSaveUL(int uid, boolean deviceIdleMode) {
         final int appId = UserHandle.getAppId(uid);
         boolean isWhitelisted = mPowerSaveTempWhitelistAppIds.get(appId)
                 || mPowerSaveWhitelistAppIds.get(appId);
         if (!deviceIdleMode) {
-            isWhitelisted = isWhitelisted || isWhitelistedFromPowerSaveExceptIdleUL(uid);
+            isWhitelisted = isWhitelisted || isAllowlistedFromPowerSaveExceptIdleUL(uid);
         }
         return isWhitelisted;
     }
@@ -4517,7 +4517,7 @@
      * (eg: Battery Saver and app idle).
      */
     @GuardedBy("mUidRulesFirstLock")
-    private boolean isWhitelistedFromPowerSaveExceptIdleUL(int uid) {
+    private boolean isAllowlistedFromPowerSaveExceptIdleUL(int uid) {
         final int appId = UserHandle.getAppId(uid);
         return mPowerSaveWhitelistExceptIdleAppIds.get(appId);
     }
@@ -4533,9 +4533,9 @@
     // NOTE: since both fw_dozable and fw_powersave uses the same map
     // (mPowerSaveTempWhitelistAppIds) for allowlisting, we can reuse their logic in this method.
     @GuardedBy("mUidRulesFirstLock")
-    private void updateRulesForWhitelistedPowerSaveUL(int uid, boolean enabled, int chain) {
+    private void updateRulesForAllowlistedPowerSaveUL(int uid, boolean enabled, int chain) {
         if (enabled) {
-            final boolean isWhitelisted = isWhitelistedFromPowerSaveUL(uid,
+            final boolean isWhitelisted = isAllowlistedFromPowerSaveUL(uid,
                     chain == FIREWALL_CHAIN_DOZABLE);
             if (isWhitelisted || isUidForegroundOnRestrictPowerUL(uid)) {
                 setUidFirewallRuleUL(chain, uid, FIREWALL_RULE_ALLOW);
@@ -4793,7 +4793,7 @@
     }
 
     @GuardedBy("mUidRulesFirstLock")
-    private void updateRulesForTempWhitelistChangeUL(int appId) {
+    private void updateRulesForTempAllowlistChangeUL(int appId) {
         final List<UserInfo> users = mUserManager.getUsers();
         final int numUsers = users.size();
         for (int i = 0; i < numUsers; i++) {
@@ -5184,7 +5184,7 @@
         final boolean isForeground = isUidForegroundOnRestrictPowerUL(uid);
         final boolean isTop = isUidTop(uid);
 
-        final boolean isWhitelisted = isWhitelistedFromPowerSaveUL(uid, mDeviceIdleMode);
+        final boolean isWhitelisted = isAllowlistedFromPowerSaveUL(uid, mDeviceIdleMode);
 
         final int oldEffectiveBlockedReasons;
         final int newEffectiveBlockedReasons;
@@ -5207,9 +5207,9 @@
             newAllowedReasons |= (isSystem(uid) ? ALLOWED_REASON_SYSTEM : 0);
             newAllowedReasons |= (isForeground ? ALLOWED_REASON_FOREGROUND : 0);
             newAllowedReasons |= (isTop ? ALLOWED_REASON_TOP : 0);
-            newAllowedReasons |= (isWhitelistedFromPowerSaveUL(uid, true)
+            newAllowedReasons |= (isAllowlistedFromPowerSaveUL(uid, true)
                     ? ALLOWED_REASON_POWER_SAVE_ALLOWLIST : 0);
-            newAllowedReasons |= (isWhitelistedFromPowerSaveExceptIdleUL(uid)
+            newAllowedReasons |= (isAllowlistedFromPowerSaveExceptIdleUL(uid)
                     ? ALLOWED_REASON_POWER_SAVE_EXCEPT_IDLE_ALLOWLIST : 0);
             newAllowedReasons |= (uidBlockedState.allowedReasons
                     & ALLOWED_REASON_RESTRICTED_MODE_PERMISSIONS);
@@ -6122,7 +6122,7 @@
                 } else {
                     mPowerSaveTempWhitelistAppIds.delete(appId);
                 }
-                updateRulesForTempWhitelistChangeUL(appId);
+                updateRulesForTempAllowlistChangeUL(appId);
             }
         }
 
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerShellCommand.java b/services/core/java/com/android/server/net/NetworkPolicyManagerShellCommand.java
index 47bb8f0..34c8a0d 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerShellCommand.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerShellCommand.java
@@ -154,13 +154,13 @@
         }
         switch(type) {
             case "app-idle-whitelist":
-                return listAppIdleWhitelist();
+                return listAppIdleAllowlist();
             case "wifi-networks":
                 return listWifiNetworks();
             case "restrict-background-whitelist":
-                return listRestrictBackgroundWhitelist();
+                return listRestrictBackgroundAllowlist();
             case "restrict-background-blacklist":
-                return listRestrictBackgroundBlacklist();
+                return listRestrictBackgroundDenylist();
         }
         pw.println("Error: unknown list type '" + type + "'");
         return -1;
@@ -175,11 +175,11 @@
         }
         switch(type) {
             case "restrict-background-whitelist":
-                return addRestrictBackgroundWhitelist();
+                return addRestrictBackgroundAllowlist();
             case "restrict-background-blacklist":
-                return addRestrictBackgroundBlacklist();
+                return addRestrictBackgroundDenylist();
             case "app-idle-whitelist":
-                return addAppIdleWhitelist();
+                return addAppIdleAllowlist();
         }
         pw.println("Error: unknown add type '" + type + "'");
         return -1;
@@ -194,11 +194,11 @@
         }
         switch(type) {
             case "restrict-background-whitelist":
-                return removeRestrictBackgroundWhitelist();
+                return removeRestrictBackgroundAllowlist();
             case "restrict-background-blacklist":
-                return removeRestrictBackgroundBlacklist();
+                return removeRestrictBackgroundDenylist();
             case "app-idle-whitelist":
-                return removeAppIdleWhitelist();
+                return removeAppIdleAllowlist();
         }
         pw.println("Error: unknown remove type '" + type + "'");
         return -1;
@@ -241,17 +241,17 @@
         return 0;
     }
 
-    private int listRestrictBackgroundWhitelist() throws RemoteException {
+    private int listRestrictBackgroundAllowlist() throws RemoteException {
         return listUidPolicies("Restrict background whitelisted UIDs",
                 POLICY_ALLOW_METERED_BACKGROUND);
     }
 
-    private int listRestrictBackgroundBlacklist() throws RemoteException {
+    private int listRestrictBackgroundDenylist() throws RemoteException {
         return listUidPolicies("Restrict background blacklisted UIDs",
                 POLICY_REJECT_METERED_BACKGROUND);
     }
 
-    private int listAppIdleWhitelist() throws RemoteException {
+    private int listAppIdleAllowlist() throws RemoteException {
         final PrintWriter pw = getOutPrintWriter();
         final int[] uids = mInterface.getAppIdleWhitelist();
         return listUidList("App Idle whitelisted UIDs", uids);
@@ -311,23 +311,23 @@
         return 0;
     }
 
-    private int addRestrictBackgroundWhitelist() throws RemoteException {
+    private int addRestrictBackgroundAllowlist() throws RemoteException {
         return setUidPolicy(POLICY_ALLOW_METERED_BACKGROUND);
     }
 
-    private int removeRestrictBackgroundWhitelist() throws RemoteException {
+    private int removeRestrictBackgroundAllowlist() throws RemoteException {
         return resetUidPolicy("not whitelisted", POLICY_ALLOW_METERED_BACKGROUND);
     }
 
-    private int addRestrictBackgroundBlacklist() throws RemoteException {
+    private int addRestrictBackgroundDenylist() throws RemoteException {
         return setUidPolicy(POLICY_REJECT_METERED_BACKGROUND);
     }
 
-    private int removeRestrictBackgroundBlacklist() throws RemoteException {
+    private int removeRestrictBackgroundDenylist() throws RemoteException {
         return resetUidPolicy("not blacklisted", POLICY_REJECT_METERED_BACKGROUND);
     }
 
-    private int setAppIdleWhitelist(boolean isWhitelisted) {
+    private int setAppIdleAllowlist(boolean isWhitelisted) {
         final int uid = getUidFromNextArg();
         if (uid < 0) {
             return uid;
@@ -336,12 +336,12 @@
         return 0;
     }
 
-    private int addAppIdleWhitelist() throws RemoteException {
-        return setAppIdleWhitelist(true);
+    private int addAppIdleAllowlist() throws RemoteException {
+        return setAppIdleAllowlist(true);
     }
 
-    private int removeAppIdleWhitelist() throws RemoteException {
-        return setAppIdleWhitelist(false);
+    private int removeAppIdleAllowlist() throws RemoteException {
+        return setAppIdleAllowlist(false);
     }
 
     private int listWifiNetworks() {
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 15a8c0f..c24e729 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -1194,7 +1194,9 @@
                 mNotificationRecordLogger.log(
                         NotificationRecordLogger.NotificationEvent.fromAction(actionIndex,
                                 generatedByAssistant, action.isContextual()), r);
-                EventLogTags.writeNotificationActionClicked(key, actionIndex,
+                EventLogTags.writeNotificationActionClicked(key,
+                        action.actionIntent.getTarget().toString(),
+                        action.actionIntent.getIntent().toString(), actionIndex,
                         r.getLifespanMs(now), r.getFreshnessMs(now), r.getExposureMs(now),
                         nv.rank, nv.count);
                 nv.recycle();
diff --git a/services/core/java/com/android/server/pm/DexOptHelper.java b/services/core/java/com/android/server/pm/DexOptHelper.java
index 39cd888..8bd2982 100644
--- a/services/core/java/com/android/server/pm/DexOptHelper.java
+++ b/services/core/java/com/android/server/pm/DexOptHelper.java
@@ -1050,7 +1050,7 @@
                 context.unregisterReceiver(this);
                 artManager.scheduleBackgroundDexoptJob();
             }
-        }, new IntentFilter(Intent.ACTION_BOOT_COMPLETED));
+        }, new IntentFilter(Intent.ACTION_LOCKED_BOOT_COMPLETED));
     }
 
     /**
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 1567af0..189eb20 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
@@ -3055,7 +3055,7 @@
      *
      * TODO(b/155513789): Remove this in favor of collecting certificates during the original parse
      *  call if requested. Leaving this as an optional method for the caller means we have to
-     *  construct a dummy ParseInput.
+     *  construct a placeholder ParseInput.
      */
     @CheckResult
     public static ParseResult<SigningDetails> getSigningDetails(ParseInput input,
diff --git a/services/core/java/com/android/server/utils/quota/CountQuotaTracker.java b/services/core/java/com/android/server/utils/quota/CountQuotaTracker.java
index 9bf046c..3b930f7 100644
--- a/services/core/java/com/android/server/utils/quota/CountQuotaTracker.java
+++ b/services/core/java/com/android/server/utils/quota/CountQuotaTracker.java
@@ -28,6 +28,7 @@
 import android.os.Looper;
 import android.os.Message;
 import android.util.ArrayMap;
+import android.util.IndentingPrintWriter;
 import android.util.LongArrayQueue;
 import android.util.Slog;
 import android.util.TimeUtils;
@@ -36,7 +37,6 @@
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.util.IndentingPrintWriter;
 
 import java.util.function.Consumer;
 import java.util.function.Function;
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index d0f86c0..71502c6 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -4375,7 +4375,6 @@
         // Reset the last saved PiP snap fraction on removal.
         mDisplayContent.mPinnedTaskController.onActivityHidden(mActivityComponent);
         mDisplayContent.onRunningActivityChanged();
-        mWmService.mEmbeddedWindowController.onActivityRemoved(this);
         mRemovingFromDisplay = false;
     }
 
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index fcf6587..ff2c719 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -2596,9 +2596,6 @@
         final int callingUid = Binder.getCallingUid();
         final long ident = Binder.clearCallingIdentity();
         try {
-            // When a task is locked, dismiss the root pinned task if it exists
-            mRootWindowContainer.removeRootTasksInWindowingModes(WINDOWING_MODE_PINNED);
-
             getLockTaskController().startLockTaskMode(task, isSystemCaller, callingUid);
         } finally {
             Binder.restoreCallingIdentity(ident);
diff --git a/services/core/java/com/android/server/wm/AsyncRotationController.java b/services/core/java/com/android/server/wm/AsyncRotationController.java
index 2eceecc..0250475 100644
--- a/services/core/java/com/android/server/wm/AsyncRotationController.java
+++ b/services/core/java/com/android/server/wm/AsyncRotationController.java
@@ -172,10 +172,9 @@
                 if (recents != null && recents.isNavigationBarAttachedToApp()) {
                     return;
                 }
-            } else if (navigationBarCanMove || mTransitionOp == OP_CHANGE_MAY_SEAMLESS) {
+            } else if (navigationBarCanMove || mTransitionOp == OP_CHANGE_MAY_SEAMLESS
+                    || mDisplayContent.mTransitionController.mNavigationBarAttachedToApp) {
                 action = Operation.ACTION_SEAMLESS;
-            } else if (mDisplayContent.mTransitionController.mNavigationBarAttachedToApp) {
-                return;
             }
             mTargetWindowTokens.put(w.mToken, new Operation(action));
             return;
@@ -294,6 +293,11 @@
             finishOp(mTargetWindowTokens.keyAt(i));
         }
         mTargetWindowTokens.clear();
+        onAllCompleted();
+    }
+
+    private void onAllCompleted() {
+        if (DEBUG) Slog.d(TAG, "onAllCompleted");
         if (mTimeoutRunnable != null) {
             mService.mH.removeCallbacks(mTimeoutRunnable);
         }
@@ -333,7 +337,7 @@
             if (DEBUG) Slog.d(TAG, "Complete directly " + token.getTopChild());
             finishOp(token);
             if (mTargetWindowTokens.isEmpty()) {
-                if (mTimeoutRunnable != null) mService.mH.removeCallbacks(mTimeoutRunnable);
+                onAllCompleted();
                 return true;
             }
         }
@@ -411,14 +415,18 @@
         if (mDisplayContent.mInputMethodWindow == null) return;
         final WindowToken imeWindowToken = mDisplayContent.mInputMethodWindow.mToken;
         if (isTargetToken(imeWindowToken)) return;
+        hideImmediately(imeWindowToken, Operation.ACTION_TOGGLE_IME);
+        if (DEBUG) Slog.d(TAG, "hideImeImmediately " + imeWindowToken.getTopChild());
+    }
+
+    private void hideImmediately(WindowToken token, @Operation.Action int action) {
         final boolean original = mHideImmediately;
         mHideImmediately = true;
-        final Operation op = new Operation(Operation.ACTION_TOGGLE_IME);
-        mTargetWindowTokens.put(imeWindowToken, op);
-        fadeWindowToken(false /* show */, imeWindowToken, ANIMATION_TYPE_TOKEN_TRANSFORM);
-        op.mLeash = imeWindowToken.getAnimationLeash();
+        final Operation op = new Operation(action);
+        mTargetWindowTokens.put(token, op);
+        fadeWindowToken(false /* show */, token, ANIMATION_TYPE_TOKEN_TRANSFORM);
+        op.mLeash = token.getAnimationLeash();
         mHideImmediately = original;
-        if (DEBUG) Slog.d(TAG, "hideImeImmediately " + imeWindowToken.getTopChild());
     }
 
     /** Returns {@code true} if the window will rotate independently. */
@@ -428,11 +436,20 @@
                 || isTargetToken(w.mToken);
     }
 
-    /** Returns {@code true} if the controller will run fade animations on the window. */
+    /**
+     * Returns {@code true} if the rotation transition appearance of the window is currently
+     * managed by this controller.
+     */
     boolean isTargetToken(WindowToken token) {
         return mTargetWindowTokens.containsKey(token);
     }
 
+    /** Returns {@code true} if the controller will run fade animations on the window. */
+    boolean hasFadeOperation(WindowToken token) {
+        final Operation op = mTargetWindowTokens.get(token);
+        return op != null && op.mAction == Operation.ACTION_FADE;
+    }
+
     /**
      * Whether the insets animation leash should use previous position when running fade animation
      * or seamless transformation in a rotated display.
@@ -564,7 +581,18 @@
             return false;
         }
         final Operation op = mTargetWindowTokens.get(w.mToken);
-        if (op == null) return false;
+        if (op == null) {
+            // If a window becomes visible after the rotation transition is requested but before
+            // the transition is ready, hide it by an animation leash so it won't be flickering
+            // by drawing the rotated content before applying projection transaction of display.
+            // And it will fade in after the display transition is finished.
+            if (mTransitionOp == OP_APP_SWITCH && !mIsStartTransactionCommitted
+                    && canBeAsync(w.mToken)) {
+                hideImmediately(w.mToken, Operation.ACTION_FADE);
+                if (DEBUG) Slog.d(TAG, "Hide on finishDrawing " + w.mToken.getTopChild());
+            }
+            return false;
+        }
         if (DEBUG) Slog.d(TAG, "handleFinishDrawing " + w);
         if (postDrawTransaction == null || !mIsSyncDrawRequested
                 || canDrawBeforeStartTransaction(op)) {
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 81750055..6499c8c 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -6499,6 +6499,13 @@
     }
 
     /**
+     * @return whether the physical display has a fixed orientation and cannot be rotated.
+     */
+    boolean isDisplayOrientationFixed() {
+        return (mDisplayInfo.flags & Display.FLAG_ROTATES_WITH_CONTENT) == 0;
+    }
+
+    /**
      * @return whether AOD is showing on this display
      */
     boolean isAodShowing() {
diff --git a/services/core/java/com/android/server/wm/DisplayRotation.java b/services/core/java/com/android/server/wm/DisplayRotation.java
index ed3fad0..94df77a5 100644
--- a/services/core/java/com/android/server/wm/DisplayRotation.java
+++ b/services/core/java/com/android/server/wm/DisplayRotation.java
@@ -434,7 +434,8 @@
         final boolean isTv = mContext.getPackageManager().hasSystemFeature(
                 PackageManager.FEATURE_LEANBACK);
         mDefaultFixedToUserRotation =
-                (isCar || isTv || mService.mIsPc || mDisplayContent.forceDesktopMode())
+                (isCar || isTv || mService.mIsPc || mDisplayContent.forceDesktopMode()
+                        || mDisplayContent.isDisplayOrientationFixed())
                 // For debug purposes the next line turns this feature off with:
                 // $ adb shell setprop config.override_forced_orient true
                 // $ adb shell wm size reset
diff --git a/services/core/java/com/android/server/wm/EmbeddedWindowController.java b/services/core/java/com/android/server/wm/EmbeddedWindowController.java
index 98027bb..c9bae12 100644
--- a/services/core/java/com/android/server/wm/EmbeddedWindowController.java
+++ b/services/core/java/com/android/server/wm/EmbeddedWindowController.java
@@ -135,19 +135,6 @@
         return mWindowsByWindowToken.get(windowToken);
     }
 
-    void onActivityRemoved(ActivityRecord activityRecord) {
-        for (int i = mWindows.size() - 1; i >= 0; i--) {
-            final EmbeddedWindow window = mWindows.valueAt(i);
-            if (window.mHostActivityRecord == activityRecord) {
-                final WindowProcessController processController =
-                        mAtmService.getProcessController(window.mOwnerPid, window.mOwnerUid);
-                if (processController != null) {
-                    processController.removeHostActivity(activityRecord);
-                }
-            }
-        }
-    }
-
     static class EmbeddedWindow implements InputTarget {
         final IWindow mClient;
         @Nullable final WindowState mHostWindowState;
@@ -230,6 +217,13 @@
                 mInputChannel.dispose();
                 mInputChannel = null;
             }
+            if (mHostActivityRecord != null) {
+                final WindowProcessController wpc =
+                        mWmService.mAtmService.getProcessController(mOwnerPid, mOwnerUid);
+                if (wpc != null) {
+                    wpc.removeHostActivity(mHostActivityRecord);
+                }
+            }
         }
 
         @Override
diff --git a/services/core/java/com/android/server/wm/LockTaskController.java b/services/core/java/com/android/server/wm/LockTaskController.java
index 0c98fb5..830f785 100644
--- a/services/core/java/com/android/server/wm/LockTaskController.java
+++ b/services/core/java/com/android/server/wm/LockTaskController.java
@@ -19,6 +19,7 @@
 import static android.app.ActivityManager.LOCK_TASK_MODE_LOCKED;
 import static android.app.ActivityManager.LOCK_TASK_MODE_NONE;
 import static android.app.ActivityManager.LOCK_TASK_MODE_PINNED;
+import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
 import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
 import static android.content.Context.DEVICE_POLICY_SERVICE;
 import static android.content.Context.STATUS_BAR_SERVICE;
@@ -669,6 +670,9 @@
             }
         }
 
+        // When a task is locked, dismiss the root pinned task if it exists
+        mSupervisor.mRootWindowContainer.removeRootTasksInWindowingModes(WINDOWING_MODE_PINNED);
+
         // System can only initiate screen pinning, not full lock task mode
         ProtoLog.w(WM_DEBUG_LOCKTASK, "%s", isSystemCaller ? "Locking pinned" : "Locking fully");
         setLockTaskMode(task, isSystemCaller ? LOCK_TASK_MODE_PINNED : LOCK_TASK_MODE_LOCKED,
diff --git a/services/core/java/com/android/server/wm/NavBarFadeAnimationController.java b/services/core/java/com/android/server/wm/NavBarFadeAnimationController.java
index 2e5474e..79b26d2 100644
--- a/services/core/java/com/android/server/wm/NavBarFadeAnimationController.java
+++ b/services/core/java/com/android/server/wm/NavBarFadeAnimationController.java
@@ -86,7 +86,7 @@
                 ANIMATION_TYPE_TOKEN_TRANSFORM);
         if (controller == null) {
             fadeAnim.run();
-        } else if (!controller.isTargetToken(mNavigationBar.mToken)) {
+        } else if (!controller.hasFadeOperation(mNavigationBar.mToken)) {
             // If fade rotation animation is running and the nav bar is not controlled by it:
             // - For fade-in animation, defer the animation until fade rotation animation finishes.
             // - For fade-out animation, just play the animation.
diff --git a/services/core/java/com/android/server/wm/Transition.java b/services/core/java/com/android/server/wm/Transition.java
index f1fb17b..44632c9 100644
--- a/services/core/java/com/android/server/wm/Transition.java
+++ b/services/core/java/com/android/server/wm/Transition.java
@@ -1930,11 +1930,6 @@
             break;
         }
 
-        final AsyncRotationController asyncRotationController = dc.getAsyncRotationController();
-        if (asyncRotationController != null) {
-            asyncRotationController.accept(navWindow);
-        }
-
         if (animate) {
             final NavBarFadeAnimationController controller =
                     new NavBarFadeAnimationController(dc);
diff --git a/services/core/java/com/android/server/wm/TransitionController.java b/services/core/java/com/android/server/wm/TransitionController.java
index 48cca32..5b466a0 100644
--- a/services/core/java/com/android/server/wm/TransitionController.java
+++ b/services/core/java/com/android/server/wm/TransitionController.java
@@ -1124,14 +1124,15 @@
                         + "track #%d", transition.getSyncId(), track);
             }
         }
-        if (sync) {
+        transition.mAnimationTrack = track;
+        info.setTrack(track);
+        mTrackCount = Math.max(mTrackCount, track + 1);
+        if (sync && mTrackCount > 1) {
+            // If there are >1 tracks, mark as sync so that all tracks finish.
             info.setFlags(info.getFlags() | TransitionInfo.FLAG_SYNC);
             ProtoLog.v(ProtoLogGroup.WM_DEBUG_WINDOW_TRANSITIONS, "Marking #%d animation as SYNC.",
                     transition.getSyncId());
         }
-        transition.mAnimationTrack = track;
-        info.setTrack(track);
-        mTrackCount = Math.max(mTrackCount, track + 1);
     }
 
     void updateAnimatingState(SurfaceControl.Transaction t) {
diff --git a/services/core/jni/com_android_server_am_CachedAppOptimizer.cpp b/services/core/jni/com_android_server_am_CachedAppOptimizer.cpp
index c4583c2..98482b8 100644
--- a/services/core/jni/com_android_server_am_CachedAppOptimizer.cpp
+++ b/services/core/jni/com_android_server_am_CachedAppOptimizer.cpp
@@ -54,6 +54,9 @@
 using android::meminfo::ProcMemInfo;
 using namespace android::meminfo;
 
+static const size_t kPageSize = getpagesize();
+static const size_t kPageMask = ~(kPageSize - 1);
+
 #define COMPACT_ACTION_FILE_FLAG 1
 #define COMPACT_ACTION_ANON_FLAG 2
 
@@ -64,7 +67,7 @@
 #define ASYNC_RECEIVED_WHILE_FROZEN (2)
 #define TXNS_PENDING_WHILE_FROZEN (4)
 
-#define MAX_RW_COUNT (INT_MAX & PAGE_MASK)
+#define MAX_RW_COUNT (INT_MAX & kPageMask)
 
 // Defines the maximum amount of VMAs we can send per process_madvise syscall.
 // Currently this is set to UIO_MAXIOV which is the maximum segments allowed by
@@ -233,7 +236,6 @@
 // process_madvise on failure
 int madviseVmasFromBatch(unique_fd& pidfd, VmaBatch& batch, int madviseType,
                          uint64_t* outBytesProcessed) {
-    static const size_t kPageSize = getpagesize();
     if (batch.totalVmas == 0 || batch.totalBytes == 0) {
         // No VMAs in Batch, skip.
         *outBytesProcessed = 0;
diff --git a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageManagerTests.java b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageManagerTests.java
index dc92376..ba13c99 100644
--- a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageManagerTests.java
+++ b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageManagerTests.java
@@ -56,7 +56,7 @@
 import android.os.RemoteException;
 import android.os.StatFs;
 import android.os.SystemClock;
-import android.platform.test.annotations.Presubmit;
+import android.platform.test.annotations.Postsubmit;
 import android.provider.DeviceConfig;
 import android.provider.Settings;
 import android.provider.Settings.SettingNotFoundException;
@@ -93,7 +93,7 @@
 import java.util.concurrent.SynchronousQueue;
 import java.util.concurrent.TimeUnit;
 
-@Presubmit
+@Postsubmit
 public class PackageManagerTests extends AndroidTestCase {
     private static final boolean localLOGV = true;
 
diff --git a/services/tests/displayservicetests/src/com/android/server/display/DisplayDeviceTest.java b/services/tests/displayservicetests/src/com/android/server/display/DisplayDeviceTest.java
new file mode 100644
index 0000000..4fd8f26
--- /dev/null
+++ b/services/tests/displayservicetests/src/com/android/server/display/DisplayDeviceTest.java
@@ -0,0 +1,120 @@
+/*
+ * 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.server.display;
+
+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;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.graphics.Point;
+import android.graphics.Rect;
+import android.platform.test.annotations.Presubmit;
+import android.view.SurfaceControl;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.SmallTest;
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+/**
+ * Tests for the {@link DisplayDevice} class.
+ *
+ * Build/Install/Run:
+ * atest DisplayServicesTests:DisplayDeviceTest
+ */
+@SmallTest
+@Presubmit
+@RunWith(AndroidJUnit4.class)
+public class DisplayDeviceTest {
+    private final DisplayDeviceInfo mDisplayDeviceInfo = new DisplayDeviceInfo();
+    private static final int WIDTH = 500;
+    private static final int HEIGHT = 900;
+    private static final Point PORTRAIT_SIZE = new Point(WIDTH, HEIGHT);
+    private static final Point LANDSCAPE_SIZE = new Point(HEIGHT, WIDTH);
+
+    @Mock
+    private SurfaceControl.Transaction mMockTransaction;
+
+    @Before
+    public void setup() {
+        MockitoAnnotations.initMocks(this);
+        mDisplayDeviceInfo.width = WIDTH;
+        mDisplayDeviceInfo.height = HEIGHT;
+        mDisplayDeviceInfo.rotation = ROTATION_0;
+    }
+
+    @Test
+    public void testGetDisplaySurfaceDefaultSizeLocked_notRotated() {
+        DisplayDevice displayDevice = new FakeDisplayDevice(mDisplayDeviceInfo);
+        assertThat(displayDevice.getDisplaySurfaceDefaultSizeLocked()).isEqualTo(PORTRAIT_SIZE);
+    }
+
+    @Test
+    public void testGetDisplaySurfaceDefaultSizeLocked_rotation0() {
+        DisplayDevice displayDevice = new FakeDisplayDevice(mDisplayDeviceInfo);
+        displayDevice.setProjectionLocked(mMockTransaction, ROTATION_0, new Rect(), new Rect());
+        assertThat(displayDevice.getDisplaySurfaceDefaultSizeLocked()).isEqualTo(PORTRAIT_SIZE);
+    }
+
+    @Test
+    public void testGetDisplaySurfaceDefaultSizeLocked_rotation90() {
+        DisplayDevice displayDevice = new FakeDisplayDevice(mDisplayDeviceInfo);
+        displayDevice.setProjectionLocked(mMockTransaction, ROTATION_90, new Rect(), new Rect());
+        assertThat(displayDevice.getDisplaySurfaceDefaultSizeLocked()).isEqualTo(LANDSCAPE_SIZE);
+    }
+
+    @Test
+    public void testGetDisplaySurfaceDefaultSizeLocked_rotation180() {
+        DisplayDevice displayDevice = new FakeDisplayDevice(mDisplayDeviceInfo);
+        displayDevice.setProjectionLocked(mMockTransaction, ROTATION_180, new Rect(), new Rect());
+        assertThat(displayDevice.getDisplaySurfaceDefaultSizeLocked()).isEqualTo(PORTRAIT_SIZE);
+    }
+
+    @Test
+    public void testGetDisplaySurfaceDefaultSizeLocked_rotation270() {
+        DisplayDevice displayDevice = new FakeDisplayDevice(mDisplayDeviceInfo);
+        displayDevice.setProjectionLocked(mMockTransaction, ROTATION_270, new Rect(), new Rect());
+        assertThat(displayDevice.getDisplaySurfaceDefaultSizeLocked()).isEqualTo(LANDSCAPE_SIZE);
+    }
+
+    private static class FakeDisplayDevice extends DisplayDevice {
+        private final DisplayDeviceInfo mDisplayDeviceInfo;
+
+        FakeDisplayDevice(DisplayDeviceInfo displayDeviceInfo) {
+            super(null, null, "", InstrumentationRegistry.getInstrumentation().getContext());
+            mDisplayDeviceInfo = displayDeviceInfo;
+        }
+
+        @Override
+        public boolean hasStableUniqueId() {
+            return false;
+        }
+
+        @Override
+        public DisplayDeviceInfo getDisplayDeviceInfoLocked() {
+            return mDisplayDeviceInfo;
+        }
+    }
+}
diff --git a/services/tests/displayservicetests/src/com/android/server/display/DisplayManagerServiceTest.java b/services/tests/displayservicetests/src/com/android/server/display/DisplayManagerServiceTest.java
index d16c9c5..50cf169 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/DisplayManagerServiceTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/DisplayManagerServiceTest.java
@@ -477,6 +477,41 @@
     }
 
     @Test
+    public void testCreateVirtualRotatesWithContent() throws RemoteException {
+        DisplayManagerService displayManager =
+                new DisplayManagerService(mContext, mBasicInjector);
+        registerDefaultDisplays(displayManager);
+
+        // This is effectively the DisplayManager service published to ServiceManager.
+        DisplayManagerService.BinderService bs = displayManager.new BinderService();
+
+        String uniqueId = "uniqueId --- Rotates with Content Test";
+        int width = 600;
+        int height = 800;
+        int dpi = 320;
+        int flags = DisplayManager.VIRTUAL_DISPLAY_FLAG_ROTATES_WITH_CONTENT;
+
+        when(mMockAppToken.asBinder()).thenReturn(mMockAppToken);
+        final VirtualDisplayConfig.Builder builder = new VirtualDisplayConfig.Builder(
+                VIRTUAL_DISPLAY_NAME, width, height, dpi);
+        builder.setFlags(flags);
+        builder.setUniqueId(uniqueId);
+        int displayId = bs.createVirtualDisplay(builder.build(), /* callback= */ mMockAppToken,
+                /* projection= */ null, PACKAGE_NAME);
+        verify(mMockProjectionService, never()).setContentRecordingSession(any(),
+                nullable(IMediaProjection.class));
+
+        displayManager.performTraversalInternal(mock(SurfaceControl.Transaction.class));
+
+        // flush the handler
+        displayManager.getDisplayHandler().runWithScissors(() -> {}, /* now= */ 0);
+
+        DisplayDeviceInfo ddi = displayManager.getDisplayDeviceInfoInternal(displayId);
+        assertNotNull(ddi);
+        assertTrue((ddi.flags & DisplayDeviceInfo.FLAG_ROTATES_WITH_CONTENT) != 0);
+    }
+
+    @Test
     public void testCreateVirtualDisplayOwnFocus() throws RemoteException {
         DisplayManagerService displayManager =
                 new DisplayManagerService(mContext, mBasicInjector);
diff --git a/services/tests/displayservicetests/src/com/android/server/display/LogicalDisplayTest.java b/services/tests/displayservicetests/src/com/android/server/display/LogicalDisplayTest.java
index 2065479..c0128ae 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/LogicalDisplayTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/LogicalDisplayTest.java
@@ -69,7 +69,6 @@
         mDisplayDeviceInfo.copyFrom(new DisplayDeviceInfo());
         mDisplayDeviceInfo.width = DISPLAY_WIDTH;
         mDisplayDeviceInfo.height = DISPLAY_HEIGHT;
-        mDisplayDeviceInfo.flags = DisplayDeviceInfo.FLAG_ROTATES_WITH_CONTENT;
         mDisplayDeviceInfo.touch = DisplayDeviceInfo.TOUCH_INTERNAL;
         mDisplayDeviceInfo.modeId = MODE_ID;
         mDisplayDeviceInfo.supportedModes = new Display.Mode[] {new Display.Mode(MODE_ID,
@@ -112,8 +111,18 @@
         mLogicalDisplay.configureDisplayLocked(t, mDisplayDevice, false);
         assertEquals(expectedPosition, mLogicalDisplay.getDisplayPosition());
 
-        expectedPosition.set(40, -20);
         DisplayInfo displayInfo = new DisplayInfo();
+        displayInfo.logicalWidth = DISPLAY_WIDTH;
+        displayInfo.logicalHeight = DISPLAY_HEIGHT;
+        // Rotation doesn't matter when the FLAG_ROTATES_WITH_CONTENT is absent.
+        displayInfo.rotation = Surface.ROTATION_90;
+        mLogicalDisplay.setDisplayInfoOverrideFromWindowManagerLocked(displayInfo);
+        mLogicalDisplay.configureDisplayLocked(t, mDisplayDevice, false);
+        assertEquals(expectedPosition, mLogicalDisplay.getDisplayPosition());
+
+        expectedPosition.set(40, -20);
+        mDisplayDeviceInfo.flags = DisplayDeviceInfo.FLAG_ROTATES_WITH_CONTENT;
+        mLogicalDisplay.updateLocked(mDeviceRepo);
         displayInfo.logicalWidth = DISPLAY_HEIGHT;
         displayInfo.logicalHeight = DISPLAY_WIDTH;
         displayInfo.rotation = Surface.ROTATION_90;
diff --git a/services/tests/servicestests/src/com/android/server/CertBlacklisterTest.java b/services/tests/servicestests/src/com/android/server/CertBlacklisterTest.java
index 90df786..45e7f35 100644
--- a/services/tests/servicestests/src/com/android/server/CertBlacklisterTest.java
+++ b/services/tests/servicestests/src/com/android/server/CertBlacklisterTest.java
@@ -34,10 +34,10 @@
  */
 public class CertBlacklisterTest extends AndroidTestCase {
 
-    private static final String BLACKLIST_ROOT = System.getenv("ANDROID_DATA") + "/misc/keychain/";
+    private static final String DENYLIST_ROOT = System.getenv("ANDROID_DATA") + "/misc/keychain/";
 
-    public static final String PUBKEY_PATH = BLACKLIST_ROOT + "pubkey_blacklist.txt";
-    public static final String SERIAL_PATH = BLACKLIST_ROOT + "serial_blacklist.txt";
+    public static final String PUBKEY_PATH = DENYLIST_ROOT + "pubkey_blacklist.txt";
+    public static final String SERIAL_PATH = DENYLIST_ROOT + "serial_blacklist.txt";
 
     public static final String PUBKEY_KEY = "pubkey_blacklist";
     public static final String SERIAL_KEY = "serial_blacklist";
diff --git a/services/tests/servicestests/src/com/android/server/integrity/AppIntegrityManagerServiceImplTest.java b/services/tests/servicestests/src/com/android/server/integrity/AppIntegrityManagerServiceImplTest.java
index 9ca84d3..ce15c6d 100644
--- a/services/tests/servicestests/src/com/android/server/integrity/AppIntegrityManagerServiceImplTest.java
+++ b/services/tests/servicestests/src/com/android/server/integrity/AppIntegrityManagerServiceImplTest.java
@@ -218,7 +218,7 @@
 
     @Test
     public void updateRuleSet_notSystemApp() throws Exception {
-        whitelistUsAsRuleProvider();
+        allowlistUsAsRuleProvider();
         makeUsSystemApp(false);
         Rule rule =
                 new Rule(
@@ -237,7 +237,7 @@
 
     @Test
     public void updateRuleSet_authorized() throws Exception {
-        whitelistUsAsRuleProvider();
+        allowlistUsAsRuleProvider();
         makeUsSystemApp();
         Rule rule =
                 new Rule(
@@ -251,7 +251,7 @@
 
     @Test
     public void updateRuleSet_correctMethodCall() throws Exception {
-        whitelistUsAsRuleProvider();
+        allowlistUsAsRuleProvider();
         makeUsSystemApp();
         IntentSender mockReceiver = mock(IntentSender.class);
         List<Rule> rules =
@@ -271,7 +271,7 @@
 
     @Test
     public void updateRuleSet_fail() throws Exception {
-        whitelistUsAsRuleProvider();
+        allowlistUsAsRuleProvider();
         makeUsSystemApp();
         doThrow(new IOException()).when(mIntegrityFileManager).writeRules(any(), any(), any());
         IntentSender mockReceiver = mock(IntentSender.class);
@@ -292,7 +292,7 @@
 
     @Test
     public void broadcastReceiverRegistration() throws Exception {
-        whitelistUsAsRuleProvider();
+        allowlistUsAsRuleProvider();
         makeUsSystemApp();
         ArgumentCaptor<IntentFilter> intentFilterCaptor =
                 ArgumentCaptor.forClass(IntentFilter.class);
@@ -308,7 +308,7 @@
 
     @Test
     public void handleBroadcast_correctArgs() throws Exception {
-        whitelistUsAsRuleProvider();
+        allowlistUsAsRuleProvider();
         makeUsSystemApp();
         ArgumentCaptor<BroadcastReceiver> broadcastReceiverCaptor =
                 ArgumentCaptor.forClass(BroadcastReceiver.class);
@@ -345,7 +345,7 @@
 
     @Test
     public void handleBroadcast_correctArgs_multipleCerts() throws Exception {
-        whitelistUsAsRuleProvider();
+        allowlistUsAsRuleProvider();
         makeUsSystemApp();
         ArgumentCaptor<BroadcastReceiver> broadcastReceiverCaptor =
                 ArgumentCaptor.forClass(BroadcastReceiver.class);
@@ -368,7 +368,7 @@
 
     @Test
     public void handleBroadcast_correctArgs_sourceStamp() throws Exception {
-        whitelistUsAsRuleProvider();
+        allowlistUsAsRuleProvider();
         makeUsSystemApp();
         ArgumentCaptor<BroadcastReceiver> broadcastReceiverCaptor =
                 ArgumentCaptor.forClass(BroadcastReceiver.class);
@@ -393,7 +393,7 @@
 
     @Test
     public void handleBroadcast_allow() throws Exception {
-        whitelistUsAsRuleProvider();
+        allowlistUsAsRuleProvider();
         makeUsSystemApp();
         ArgumentCaptor<BroadcastReceiver> broadcastReceiverCaptor =
                 ArgumentCaptor.forClass(BroadcastReceiver.class);
@@ -412,7 +412,7 @@
 
     @Test
     public void handleBroadcast_reject() throws Exception {
-        whitelistUsAsRuleProvider();
+        allowlistUsAsRuleProvider();
         makeUsSystemApp();
         ArgumentCaptor<BroadcastReceiver> broadcastReceiverCaptor =
                 ArgumentCaptor.forClass(BroadcastReceiver.class);
@@ -438,7 +438,7 @@
 
     @Test
     public void handleBroadcast_notInitialized() throws Exception {
-        whitelistUsAsRuleProvider();
+        allowlistUsAsRuleProvider();
         makeUsSystemApp();
         when(mIntegrityFileManager.initialized()).thenReturn(false);
         ArgumentCaptor<BroadcastReceiver> broadcastReceiverCaptor =
@@ -459,7 +459,7 @@
 
     @Test
     public void verifierAsInstaller_skipIntegrityVerification() throws Exception {
-        whitelistUsAsRuleProvider();
+        allowlistUsAsRuleProvider();
         makeUsSystemApp();
         setIntegrityCheckIncludesRuleProvider(false);
         ArgumentCaptor<BroadcastReceiver> broadcastReceiverCaptor =
@@ -480,7 +480,7 @@
 
     @Test
     public void getCurrentRules() throws Exception {
-        whitelistUsAsRuleProvider();
+        allowlistUsAsRuleProvider();
         makeUsSystemApp();
         Rule rule = new Rule(IntegrityFormula.Application.packageNameEquals("package"), Rule.DENY);
         when(mIntegrityFileManager.readRules(any())).thenReturn(Arrays.asList(rule));
@@ -490,7 +490,7 @@
 
     @Test
     public void getWhitelistedRuleProviders_returnsEmptyForNonSystemApps() throws Exception {
-        whitelistUsAsRuleProvider();
+        allowlistUsAsRuleProvider();
         makeUsSystemApp(false);
 
         assertThat(mService.getWhitelistedRuleProviders()).isEmpty();
@@ -498,13 +498,13 @@
 
     @Test
     public void getWhitelistedRuleProviders() throws Exception {
-        whitelistUsAsRuleProvider();
+        allowlistUsAsRuleProvider();
         makeUsSystemApp();
 
         assertThat(mService.getWhitelistedRuleProviders()).containsExactly(TEST_FRAMEWORK_PACKAGE);
     }
 
-    private void whitelistUsAsRuleProvider() {
+    private void allowlistUsAsRuleProvider() {
         Resources mockResources = mock(Resources.class);
         when(mockResources.getStringArray(R.array.config_integrityRuleProviderPackages))
                 .thenReturn(new String[] {TEST_FRAMEWORK_PACKAGE});
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/KeySyncTaskTest.java b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/KeySyncTaskTest.java
index cc1100b..5654c89 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/KeySyncTaskTest.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/KeySyncTaskTest.java
@@ -469,7 +469,7 @@
         verify(mTestOnlyInsecureCertificateHelper, atLeast(1))
                 .isTestOnlyCertificateAlias(eq(TEST_ROOT_CERT_ALIAS));
 
-        // no whitelists check
+        // no allowlists check
         verify(mTestOnlyInsecureCertificateHelper, never())
                 .doesCredentialSupportInsecureMode(anyInt(), any());
         verify(mTestOnlyInsecureCertificateHelper, never())
diff --git a/services/tests/servicestests/src/com/android/server/os/BugreportManagerServiceImplTest.java b/services/tests/servicestests/src/com/android/server/os/BugreportManagerServiceImplTest.java
index 24029b1..fc27edc 100644
--- a/services/tests/servicestests/src/com/android/server/os/BugreportManagerServiceImplTest.java
+++ b/services/tests/servicestests/src/com/android/server/os/BugreportManagerServiceImplTest.java
@@ -35,6 +35,7 @@
 import androidx.test.platform.app.InstrumentationRegistry;
 import androidx.test.runner.AndroidJUnit4;
 
+import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -68,6 +69,27 @@
         mBugreportFileManager = new BugreportManagerServiceImpl.BugreportFileManager();
     }
 
+    @After
+    public void tearDown() throws Exception {
+        // Changes to RoleManager persist between tests, so we need to clear out any funny
+        // business we did in previous tests.
+        RoleManager roleManager = mContext.getSystemService(RoleManager.class);
+        CallbackFuture future = new CallbackFuture();
+        runWithShellPermissionIdentity(
+                () -> {
+                    roleManager.setBypassingRoleQualification(false);
+                    roleManager.removeRoleHolderAsUser(
+                            "android.app.role.SYSTEM_AUTOMOTIVE_PROJECTION",
+                            mContext.getPackageName(),
+                            /* flags= */ 0,
+                            Process.myUserHandle(),
+                            mContext.getMainExecutor(),
+                            future);
+                });
+
+        assertThat(future.get()).isEqualTo(true);
+    }
+
     @Test
     public void testBugreportFileManagerFileExists() {
         Pair<Integer, String> callingInfo = new Pair<>(mCallingUid, mCallingPackage);
@@ -131,14 +153,17 @@
                 new BugreportManagerServiceImpl.Injector(mContext, new ArraySet<>()));
         RoleManager roleManager = mContext.getSystemService(RoleManager.class);
         CallbackFuture future = new CallbackFuture();
-        runWithShellPermissionIdentity(() -> roleManager.setBypassingRoleQualification(true));
-        runWithShellPermissionIdentity(() -> roleManager.addRoleHolderAsUser(
-                "android.app.role.SYSTEM_AUTOMOTIVE_PROJECTION",
-                mContext.getPackageName(),
-                /* flags= */ 0,
-                Process.myUserHandle(),
-                mContext.getMainExecutor(),
-                future));
+        runWithShellPermissionIdentity(
+                () -> {
+                    roleManager.setBypassingRoleQualification(true);
+                    roleManager.addRoleHolderAsUser(
+                            "android.app.role.SYSTEM_AUTOMOTIVE_PROJECTION",
+                            mContext.getPackageName(),
+                            /* flags= */ 0,
+                            Process.myUserHandle(),
+                            mContext.getMainExecutor(),
+                            future);
+                });
 
         assertThat(future.get()).isEqualTo(true);
         mService.cancelBugreport(Binder.getCallingUid(), mContext.getPackageName());
diff --git a/services/tests/servicestests/src/com/android/server/pm/UserSystemPackageInstallerTest.java b/services/tests/servicestests/src/com/android/server/pm/UserSystemPackageInstallerTest.java
index cca924e..7798644 100644
--- a/services/tests/servicestests/src/com/android/server/pm/UserSystemPackageInstallerTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/UserSystemPackageInstallerTest.java
@@ -117,7 +117,7 @@
         for (int userId : mRemoveUsers) {
             um.removeUser(userId);
         }
-        setUserTypePackageWhitelistMode(mOriginalWhitelistMode);
+        setUserTypePackageAllowlistMode(mOriginalWhitelistMode);
     }
 
     /**
@@ -184,7 +184,7 @@
             }
         }
 
-        final ArrayMap<String, Long> expectedOutput = getNewPackageToWhitelistedBitSetMap();
+        final ArrayMap<String, Long> expectedOutput = getNewPackageToAllowlistedBitSetMap();
         expectedOutput.put("com.android.package1", expectedUserTypeBitSet1);
         expectedOutput.put("com.android.package2", expectedUserTypeBitSet2);
         expectedOutput.put("com.android.package3", expectedUserTypeBitSet3);
@@ -227,7 +227,7 @@
             }
         };
 
-        final ArrayMap<String, Long> expectedOutput = getNewPackageToWhitelistedBitSetMap();
+        final ArrayMap<String, Long> expectedOutput = getNewPackageToAllowlistedBitSetMap();
         expectedOutput.put("com.android.package2", 0L);
         expectedOutput.put("com.android.package3", 0L);
         expectedOutput.put("com.android.package4", 0L);
@@ -340,7 +340,7 @@
     public void testPackagesForCreateUser_full() {
         final String userTypeToCreate = USER_TYPE_FULL_SECONDARY;
         final long userTypeMask = mUserSystemPackageInstaller.getUserTypeMask(userTypeToCreate);
-        setUserTypePackageWhitelistMode(USER_TYPE_PACKAGE_WHITELIST_MODE_ENFORCE);
+        setUserTypePackageAllowlistMode(USER_TYPE_PACKAGE_WHITELIST_MODE_ENFORCE);
         PackageManager pm = mContext.getPackageManager();
 
         final SystemConfig sysConfig = new SystemConfigTestClass(true);
@@ -384,7 +384,7 @@
      */
     @Test
     public void testInstallOverlayPackagesExplicitMode() {
-        setUserTypePackageWhitelistMode(USER_TYPE_PACKAGE_WHITELIST_MODE_ENFORCE);
+        setUserTypePackageAllowlistMode(USER_TYPE_PACKAGE_WHITELIST_MODE_ENFORCE);
 
         final String[] userTypes = new String[]{"type"};
         final long maskOfType = 0b0001L;
@@ -453,49 +453,49 @@
      */
     @Test
     public void testSetWhitelistEnabledMode() {
-        setUserTypePackageWhitelistMode(USER_TYPE_PACKAGE_WHITELIST_MODE_DISABLE);
+        setUserTypePackageAllowlistMode(USER_TYPE_PACKAGE_WHITELIST_MODE_DISABLE);
         assertFalse(mUserSystemPackageInstaller.isLogMode());
         assertFalse(mUserSystemPackageInstaller.isEnforceMode());
         assertFalse(mUserSystemPackageInstaller.isImplicitWhitelistMode());
         assertFalse(mUserSystemPackageInstaller.isImplicitWhitelistSystemMode());
         assertFalse(mUserSystemPackageInstaller.isIgnoreOtaMode());
 
-        setUserTypePackageWhitelistMode(USER_TYPE_PACKAGE_WHITELIST_MODE_LOG);
+        setUserTypePackageAllowlistMode(USER_TYPE_PACKAGE_WHITELIST_MODE_LOG);
         assertTrue(mUserSystemPackageInstaller.isLogMode());
         assertFalse(mUserSystemPackageInstaller.isEnforceMode());
         assertFalse(mUserSystemPackageInstaller.isImplicitWhitelistMode());
         assertFalse(mUserSystemPackageInstaller.isImplicitWhitelistSystemMode());
         assertFalse(mUserSystemPackageInstaller.isIgnoreOtaMode());
 
-        setUserTypePackageWhitelistMode(USER_TYPE_PACKAGE_WHITELIST_MODE_ENFORCE);
+        setUserTypePackageAllowlistMode(USER_TYPE_PACKAGE_WHITELIST_MODE_ENFORCE);
         assertFalse(mUserSystemPackageInstaller.isLogMode());
         assertTrue(mUserSystemPackageInstaller.isEnforceMode());
         assertFalse(mUserSystemPackageInstaller.isImplicitWhitelistMode());
         assertFalse(mUserSystemPackageInstaller.isImplicitWhitelistSystemMode());
         assertFalse(mUserSystemPackageInstaller.isIgnoreOtaMode());
 
-        setUserTypePackageWhitelistMode(USER_TYPE_PACKAGE_WHITELIST_MODE_IMPLICIT_WHITELIST);
+        setUserTypePackageAllowlistMode(USER_TYPE_PACKAGE_WHITELIST_MODE_IMPLICIT_WHITELIST);
         assertFalse(mUserSystemPackageInstaller.isLogMode());
         assertFalse(mUserSystemPackageInstaller.isEnforceMode());
         assertTrue(mUserSystemPackageInstaller.isImplicitWhitelistMode());
         assertFalse(mUserSystemPackageInstaller.isImplicitWhitelistSystemMode());
         assertFalse(mUserSystemPackageInstaller.isIgnoreOtaMode());
 
-        setUserTypePackageWhitelistMode(USER_TYPE_PACKAGE_WHITELIST_MODE_IMPLICIT_WHITELIST_SYSTEM);
+        setUserTypePackageAllowlistMode(USER_TYPE_PACKAGE_WHITELIST_MODE_IMPLICIT_WHITELIST_SYSTEM);
         assertFalse(mUserSystemPackageInstaller.isLogMode());
         assertFalse(mUserSystemPackageInstaller.isEnforceMode());
         assertFalse(mUserSystemPackageInstaller.isImplicitWhitelistMode());
         assertTrue(mUserSystemPackageInstaller.isImplicitWhitelistSystemMode());
         assertFalse(mUserSystemPackageInstaller.isIgnoreOtaMode());
 
-        setUserTypePackageWhitelistMode(USER_TYPE_PACKAGE_WHITELIST_MODE_IGNORE_OTA);
+        setUserTypePackageAllowlistMode(USER_TYPE_PACKAGE_WHITELIST_MODE_IGNORE_OTA);
         assertFalse(mUserSystemPackageInstaller.isLogMode());
         assertFalse(mUserSystemPackageInstaller.isEnforceMode());
         assertFalse(mUserSystemPackageInstaller.isImplicitWhitelistMode());
         assertFalse(mUserSystemPackageInstaller.isImplicitWhitelistSystemMode());
         assertTrue(mUserSystemPackageInstaller.isIgnoreOtaMode());
 
-        setUserTypePackageWhitelistMode(
+        setUserTypePackageAllowlistMode(
                 USER_TYPE_PACKAGE_WHITELIST_MODE_LOG | USER_TYPE_PACKAGE_WHITELIST_MODE_ENFORCE);
         assertTrue(mUserSystemPackageInstaller.isLogMode());
         assertTrue(mUserSystemPackageInstaller.isEnforceMode());
@@ -503,7 +503,7 @@
         assertFalse(mUserSystemPackageInstaller.isImplicitWhitelistSystemMode());
         assertFalse(mUserSystemPackageInstaller.isIgnoreOtaMode());
 
-        setUserTypePackageWhitelistMode(USER_TYPE_PACKAGE_WHITELIST_MODE_IMPLICIT_WHITELIST
+        setUserTypePackageAllowlistMode(USER_TYPE_PACKAGE_WHITELIST_MODE_IMPLICIT_WHITELIST
                 | USER_TYPE_PACKAGE_WHITELIST_MODE_ENFORCE);
         assertFalse(mUserSystemPackageInstaller.isLogMode());
         assertTrue(mUserSystemPackageInstaller.isEnforceMode());
@@ -513,7 +513,7 @@
     }
 
     /** Sets the allowlist mode to the desired value via adb's setprop. */
-    private void setUserTypePackageWhitelistMode(int mode) {
+    private void setUserTypePackageAllowlistMode(int mode) {
         UiDevice uiDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
         try {
             String result = uiDevice.executeShellCommand(String.format("setprop %s %d",
@@ -526,7 +526,7 @@
     }
 
     /** @see UserSystemPackageInstaller#mWhitelistedPackagesForUserTypes */
-    private ArrayMap<String, Long> getNewPackageToWhitelistedBitSetMap() {
+    private ArrayMap<String, Long> getNewPackageToAllowlistedBitSetMap() {
         final ArrayMap<String, Long> pkgBitSetMap = new ArrayMap<>();
         // "android" is always treated as allowlisted for all types, regardless of the xml file.
         pkgBitSetMap.put("android", ~0L);
diff --git a/services/tests/servicestests/src/com/android/server/power/hint/OWNERS b/services/tests/servicestests/src/com/android/server/power/hint/OWNERS
new file mode 100644
index 0000000..c28c07a
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/power/hint/OWNERS
@@ -0,0 +1,2 @@
+include /ADPF_OWNERS
+
diff --git a/services/tests/servicestests/utils/com/android/server/testutils/TestHandler.java b/services/tests/servicestests/utils/com/android/server/testutils/TestHandler.java
index 22d383a..fc5213c 100644
--- a/services/tests/servicestests/utils/com/android/server/testutils/TestHandler.java
+++ b/services/tests/servicestests/utils/com/android/server/testutils/TestHandler.java
@@ -82,7 +82,7 @@
             uptimeMillis = uptimeMillis - SystemClock.uptimeMillis() + mClock.getAsLong();
         }
 
-        // post a dummy queue entry to keep track of message removal
+        // post a sentinel queue entry to keep track of message removal
         return super.sendMessageAtTime(msg, Long.MAX_VALUE)
                 && mMessages.add(new MsgInfo(Message.obtain(msg), uptimeMillis, mMessageCount));
     }
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
index bdee99b..6a6fa3f 100755
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -6043,6 +6043,49 @@
     }
 
     @Test
+    public void testVisitUris_styleExtrasWithoutStyle() {
+        Notification notification = new Notification.Builder(mContext, "a")
+                .setSmallIcon(android.R.drawable.sym_def_app_icon)
+                .build();
+
+        Notification.MessagingStyle messagingStyle = new Notification.MessagingStyle(
+                personWithIcon("content://user"))
+                .addHistoricMessage(new Notification.MessagingStyle.Message("Heyhey!",
+                                System.currentTimeMillis(),
+                                personWithIcon("content://historicalMessenger")))
+                .addMessage(new Notification.MessagingStyle.Message("Are you there",
+                                System.currentTimeMillis(),
+                                personWithIcon("content://messenger")))
+                        .setShortcutIcon(
+                                Icon.createWithContentUri("content://conversationShortcut"));
+        messagingStyle.addExtras(notification.extras); // Instead of Builder.setStyle(style).
+
+        Notification.CallStyle callStyle = Notification.CallStyle.forOngoingCall(
+                        personWithIcon("content://caller"),
+                        PendingIntent.getActivity(mContext, 0, new Intent(),
+                                PendingIntent.FLAG_IMMUTABLE))
+                .setVerificationIcon(Icon.createWithContentUri("content://callVerification"));
+        callStyle.addExtras(notification.extras); // Same.
+
+        Consumer<Uri> visitor = (Consumer<Uri>) spy(Consumer.class);
+        notification.visitUris(visitor);
+
+        verify(visitor).accept(eq(Uri.parse("content://user")));
+        verify(visitor).accept(eq(Uri.parse("content://historicalMessenger")));
+        verify(visitor).accept(eq(Uri.parse("content://messenger")));
+        verify(visitor).accept(eq(Uri.parse("content://conversationShortcut")));
+        verify(visitor).accept(eq(Uri.parse("content://caller")));
+        verify(visitor).accept(eq(Uri.parse("content://callVerification")));
+    }
+
+    private static Person personWithIcon(String iconUri) {
+        return new Person.Builder()
+                .setName("Mr " + iconUri)
+                .setIcon(Icon.createWithContentUri(iconUri))
+                .build();
+    }
+
+    @Test
     public void testVisitUris_wearableExtender() {
         Icon actionIcon = Icon.createWithContentUri("content://media/action");
         Icon wearActionIcon = Icon.createWithContentUri("content://media/wearAction");
@@ -7752,7 +7795,8 @@
     public void testOnNotificationActionClick() {
         final int actionIndex = 2;
         final Notification.Action action =
-                new Notification.Action.Builder(null, "text", null).build();
+                new Notification.Action.Builder(null, "text", PendingIntent.getActivity(
+                        mContext, 0, new Intent(), PendingIntent.FLAG_IMMUTABLE)).build();
         final boolean generatedByAssistant = false;
 
         NotificationRecord r = generateNotificationRecord(mTestNotificationChannel);
@@ -7776,7 +7820,8 @@
     public void testOnAssistantNotificationActionClick() {
         final int actionIndex = 1;
         final Notification.Action action =
-                new Notification.Action.Builder(null, "text", null).build();
+                new Notification.Action.Builder(null, "text", PendingIntent.getActivity(
+                        mContext, 0, new Intent(), PendingIntent.FLAG_IMMUTABLE)).build();
         final boolean generatedByAssistant = true;
 
         NotificationRecord r = generateNotificationRecord(mTestNotificationChannel);
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayRotationTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayRotationTests.java
index f757330..1617093 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayRotationTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayRotationTests.java
@@ -1176,6 +1176,15 @@
                 + " fixed to user rotation.", mTarget.isFixedToUserRotation());
     }
 
+    @Test
+    public void testIsFixedToUserRotation_displayContentOrientationFixed() throws Exception {
+        mBuilder.build();
+        when(mMockDisplayContent.isDisplayOrientationFixed()).thenReturn(true);
+
+        assertFalse("Display rotation should respect app requested orientation if"
+                + " the display has fixed orientation.", mTarget.isFixedToUserRotation());
+    }
+
     private void moveTimeForward(long timeMillis) {
         sCurrentUptimeMillis += timeMillis;
         sClock.fastForward(timeMillis);
diff --git a/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java b/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java
index b4f1176..7544fda 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java
@@ -39,6 +39,7 @@
 import static android.window.TransitionInfo.FLAG_IS_WALLPAPER;
 import static android.window.TransitionInfo.FLAG_MOVED_TO_TOP;
 import static android.window.TransitionInfo.FLAG_SHOW_WALLPAPER;
+import static android.window.TransitionInfo.FLAG_SYNC;
 import static android.window.TransitionInfo.FLAG_TRANSLUCENT;
 import static android.window.TransitionInfo.isIndependent;
 
@@ -1186,6 +1187,7 @@
         final WindowState statusBar = createWindow(null, TYPE_STATUS_BAR, "statusBar");
         makeWindowVisible(statusBar);
         mDisplayContent.getDisplayPolicy().addWindowLw(statusBar, statusBar.mAttrs);
+        final WindowState navBar = createWindow(null, TYPE_NAVIGATION_BAR, "navBar");
         final ActivityRecord app = createActivityRecord(mDisplayContent);
         final Transition transition = app.mTransitionController.createTransition(TRANSIT_OPEN);
         app.mTransitionController.requestStartTransition(transition, app.getTask(),
@@ -1215,9 +1217,17 @@
         mDisplayContent.mTransitionController.dispatchLegacyAppTransitionFinished(app);
         assertTrue(mDisplayContent.hasTopFixedRotationLaunchingApp());
 
+        // The bar was invisible so it is not handled by the controller. But if it becomes visible
+        // and drawn before the transition starts,
+        assertFalse(asyncRotationController.isTargetToken(navBar.mToken));
+        navBar.finishDrawing(null /* postDrawTransaction */, Integer.MAX_VALUE);
+        assertTrue(asyncRotationController.isTargetToken(navBar.mToken));
+
         player.startTransition();
         // Non-app windows should not be collected.
         assertFalse(mDisplayContent.mTransitionController.isCollecting(statusBar.mToken));
+        // Avoid DeviceStateController disturbing the test by triggering another rotation change.
+        doReturn(false).when(mDisplayContent).updateRotationUnchecked();
 
         onRotationTransactionReady(player, mWm.mTransactionFactory.get()).onTransactionCommitted();
         assertEquals(ROTATION_ANIMATION_SEAMLESS, player.mLastReady.getChange(
@@ -2384,6 +2394,37 @@
         assertFalse(controller.isCollecting());
     }
 
+    @Test
+    public void testNoSyncFlagIfOneTrack() {
+        final TransitionController controller = mAtm.getTransitionController();
+        final TestTransitionPlayer player = registerTestTransitionPlayer();
+
+        mSyncEngine = createTestBLASTSyncEngine();
+        controller.setSyncEngine(mSyncEngine);
+
+        final Transition transitA = createTestTransition(TRANSIT_OPEN, controller);
+        final Transition transitB = createTestTransition(TRANSIT_OPEN, controller);
+        final Transition transitC = createTestTransition(TRANSIT_OPEN, controller);
+
+        controller.startCollectOrQueue(transitA, (deferred) -> {});
+        controller.startCollectOrQueue(transitB, (deferred) -> {});
+        controller.startCollectOrQueue(transitC, (deferred) -> {});
+
+        // Verify that, as-long as there is <= 1 track, we won't get a SYNC flag
+        transitA.start();
+        transitA.setAllReady();
+        mSyncEngine.tryFinishForTest(transitA.getSyncId());
+        assertTrue((player.mLastReady.getFlags() & FLAG_SYNC) == 0);
+        transitB.start();
+        transitB.setAllReady();
+        mSyncEngine.tryFinishForTest(transitB.getSyncId());
+        assertTrue((player.mLastReady.getFlags() & FLAG_SYNC) == 0);
+        transitC.start();
+        transitC.setAllReady();
+        mSyncEngine.tryFinishForTest(transitC.getSyncId());
+        assertTrue((player.mLastReady.getFlags() & FLAG_SYNC) == 0);
+    }
+
     private static void makeTaskOrganized(Task... tasks) {
         final ITaskOrganizer organizer = mock(ITaskOrganizer.class);
         for (Task t : tasks) {
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java
index 58da4b43..3d78a1d 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java
@@ -54,6 +54,7 @@
 import android.service.voice.HotwordDetectionService;
 import android.service.voice.HotwordDetectionServiceFailure;
 import android.service.voice.HotwordDetector;
+import android.service.voice.IDetectorSessionStorageService;
 import android.service.voice.IMicrophoneHotwordDetectionVoiceInteractionCallback;
 import android.service.voice.ISandboxedDetectionService;
 import android.service.voice.IVisualQueryDetectionVoiceInteractionCallback;
@@ -69,6 +70,7 @@
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.app.IHotwordRecognitionStatusCallback;
 import com.android.internal.app.IVisualQueryDetectionAttentionListener;
+import com.android.internal.infra.AndroidFuture;
 import com.android.internal.infra.ServiceConnector;
 import com.android.server.LocalServices;
 import com.android.server.pm.permission.PermissionManagerServiceInternal;
@@ -157,6 +159,8 @@
     @NonNull private ServiceConnection mRemoteVisualQueryDetectionService;
     @GuardedBy("mLock")
     @Nullable private IBinder mAudioFlinger;
+
+    @Nullable private IHotwordRecognitionStatusCallback mHotwordRecognitionCallback;
     @GuardedBy("mLock")
     private boolean mDebugHotwordLogging = false;
 
@@ -694,6 +698,7 @@
             updateContentCaptureManager(connection);
             updateSpeechService(connection);
             updateServiceIdentity(connection);
+            updateStorageService(connection);
             return connection;
         }
     }
@@ -910,6 +915,7 @@
                     mVoiceInteractionServiceUid, mVoiceInteractorIdentity,
                     mScheduledExecutorService, mDebugHotwordLogging, mRemoteExceptionListener);
         }
+        mHotwordRecognitionCallback = callback;
         mDetectorSessions.put(detectorType, session);
         session.initialize(options, sharedMemory);
     }
@@ -1035,6 +1041,23 @@
         }));
     }
 
+    private void updateStorageService(ServiceConnection connection) {
+        connection.run(service -> {
+            service.registerRemoteStorageService(new IDetectorSessionStorageService.Stub() {
+                @Override
+                public void openFile(String filename, AndroidFuture future)
+                        throws RemoteException {
+                    Slog.v(TAG, "BinderCallback#onFileOpen");
+                    try {
+                        mHotwordRecognitionCallback.onOpenFile(filename, future);
+                    } catch (RemoteException e) {
+                        e.rethrowFromSystemServer();
+                    }
+                }
+            });
+        });
+    }
+
     private void addServiceUidForAudioPolicy(int uid) {
         mScheduledExecutorService.execute(() -> {
             AudioManagerInternal audioManager =
diff --git a/telecomm/OWNERS b/telecomm/OWNERS
index dcaf858..b57b7c7 100644
--- a/telecomm/OWNERS
+++ b/telecomm/OWNERS
@@ -4,7 +4,6 @@
 tgunn@google.com
 xiaotonj@google.com
 rgreenwalt@google.com
-chinmayd@google.com
 grantmenke@google.com
 pmadapurmath@google.com
 tjstuart@google.com
\ No newline at end of file
diff --git a/tests/ApkVerityTest/ApkVerityTestApp/feature_split/src/com/android/apkverity/feature_x/DummyActivity.java b/tests/ApkVerityTest/ApkVerityTestApp/feature_split/src/com/android/apkverity/feature_x/DummyActivity.java
index 0f694c2..fe91260 100644
--- a/tests/ApkVerityTest/ApkVerityTestApp/feature_split/src/com/android/apkverity/feature_x/DummyActivity.java
+++ b/tests/ApkVerityTest/ApkVerityTestApp/feature_split/src/com/android/apkverity/feature_x/DummyActivity.java
@@ -18,5 +18,5 @@
 
 import android.app.Activity;
 
-/** Dummy class just to generate some dex */
+/** Placeholder class just to generate some dex */
 public class DummyActivity extends Activity {}
diff --git a/tests/ApkVerityTest/ApkVerityTestApp/src/com/android/apkverity/DummyActivity.java b/tests/ApkVerityTest/ApkVerityTestApp/src/com/android/apkverity/DummyActivity.java
index 837c7be..a7bd771 100644
--- a/tests/ApkVerityTest/ApkVerityTestApp/src/com/android/apkverity/DummyActivity.java
+++ b/tests/ApkVerityTest/ApkVerityTestApp/src/com/android/apkverity/DummyActivity.java
@@ -18,5 +18,5 @@
 
 import android.app.Activity;
 
-/** Dummy class just to generate some dex */
+/** Placeholder class just to generate some dex */
 public class DummyActivity extends Activity {}
diff --git a/tests/Camera2Tests/SmartCamera/SimpleCamera/src/androidx/media/filterfw/GraphExporter.java b/tests/Camera2Tests/SmartCamera/SimpleCamera/src/androidx/media/filterfw/GraphExporter.java
index 0013965..4b7ca53 100644
--- a/tests/Camera2Tests/SmartCamera/SimpleCamera/src/androidx/media/filterfw/GraphExporter.java
+++ b/tests/Camera2Tests/SmartCamera/SimpleCamera/src/androidx/media/filterfw/GraphExporter.java
@@ -113,7 +113,7 @@
                         getDotName(target.getFilter().getName()) + ":" +
                         getDotName(target.getName()) + "_IN;\n" );
                 } else {
-                    // Found a unconnected output port, add dummy node
+                    // Found a unconnected output port, add placeholder node
                     String color = filter.getSignature().getOutputPortInfo(portName).isRequired()
                         ? "red" : "blue";  // red for unconnected, required ports
                     dotFile.write("  " +
@@ -131,7 +131,7 @@
                 if(target != null) {
                     // Found a connection -- nothing to do, connections have been written out above
                 } else {
-                    // Found a unconnected input port, add dummy node
+                    // Found a unconnected input port, add placeholder node
                     String color = filter.getSignature().getInputPortInfo(portName).isRequired()
                         ? "red" : "blue";  // red for unconnected, required ports
                     dotFile.write("  " +
diff --git a/tests/Camera2Tests/SmartCamera/SimpleCamera/src/androidx/media/filterfw/MffContext.java b/tests/Camera2Tests/SmartCamera/SimpleCamera/src/androidx/media/filterfw/MffContext.java
index b7212f9..6bd6c18 100644
--- a/tests/Camera2Tests/SmartCamera/SimpleCamera/src/androidx/media/filterfw/MffContext.java
+++ b/tests/Camera2Tests/SmartCamera/SimpleCamera/src/androidx/media/filterfw/MffContext.java
@@ -66,9 +66,9 @@
 
         /**
          * On older Android versions the Camera may need a SurfaceView to render into in order to
-         * function. You may specify a dummy SurfaceView here if you do not want the context to
+         * function. You may specify a placeholder SurfaceView here if you do not want the context to
          * create its own view. Note, that your view may or may not be used. You cannot rely on
-         * your dummy view to be used by the Camera. If you pass null, no dummy view will be used.
+         * your placeholder view to be used by the Camera. If you pass null, no placeholder view will be used.
          * In this case your application may not run correctly on older devices if you use the
          * camera. This flag has no effect if you do not require the camera.
          */
@@ -104,7 +104,7 @@
     /** The current context state. */
     private State mState = new State();
 
-    /** A dummy SurfaceView that is required for Camera operation on older devices. */
+    /** A placeholder SurfaceView that is required for Camera operation on older devices. */
     private SurfaceView mDummySurfaceView = null;
 
     /** Handler to execute code in the context's thread, such as issuing callbacks. */
@@ -126,7 +126,7 @@
      * multiple MffContexts, however data between them cannot be shared. The context must be
      * created in a thread with a Looper (such as the main/UI thread).
      *
-     * On older versions of Android, the MffContext may create a visible dummy view for the
+     * On older versions of Android, the MffContext may create a visible placeholder view for the
      * camera to render into. This is a 1x1 SurfaceView that is placed into the top-left corner.
      *
      * @param context The application context to attach the MffContext to.
@@ -142,7 +142,7 @@
      * multiple MffContexts, however data between them cannot be shared. The context must be
      * created in a thread with a Looper (such as the main/UI thread).
      *
-     * On older versions of Android, the MffContext may create a visible dummy view for the
+     * On older versions of Android, the MffContext may create a visible placeholder view for the
      * camera to render into. This is a 1x1 SurfaceView that is placed into the top-left corner.
      * You may alternatively specify your own SurfaceView in the configuration.
      *
diff --git a/tests/DynamicCodeLoggerIntegrationTests/src/com/android/dcl/Simple.java b/tests/DynamicCodeLoggerIntegrationTests/src/com/android/dcl/Simple.java
index e995a26..2ca91fb 100644
--- a/tests/DynamicCodeLoggerIntegrationTests/src/com/android/dcl/Simple.java
+++ b/tests/DynamicCodeLoggerIntegrationTests/src/com/android/dcl/Simple.java
@@ -16,7 +16,7 @@
 
 package com.android.dcl;
 
-/** Dummy class which is built into a jar purely so we can pass it to DexClassLoader. */
+/** Placeholder class which is built into a jar purely so we can pass it to DexClassLoader. */
 public final class Simple {
     public Simple() {}
 }
diff --git a/tests/FlickerTests/Android.bp b/tests/FlickerTests/Android.bp
index 1d423ca..2ccc0fa 100644
--- a/tests/FlickerTests/Android.bp
+++ b/tests/FlickerTests/Android.bp
@@ -97,6 +97,7 @@
         "flickerlib-helpers",
         "platform-test-annotations",
         "wm-flicker-common-app-helpers",
+        "wm-shell-flicker-utils",
     ],
     data: [
         ":FlickerTestApp",
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/splitscreen/EnterSystemSplitTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/splitscreen/EnterSystemSplitTest.kt
new file mode 100644
index 0000000..87231c8
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/splitscreen/EnterSystemSplitTest.kt
@@ -0,0 +1,189 @@
+/*
+ * 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.server.wm.flicker.activityembedding.splitscreen
+
+import android.platform.test.annotations.Presubmit
+import android.platform.test.annotations.RequiresDevice
+import android.tools.common.datatypes.Rect
+import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.device.flicker.legacy.FlickerBuilder
+import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.device.traces.parsers.toFlickerComponent
+import com.android.server.wm.flicker.helpers.ActivityEmbeddingAppHelper
+import com.android.server.wm.flicker.activityembedding.ActivityEmbeddingTestBase
+import com.android.server.wm.flicker.testapp.ActivityOptions
+import com.android.wm.shell.flicker.utils.*
+import org.junit.FixMethodOrder
+import org.junit.Ignore
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.MethodSorters
+import org.junit.runners.Parameterized
+
+/***
+ * Test entering System SplitScreen with Activity Embedding Split and another app.
+ *
+ * Setup: Launch A|B in split and secondaryApp, return to home.
+ * Transitions: Let AE Split A|B enter splitscreen with secondaryApp. Resulting in A|B|secondaryApp.
+ *
+ * To run this test: `atest FlickerTestsOther:EnterSystemSplitTest`
+ */
+@RequiresDevice
+@RunWith(Parameterized::class)
+@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+class EnterSystemSplitTest(flicker: LegacyFlickerTest) :
+        ActivityEmbeddingTestBase(flicker) {
+
+    private val secondaryApp = SplitScreenUtils.getPrimary(instrumentation)
+    override val transition: FlickerBuilder.() -> Unit = {
+        setup {
+            testApp.launchViaIntent(wmHelper)
+            testApp.launchSecondaryActivity(wmHelper)
+            secondaryApp.launchViaIntent(wmHelper)
+            tapl.goHome()
+            wmHelper
+                    .StateSyncBuilder()
+                    .withAppTransitionIdle()
+                    .withHomeActivityVisible()
+                    .waitForAndVerify()
+            startDisplayBounds =
+                    wmHelper.currentState.layerState.physicalDisplayBounds ?:
+                    error("Display not found")
+        }
+        transitions {
+            SplitScreenUtils.enterSplit(wmHelper, tapl, device, testApp, secondaryApp)
+            SplitScreenUtils.waitForSplitComplete(wmHelper, testApp, secondaryApp)
+        }
+    }
+
+    @Presubmit
+    @Test
+    fun splitScreenDividerBecomesVisible() = flicker.splitScreenDividerBecomesVisible()
+
+    @Presubmit
+    @Test
+    fun activityEmbeddingSplitLayerBecomesVisible() {
+        flicker.splitAppLayerBoundsIsVisibleAtEnd(
+                testApp, landscapePosLeft = tapl.isTablet, portraitPosTop = false)
+    }
+
+    @Presubmit
+    @Test
+    fun activityEmbeddingSplitWindowBecomesVisible() = flicker.appWindowIsVisibleAtEnd(testApp)
+
+    @Presubmit
+    @Test
+    fun secondaryLayerBecomesVisible() {
+        flicker.splitAppLayerBoundsIsVisibleAtEnd(
+                secondaryApp, landscapePosLeft = !tapl.isTablet, portraitPosTop = true)
+    }
+
+    @Presubmit
+    @Test
+    fun secondaryAppWindowBecomesVisible() = flicker.appWindowIsVisibleAtEnd(secondaryApp)
+
+    /**
+     * After the transition there should be both ActivityEmbedding activities,
+     * SplitScreenPrimaryActivity and the system split divider on screen.
+     * Verify the layers are in expected sizes.
+     */
+    @Presubmit
+    @Test
+    fun activityEmbeddingSplitSurfaceAreEven() {
+        flicker.assertLayersEnd {
+            val leftAELayerRegion =
+                    visibleRegion(ActivityEmbeddingAppHelper.MAIN_ACTIVITY_COMPONENT)
+            val rightAELayerRegion =
+                    visibleRegion(ActivityEmbeddingAppHelper.SECONDARY_ACTIVITY_COMPONENT)
+            val secondaryAppLayerRegion =
+                    visibleRegion(
+                            ActivityOptions.SplitScreen.Primary.COMPONENT.toFlickerComponent())
+            val systemDivider = visibleRegion(SPLIT_SCREEN_DIVIDER_COMPONENT)
+            leftAELayerRegion
+                    .plus(rightAELayerRegion.region)
+                    .plus(secondaryAppLayerRegion.region)
+                    .plus(systemDivider.region)
+                    .coversExactly(startDisplayBounds)
+            check { "ActivityEmbeddingSplitHeight" }
+                    .that(leftAELayerRegion.region.height)
+                    .isEqual(rightAELayerRegion.region.height)
+            check { "SystemSplitHeight" }
+                    .that(rightAELayerRegion.region.height)
+                    .isEqual(secondaryAppLayerRegion.region.height)
+            // TODO(b/292283182): Remove this special case handling.
+            check { "ActivityEmbeddingSplitWidth" }
+                    .that(Math.abs(
+                            leftAELayerRegion.region.width - rightAELayerRegion.region.width))
+                    .isLower(2)
+            check { "SystemSplitWidth" }
+                    .that(Math.abs(secondaryAppLayerRegion.region.width -
+                            2 * rightAELayerRegion.region.width))
+                    .isLower(2)
+        }
+    }
+
+    /**
+     * Verify the windows are in expected sizes.
+     */
+    @Presubmit
+    @Test
+    fun activityEmbeddingSplitWindowsAreEven() {
+        flicker.assertWmEnd {
+            val leftAEWindowRegion =
+                    visibleRegion(ActivityEmbeddingAppHelper.MAIN_ACTIVITY_COMPONENT)
+            val rightAEWindowRegion =
+                    visibleRegion(ActivityEmbeddingAppHelper.SECONDARY_ACTIVITY_COMPONENT)
+            // There's no window for the divider bar.
+            val secondaryAppLayerRegion =
+                    visibleRegion(
+                            ActivityOptions.SplitScreen.Primary.COMPONENT.toFlickerComponent())
+            check { "ActivityEmbeddingSplitHeight" }
+                    .that(leftAEWindowRegion.region.height)
+                    .isEqual(rightAEWindowRegion.region.height)
+            check { "SystemSplitHeight" }
+                    .that(rightAEWindowRegion.region.height)
+                    .isEqual(secondaryAppLayerRegion.region.height)
+            check { "ActivityEmbeddingSplitWidth" }
+                    .that(Math.abs(
+                            leftAEWindowRegion.region.width - rightAEWindowRegion.region.width))
+                    .isLower(2)
+            check { "SystemSplitWidth" }
+                    .that(Math.abs(secondaryAppLayerRegion.region.width -
+                            2 * rightAEWindowRegion.region.width))
+                    .isLower(2)
+        }
+    }
+
+    @Ignore("Not applicable to this CUJ.")
+    override fun visibleLayersShownMoreThanOneConsecutiveEntry() {}
+
+    companion object {
+        /** {@inheritDoc} */
+        private var startDisplayBounds = Rect.EMPTY
+        /**
+         * Creates the test configurations.
+         *
+         * See [LegacyFlickerTestFactory.nonRotationTests] for configuring screen orientation and
+         * navigation modes.
+         */
+        @Parameterized.Parameters(name = "{0}")
+        @JvmStatic
+        fun getParams() = LegacyFlickerTestFactory.nonRotationTests()
+    }
+}
\ No newline at end of file
diff --git a/tests/InputMethodStressTest/src/com/android/inputmethod/stresstest/ImeStressTestUtil.java b/tests/InputMethodStressTest/src/com/android/inputmethod/stresstest/ImeStressTestUtil.java
index c9b5c96..12556bc 100644
--- a/tests/InputMethodStressTest/src/com/android/inputmethod/stresstest/ImeStressTestUtil.java
+++ b/tests/InputMethodStressTest/src/com/android/inputmethod/stresstest/ImeStressTestUtil.java
@@ -154,7 +154,7 @@
      * <p>The given {@code pred} will be called on the main thread.
      */
     public static void waitOnMainUntil(String message, Callable<Boolean> pred) {
-        eventually(() -> assertWithMessage(message).that(pred.call()).isTrue(), TIMEOUT);
+        eventually(() -> assertWithMessage(message).that(callOnMainSync(pred)).isTrue(), TIMEOUT);
     }
 
     /** Waits until IME is shown, or throws on timeout. */
diff --git a/tests/SoundTriggerTestApp/src/com/android/test/soundtrigger/SoundTriggerTestService.java b/tests/SoundTriggerTestApp/src/com/android/test/soundtrigger/SoundTriggerTestService.java
index 3567c08..cc6cebf 100644
--- a/tests/SoundTriggerTestApp/src/com/android/test/soundtrigger/SoundTriggerTestService.java
+++ b/tests/SoundTriggerTestApp/src/com/android/test/soundtrigger/SoundTriggerTestService.java
@@ -469,7 +469,7 @@
             }
         }
 
-        // Create a few dummy models if we didn't load anything.
+        // Create a few placeholder models if we didn't load anything.
         if (!loadedModel) {
             Properties dummyModelProperties = new Properties();
             for (String name : new String[]{"1", "2", "3"}) {
diff --git a/tests/libs-permissions/system_ext/java/com/android/test/libs/system_ext/LibsSystemExtTest.java b/tests/libs-permissions/system_ext/java/com/android/test/libs/system_ext/LibsSystemExtTest.java
index 9999aba..673c73a 100644
--- a/tests/libs-permissions/system_ext/java/com/android/test/libs/system_ext/LibsSystemExtTest.java
+++ b/tests/libs-permissions/system_ext/java/com/android/test/libs/system_ext/LibsSystemExtTest.java
@@ -22,7 +22,7 @@
 public class LibsSystemExtTest {
 
     /**
-     * Dummy method for testing.
+     * Placeholder method for testing.
      */
     public static void test() {
     }
diff --git a/tools/aapt/AaptAssets.cpp b/tools/aapt/AaptAssets.cpp
index 899d268..b94d14f 100644
--- a/tools/aapt/AaptAssets.cpp
+++ b/tools/aapt/AaptAssets.cpp
@@ -219,7 +219,7 @@
      if (numTags >= 1) {
          const String8& lang = parts[0];
          if (isAlpha(lang) && (lang.length() == 2 || lang.length() == 3)) {
-             setLanguage(lang.string());
+             setLanguage(lang.c_str());
              valid = true;
          }
      }
@@ -232,11 +232,11 @@
      const String8& part2 = parts[1];
      if ((part2.length() == 2 && isAlpha(part2)) ||
          (part2.length() == 3 && isNumber(part2))) {
-         setRegion(part2.string());
+         setRegion(part2.c_str());
      } else if (part2.length() == 4 && isAlpha(part2)) {
-         setScript(part2.string());
+         setScript(part2.c_str());
      } else if (part2.length() >= 4 && part2.length() <= 8) {
-         setVariant(part2.string());
+         setVariant(part2.c_str());
      } else {
          valid = false;
      }
@@ -249,9 +249,9 @@
      const String8& part3 = parts[2];
      if (((part3.length() == 2 && isAlpha(part3)) ||
          (part3.length() == 3 && isNumber(part3))) && script[0]) {
-         setRegion(part3.string());
+         setRegion(part3.c_str());
      } else if (part3.length() >= 4 && part3.length() <= 8) {
-         setVariant(part3.string());
+         setVariant(part3.c_str());
      } else {
          valid = false;
      }
@@ -262,7 +262,7 @@
 
      const String8& part4 = parts[3];
      if (part4.length() >= 4 && part4.length() <= 8) {
-         setVariant(part4.string());
+         setVariant(part4.c_str());
      } else {
          valid = false;
      }
@@ -310,7 +310,7 @@
                     break;
                 default:
                     fprintf(stderr, "ERROR: Invalid BCP 47 tag in directory name %s\n",
-                            part.string());
+                            part.c_str());
                     return -1;
             }
         } else if (subtags.size() == 3) {
@@ -324,7 +324,7 @@
             } else if (subtags[1].size() == 2 || subtags[1].size() == 3) {
                 setRegion(subtags[1]);
             } else {
-                fprintf(stderr, "ERROR: Invalid BCP 47 tag in directory name %s\n", part.string());
+                fprintf(stderr, "ERROR: Invalid BCP 47 tag in directory name %s\n", part.c_str());
                 return -1;
             }
 
@@ -341,14 +341,14 @@
             setRegion(subtags[2]);
             setVariant(subtags[3]);
         } else {
-            fprintf(stderr, "ERROR: Invalid BCP 47 tag in directory name: %s\n", part.string());
+            fprintf(stderr, "ERROR: Invalid BCP 47 tag in directory name: %s\n", part.c_str());
             return -1;
         }
 
         return ++currentIndex;
     } else {
         if ((part.length() == 2 || part.length() == 3)
-               && isAlpha(part) && strcmp("car", part.string())) {
+               && isAlpha(part) && strcmp("car", part.c_str())) {
             setLanguage(part);
             if (++currentIndex == size) {
                 return size;
@@ -358,8 +358,8 @@
         }
 
         part = parts[currentIndex];
-        if (part.string()[0] == 'r' && part.length() == 3) {
-            setRegion(part.string() + 1);
+        if (part.c_str()[0] == 'r' && part.length() == 3) {
+            setRegion(part.c_str() + 1);
             if (++currentIndex == size) {
                 return size;
             }
@@ -524,8 +524,8 @@
     ssize_t index = mFiles.indexOfKey(file->getGroupEntry());
     if (index >= 0 && overwriteDuplicate) {
         fprintf(stderr, "warning: overwriting '%s' with '%s'\n",
-                mFiles[index]->getSourceFile().string(),
-                file->getSourceFile().string());
+                mFiles[index]->getSourceFile().c_str(),
+                file->getSourceFile().c_str());
         removeFile(index);
         index = -1;
     }
@@ -545,7 +545,7 @@
     const sp<AaptFile>& originalFile = mFiles.valueAt(index);
     SourcePos(file->getSourceFile(), -1)
             .error("Duplicate file.\n%s: Original is here. %s",
-                   originalFile->getPrintableSource().string(),
+                   originalFile->getPrintableSource().c_str(),
                    (withoutVersion.version != 0) ? "The version qualifier may be implied." : "");
     return UNKNOWN_ERROR;
 }
@@ -557,21 +557,21 @@
 
 void AaptGroup::print(const String8& prefix) const
 {
-    printf("%s%s\n", prefix.string(), getPath().string());
+    printf("%s%s\n", prefix.c_str(), getPath().c_str());
     const size_t N=mFiles.size();
     size_t i;
     for (i=0; i<N; i++) {
         sp<AaptFile> file = mFiles.valueAt(i);
         const AaptGroupEntry& e = file->getGroupEntry();
         if (file->hasData()) {
-            printf("%s  Gen: (%s) %d bytes\n", prefix.string(), e.toDirName(String8()).string(),
+            printf("%s  Gen: (%s) %d bytes\n", prefix.c_str(), e.toDirName(String8()).c_str(),
                     (int)file->getSize());
         } else {
-            printf("%s  Src: (%s) %s\n", prefix.string(), e.toDirName(String8()).string(),
-                    file->getPrintableSource().string());
+            printf("%s  Src: (%s) %s\n", prefix.c_str(), e.toDirName(String8()).c_str(),
+                    file->getPrintableSource().c_str());
         }
-        //printf("%s  File Group Entry: %s\n", prefix.string(),
-        //        file->getGroupEntry().toDirName(String8()).string());
+        //printf("%s  File Group Entry: %s\n", prefix.c_str(),
+        //        file->getGroupEntry().toDirName(String8()).c_str());
     }
 }
 
@@ -660,9 +660,9 @@
     {
         DIR* dir = NULL;
 
-        dir = opendir(srcDir.string());
+        dir = opendir(srcDir.c_str());
         if (dir == NULL) {
-            fprintf(stderr, "ERROR: opendir(%s): %s\n", srcDir.string(), strerror(errno));
+            fprintf(stderr, "ERROR: opendir(%s): %s\n", srcDir.c_str(), strerror(errno));
             return UNKNOWN_ERROR;
         }
 
@@ -676,7 +676,7 @@
             if (entry == NULL)
                 break;
 
-            if (isHidden(srcDir.string(), entry->d_name))
+            if (isHidden(srcDir.c_str(), entry->d_name))
                 continue;
 
             String8 name(entry->d_name);
@@ -701,8 +701,8 @@
         String8 pathName(srcDir);
         FileType type;
 
-        pathName.appendPath(fileNames[i].string());
-        type = getFileType(pathName.string());
+        pathName.appendPath(fileNames[i].c_str());
+        type = getFileType(pathName.c_str());
         if (type == kFileTypeDirectory) {
             sp<AaptDir> subdir;
             bool notAdded = false;
@@ -732,7 +732,7 @@
 
         } else {
             if (bundle->getVerbose())
-                printf("   (ignoring non-file/dir '%s')\n", pathName.string());
+                printf("   (ignoring non-file/dir '%s')\n", pathName.c_str());
         }
     }
 
@@ -745,7 +745,7 @@
     const size_t ND = mDirs.size();
     size_t i;
     for (i = 0; i < NF; i++) {
-        if (!validateFileName(mFiles.valueAt(i)->getLeaf().string())) {
+        if (!validateFileName(mFiles.valueAt(i)->getLeaf().c_str())) {
             SourcePos(mFiles.valueAt(i)->getPrintableSource(), -1).error(
                     "Invalid filename.  Unable to add.");
             return UNKNOWN_ERROR;
@@ -753,11 +753,11 @@
 
         size_t j;
         for (j = i+1; j < NF; j++) {
-            if (strcasecmp(mFiles.valueAt(i)->getLeaf().string(),
-                           mFiles.valueAt(j)->getLeaf().string()) == 0) {
+            if (strcasecmp(mFiles.valueAt(i)->getLeaf().c_str(),
+                           mFiles.valueAt(j)->getLeaf().c_str()) == 0) {
                 SourcePos(mFiles.valueAt(i)->getPrintableSource(), -1).error(
                         "File is case-insensitive equivalent to: %s",
-                        mFiles.valueAt(j)->getPrintableSource().string());
+                        mFiles.valueAt(j)->getPrintableSource().c_str());
                 return UNKNOWN_ERROR;
             }
 
@@ -766,18 +766,18 @@
         }
 
         for (j = 0; j < ND; j++) {
-            if (strcasecmp(mFiles.valueAt(i)->getLeaf().string(),
-                           mDirs.valueAt(j)->getLeaf().string()) == 0) {
+            if (strcasecmp(mFiles.valueAt(i)->getLeaf().c_str(),
+                           mDirs.valueAt(j)->getLeaf().c_str()) == 0) {
                 SourcePos(mFiles.valueAt(i)->getPrintableSource(), -1).error(
                         "File conflicts with dir from: %s",
-                        mDirs.valueAt(j)->getPrintableSource().string());
+                        mDirs.valueAt(j)->getPrintableSource().c_str());
                 return UNKNOWN_ERROR;
             }
         }
     }
 
     for (i = 0; i < ND; i++) {
-        if (!validateFileName(mDirs.valueAt(i)->getLeaf().string())) {
+        if (!validateFileName(mDirs.valueAt(i)->getLeaf().c_str())) {
             SourcePos(mDirs.valueAt(i)->getPrintableSource(), -1).error(
                     "Invalid directory name, unable to add.");
             return UNKNOWN_ERROR;
@@ -785,11 +785,11 @@
 
         size_t j;
         for (j = i+1; j < ND; j++) {
-            if (strcasecmp(mDirs.valueAt(i)->getLeaf().string(),
-                           mDirs.valueAt(j)->getLeaf().string()) == 0) {
+            if (strcasecmp(mDirs.valueAt(i)->getLeaf().c_str(),
+                           mDirs.valueAt(j)->getLeaf().c_str()) == 0) {
                 SourcePos(mDirs.valueAt(i)->getPrintableSource(), -1).error(
                         "Directory is case-insensitive equivalent to: %s",
-                        mDirs.valueAt(j)->getPrintableSource().string());
+                        mDirs.valueAt(j)->getPrintableSource().c_str());
                 return UNKNOWN_ERROR;
             }
         }
@@ -846,12 +846,12 @@
         const AaptSymbolEntry& entry = javaSymbols->mSymbols.valueAt(i);
         ssize_t pos = mSymbols.indexOfKey(name);
         if (pos < 0) {
-            entry.sourcePos.error("Symbol '%s' declared with <java-symbol> not defined\n", name.string());
+            entry.sourcePos.error("Symbol '%s' declared with <java-symbol> not defined\n", name.c_str());
             err = UNKNOWN_ERROR;
             continue;
         }
         //printf("**** setting symbol #%d/%d %s to isJavaSymbol=%d\n",
-        //        i, N, name.string(), entry.isJavaSymbol ? 1 : 0);
+        //        i, N, name.c_str(), entry.isJavaSymbol ? 1 : 0);
         mSymbols.editValueAt(pos).isJavaSymbol = entry.isJavaSymbol;
     }
 
@@ -862,11 +862,11 @@
         ssize_t pos = mNestedSymbols.indexOfKey(name);
         if (pos < 0) {
             SourcePos pos;
-            pos.error("Java symbol dir %s not defined\n", name.string());
+            pos.error("Java symbol dir %s not defined\n", name.c_str());
             err = UNKNOWN_ERROR;
             continue;
         }
-        //printf("**** applying java symbols in dir %s\n", name.string());
+        //printf("**** applying java symbols in dir %s\n", name.c_str());
         status_t myerr = mNestedSymbols.valueAt(pos)->applyJavaSymbols(symbols);
         if (myerr != NO_ERROR) {
             err = myerr;
@@ -1131,9 +1131,9 @@
 {
     ssize_t err = 0;
 
-    DIR* dir = opendir(srcDir.string());
+    DIR* dir = opendir(srcDir.c_str());
     if (dir == NULL) {
-        fprintf(stderr, "ERROR: opendir(%s): %s\n", srcDir.string(), strerror(errno));
+        fprintf(stderr, "ERROR: opendir(%s): %s\n", srcDir.c_str(), strerror(errno));
         return UNKNOWN_ERROR;
     }
 
@@ -1149,7 +1149,7 @@
             break;
         }
 
-        if (isHidden(srcDir.string(), entry->d_name)) {
+        if (isHidden(srcDir.c_str(), entry->d_name)) {
             continue;
         }
 
@@ -1160,7 +1160,7 @@
         String8 resType;
         bool b = group.initFromDirName(entry->d_name, &resType);
         if (!b) {
-            fprintf(stderr, "invalid resource directory name: %s %s\n", srcDir.string(),
+            fprintf(stderr, "invalid resource directory name: %s %s\n", srcDir.c_str(),
                     entry->d_name);
             err = -1;
             continue;
@@ -1168,7 +1168,7 @@
 
         if (bundle->getMaxResVersion() != NULL && group.getVersionString().length() != 0) {
             int maxResInt = atoi(bundle->getMaxResVersion());
-            const char *verString = group.getVersionString().string();
+            const char *verString = group.getVersionString().c_str();
             int dirVersionInt = atoi(verString + 1); // skip 'v' in version name
             if (dirVersionInt > maxResInt) {
               fprintf(stderr, "max res %d, skipping %s\n", maxResInt, entry->d_name);
@@ -1176,7 +1176,7 @@
             }
         }
 
-        FileType type = getFileType(subdirName.string());
+        FileType type = getFileType(subdirName.c_str());
 
         if (type == kFileTypeDirectory) {
             sp<AaptDir> dir = makeDir(resType);
@@ -1200,7 +1200,7 @@
             }
         } else {
             if (bundle->getVerbose()) {
-                fprintf(stderr, "   (ignoring file '%s')\n", subdirName.string());
+                fprintf(stderr, "   (ignoring file '%s')\n", subdirName.c_str());
             }
         }
     }
@@ -1248,7 +1248,7 @@
         String8 remain;
         if (entryName.walkPath(&remain) == kResourceDir) {
             // these are the resources, pull their type out of the directory name
-            kind.initFromDirName(remain.walkPath().string(), &resType);
+            kind.initFromDirName(remain.walkPath().c_str(), &resType);
         } else {
             // these are untyped and don't have an AaptGroupEntry
         }
@@ -1263,7 +1263,7 @@
         sp<AaptFile> file = new AaptFile(entryName, kind, resType);
         status_t err = dir->addLeafFile(entryName.getPathLeaf(), file);
         if (err != NO_ERROR) {
-            fprintf(stderr, "err=%s entryName=%s\n", strerror(err), entryName.string());
+            fprintf(stderr, "err=%s entryName=%s\n", strerror(err), entryName.c_str());
             count = err;
             goto bail;
         }
@@ -1273,7 +1273,7 @@
         if (entryName == "AndroidManifest.xml") {
             printf("AndroidManifest.xml\n");
         }
-        printf("\n\nfile: %s\n", entryName.string());
+        printf("\n\nfile: %s\n", entryName.c_str());
 #endif
 
         size_t len = entry->getUncompressedLen();
@@ -1317,9 +1317,9 @@
     uint32_t preferredDensity = 0;
     if (bundle->getPreferredDensity().size() > 0) {
         ResTable_config preferredConfig;
-        if (!AaptConfig::parseDensity(bundle->getPreferredDensity().string(), &preferredConfig)) {
+        if (!AaptConfig::parseDensity(bundle->getPreferredDensity().c_str(), &preferredConfig)) {
             fprintf(stderr, "Error parsing preferred density: %s\n",
-                    bundle->getPreferredDensity().string());
+                    bundle->getPreferredDensity().c_str());
             return UNKNOWN_ERROR;
         }
         preferredDensity = preferredConfig.density;
@@ -1332,11 +1332,11 @@
     if (bundle->getVerbose()) {
         if (!reqFilter->isEmpty()) {
             printf("Applying required filter: %s\n",
-                    bundle->getConfigurations().string());
+                    bundle->getConfigurations().c_str());
         }
         if (preferredDensity > 0) {
             printf("Applying preferred density filter: %s\n",
-                    bundle->getPreferredDensity().string());
+                    bundle->getPreferredDensity().c_str());
         }
     }
 
@@ -1385,7 +1385,7 @@
                 if (!reqFilter->match(config)) {
                     if (bundle->getVerbose()) {
                         printf("Pruning unneeded resource: %s\n",
-                                file->getPrintableSource().string());
+                                file->getPrintableSource().c_str());
                     }
                     grp->removeFile(k);
                     k--;
@@ -1453,7 +1453,7 @@
                     if (bestDensity != config.density) {
                         if (bundle->getVerbose()) {
                             printf("Pruning unneeded resource: %s\n",
-                                    file->getPrintableSource().string());
+                                    file->getPrintableSource().c_str());
                         }
                         grp->removeFile(k);
                         k--;
@@ -1495,10 +1495,10 @@
         ssize_t pos = mSymbols.indexOfKey(name);
         if (pos < 0) {
             SourcePos pos;
-            pos.error("Java symbol dir %s not defined\n", name.string());
+            pos.error("Java symbol dir %s not defined\n", name.c_str());
             return UNKNOWN_ERROR;
         }
-        //printf("**** applying java symbols in dir %s\n", name.string());
+        //printf("**** applying java symbols in dir %s\n", name.c_str());
         status_t err = mSymbols.valueAt(pos)->applyJavaSymbols(symbols);
         if (err != NO_ERROR) {
             return err;
@@ -1510,7 +1510,7 @@
 
 bool AaptAssets::isJavaSymbol(const AaptSymbolEntry& sym, bool includePrivate) const {
     //printf("isJavaSymbol %s: public=%d, includePrivate=%d, isJavaSymbol=%d\n",
-    //        sym.name.string(), sym.isPublic ? 1 : 0, includePrivate ? 1 : 0,
+    //        sym.name.c_str(), sym.isPublic ? 1 : 0, includePrivate ? 1 : 0,
     //        sym.isJavaSymbol ? 1 : 0);
     if (!mHavePrivateSymbols) return true;
     if (sym.isPublic) return true;
@@ -1529,12 +1529,12 @@
     const size_t packageIncludeCount = includes.size();
     for (size_t i = 0; i < packageIncludeCount; i++) {
         if (bundle->getVerbose()) {
-            printf("Including resources from package: %s\n", includes[i].string());
+            printf("Including resources from package: %s\n", includes[i].c_str());
         }
 
         if (!mIncludedAssets.addAssetPath(includes[i], NULL)) {
             fprintf(stderr, "ERROR: Asset package include '%s' not found.\n",
-                    includes[i].string());
+                    includes[i].c_str());
             return UNKNOWN_ERROR;
         }
     }
@@ -1543,12 +1543,12 @@
     if (!featureOfBase.isEmpty()) {
         if (bundle->getVerbose()) {
             printf("Including base feature resources from package: %s\n",
-                    featureOfBase.string());
+                    featureOfBase.c_str());
         }
 
         if (!mIncludedAssets.addAssetPath(featureOfBase, NULL)) {
             fprintf(stderr, "ERROR: base feature package '%s' not found.\n",
-                    featureOfBase.string());
+                    featureOfBase.c_str());
             return UNKNOWN_ERROR;
         }
     }
@@ -1581,23 +1581,23 @@
     innerPrefix.append("  ");
     String8 innerInnerPrefix(innerPrefix);
     innerInnerPrefix.append("  ");
-    printf("%sConfigurations:\n", prefix.string());
+    printf("%sConfigurations:\n", prefix.c_str());
     const size_t N=mGroupEntries.size();
     for (size_t i=0; i<N; i++) {
         String8 cname = mGroupEntries.itemAt(i).toDirName(String8());
-        printf("%s %s\n", prefix.string(),
-                cname != "" ? cname.string() : "(default)");
+        printf("%s %s\n", prefix.c_str(),
+                cname != "" ? cname.c_str() : "(default)");
     }
 
-    printf("\n%sFiles:\n", prefix.string());
+    printf("\n%sFiles:\n", prefix.c_str());
     AaptDir::print(innerPrefix);
 
-    printf("\n%sResource Dirs:\n", prefix.string());
+    printf("\n%sResource Dirs:\n", prefix.c_str());
     const Vector<sp<AaptDir> >& resdirs = mResDirs;
     const size_t NR = resdirs.size();
     for (size_t i=0; i<NR; i++) {
         const sp<AaptDir>& d = resdirs.itemAt(i);
-        printf("%s  Type %s\n", prefix.string(), d->getLeaf().string());
+        printf("%s  Type %s\n", prefix.c_str(), d->getLeaf().c_str());
         d->print(innerInnerPrefix);
     }
 }
@@ -1631,7 +1631,7 @@
         NULL
     };
     const char*const* k = KEYWORDS;
-    const char*const s = symbol.string();
+    const char*const s = symbol.c_str();
     while (*k) {
         if (0 == strcmp(s, *k)) {
             return false;
diff --git a/tools/aapt/AaptAssets.h b/tools/aapt/AaptAssets.h
index eadd48a..498fc4e 100644
--- a/tools/aapt/AaptAssets.h
+++ b/tools/aapt/AaptAssets.h
@@ -463,7 +463,7 @@
         if (valid_symbol_name(symbol)) {
             return true;
         }
-        pos.error("invalid %s: '%s'\n", label, symbol.string());
+        pos.error("invalid %s: '%s'\n", label, symbol.c_str());
         return false;
     }
     AaptSymbolEntry& edit_symbol(const String8& symbol, const SourcePos* pos) {
diff --git a/tools/aapt/AaptConfig.cpp b/tools/aapt/AaptConfig.cpp
index 0aca45e..7578f79 100644
--- a/tools/aapt/AaptConfig.cpp
+++ b/tools/aapt/AaptConfig.cpp
@@ -39,7 +39,7 @@
     ssize_t index = 0;
     ssize_t localeIndex = 0;
     const ssize_t N = parts.size();
-    const char* part = parts[index].string();
+    const char* part = parts[index].c_str();
 
     if (str.length() == 0) {
         goto success;
@@ -50,7 +50,7 @@
         if (index == N) {
             goto success;
         }
-        part = parts[index].string();
+        part = parts[index].c_str();
     }
 
     if (parseMnc(part, &config)) {
@@ -58,7 +58,7 @@
         if (index == N) {
             goto success;
         }
-        part = parts[index].string();
+        part = parts[index].c_str();
     }
 
     // Locale spans a few '-' separators, so we let it
@@ -72,7 +72,7 @@
         if (index >= N) {
             goto success;
         }
-        part = parts[index].string();
+        part = parts[index].c_str();
     }
 
     if (parseLayoutDirection(part, &config)) {
@@ -80,7 +80,7 @@
         if (index == N) {
             goto success;
         }
-        part = parts[index].string();
+        part = parts[index].c_str();
     }
 
     if (parseSmallestScreenWidthDp(part, &config)) {
@@ -88,7 +88,7 @@
         if (index == N) {
             goto success;
         }
-        part = parts[index].string();
+        part = parts[index].c_str();
     }
 
     if (parseScreenWidthDp(part, &config)) {
@@ -96,7 +96,7 @@
         if (index == N) {
             goto success;
         }
-        part = parts[index].string();
+        part = parts[index].c_str();
     }
 
     if (parseScreenHeightDp(part, &config)) {
@@ -104,7 +104,7 @@
         if (index == N) {
             goto success;
         }
-        part = parts[index].string();
+        part = parts[index].c_str();
     }
 
     if (parseScreenLayoutSize(part, &config)) {
@@ -112,7 +112,7 @@
         if (index == N) {
             goto success;
         }
-        part = parts[index].string();
+        part = parts[index].c_str();
     }
 
     if (parseScreenLayoutLong(part, &config)) {
@@ -120,7 +120,7 @@
         if (index == N) {
             goto success;
         }
-        part = parts[index].string();
+        part = parts[index].c_str();
     }
 
     if (parseScreenRound(part, &config)) {
@@ -128,7 +128,7 @@
         if (index == N) {
             goto success;
         }
-        part = parts[index].string();
+        part = parts[index].c_str();
     }
 
     if (parseWideColorGamut(part, &config)) {
@@ -136,7 +136,7 @@
         if (index == N) {
             goto success;
         }
-        part = parts[index].string();
+        part = parts[index].c_str();
     }
 
     if (parseHdr(part, &config)) {
@@ -144,7 +144,7 @@
         if (index == N) {
             goto success;
         }
-        part = parts[index].string();
+        part = parts[index].c_str();
     }
 
     if (parseOrientation(part, &config)) {
@@ -152,7 +152,7 @@
         if (index == N) {
             goto success;
         }
-        part = parts[index].string();
+        part = parts[index].c_str();
     }
 
     if (parseUiModeType(part, &config)) {
@@ -160,7 +160,7 @@
         if (index == N) {
             goto success;
         }
-        part = parts[index].string();
+        part = parts[index].c_str();
     }
 
     if (parseUiModeNight(part, &config)) {
@@ -168,7 +168,7 @@
         if (index == N) {
             goto success;
         }
-        part = parts[index].string();
+        part = parts[index].c_str();
     }
 
     if (parseDensity(part, &config)) {
@@ -176,7 +176,7 @@
         if (index == N) {
             goto success;
         }
-        part = parts[index].string();
+        part = parts[index].c_str();
     }
 
     if (parseTouchscreen(part, &config)) {
@@ -184,7 +184,7 @@
         if (index == N) {
             goto success;
         }
-        part = parts[index].string();
+        part = parts[index].c_str();
     }
 
     if (parseKeysHidden(part, &config)) {
@@ -192,7 +192,7 @@
         if (index == N) {
             goto success;
         }
-        part = parts[index].string();
+        part = parts[index].c_str();
     }
 
     if (parseKeyboard(part, &config)) {
@@ -200,7 +200,7 @@
         if (index == N) {
             goto success;
         }
-        part = parts[index].string();
+        part = parts[index].c_str();
     }
 
     if (parseNavHidden(part, &config)) {
@@ -208,7 +208,7 @@
         if (index == N) {
             goto success;
         }
-        part = parts[index].string();
+        part = parts[index].c_str();
     }
 
     if (parseNavigation(part, &config)) {
@@ -216,7 +216,7 @@
         if (index == N) {
             goto success;
         }
-        part = parts[index].string();
+        part = parts[index].c_str();
     }
 
     if (parseScreenSize(part, &config)) {
@@ -224,7 +224,7 @@
         if (index == N) {
             goto success;
         }
-        part = parts[index].string();
+        part = parts[index].c_str();
     }
 
     if (parseVersion(part, &config)) {
@@ -232,7 +232,7 @@
         if (index == N) {
             goto success;
         }
-        part = parts[index].string();
+        part = parts[index].c_str();
     }
 
     // Unrecognized.
@@ -773,8 +773,8 @@
     if (y == name || *y != 0) return false;
     String8 yName(x, y-x);
 
-    uint16_t w = (uint16_t)atoi(xName.string());
-    uint16_t h = (uint16_t)atoi(yName.string());
+    uint16_t w = (uint16_t)atoi(xName.c_str());
+    uint16_t h = (uint16_t)atoi(yName.c_str());
     if (w < h) {
         return false;
     }
@@ -805,7 +805,7 @@
     String8 xName(name, x-name);
 
     if (out) {
-        out->smallestScreenWidthDp = (uint16_t)atoi(xName.string());
+        out->smallestScreenWidthDp = (uint16_t)atoi(xName.c_str());
     }
 
     return true;
@@ -827,7 +827,7 @@
     String8 xName(name, x-name);
 
     if (out) {
-        out->screenWidthDp = (uint16_t)atoi(xName.string());
+        out->screenWidthDp = (uint16_t)atoi(xName.c_str());
     }
 
     return true;
@@ -849,7 +849,7 @@
     String8 xName(name, x-name);
 
     if (out) {
-        out->screenHeightDp = (uint16_t)atoi(xName.string());
+        out->screenHeightDp = (uint16_t)atoi(xName.c_str());
     }
 
     return true;
@@ -875,7 +875,7 @@
     String8 sdkName(name, s-name);
 
     if (out) {
-        out->sdkVersion = (uint16_t)atoi(sdkName.string());
+        out->sdkVersion = (uint16_t)atoi(sdkName.c_str());
         out->minorVersion = 0;
     }
 
diff --git a/tools/aapt/AaptUtil.cpp b/tools/aapt/AaptUtil.cpp
index 293e144..e82860d 100644
--- a/tools/aapt/AaptUtil.cpp
+++ b/tools/aapt/AaptUtil.cpp
@@ -23,7 +23,7 @@
 
 Vector<String8> split(const String8& str, const char sep) {
     Vector<String8> parts;
-    const char* p = str.string();
+    const char* p = str.c_str();
     const char* q;
 
     while (true) {
@@ -41,7 +41,7 @@
 
 Vector<String8> splitAndLowerCase(const String8& str, const char sep) {
     Vector<String8> parts;
-    const char* p = str.string();
+    const char* p = str.c_str();
     const char* q;
 
     while (true) {
diff --git a/tools/aapt/ApkBuilder.cpp b/tools/aapt/ApkBuilder.cpp
index 01e02e2..335c43b 100644
--- a/tools/aapt/ApkBuilder.cpp
+++ b/tools/aapt/ApkBuilder.cpp
@@ -36,7 +36,7 @@
             if (splitConfigs.count(*iter) > 0) {
                 // Can't have overlapping configurations.
                 fprintf(stderr, "ERROR: Split configuration '%s' is already defined "
-                        "in another split.\n", iter->toString().string());
+                        "in another split.\n", iter->toString().c_str());
                 return ALREADY_EXISTS;
             }
         }
@@ -115,10 +115,10 @@
 }
 
 void ApkSplit::print() const {
-    fprintf(stderr, "APK Split '%s'\n", mName.string());
+    fprintf(stderr, "APK Split '%s'\n", mName.c_str());
 
     std::set<OutputEntry>::const_iterator iter = mFiles.begin();
     for (; iter != mFiles.end(); iter++) {
-        fprintf(stderr, "  %s (%s)\n", iter->getPath().string(), iter->getFile()->getSourceFile().string());
+        fprintf(stderr, "  %s (%s)\n", iter->getPath().c_str(), iter->getFile()->getSourceFile().c_str());
     }
 }
diff --git a/tools/aapt/CacheUpdater.h b/tools/aapt/CacheUpdater.h
index 6fa96d6..2dc143c 100644
--- a/tools/aapt/CacheUpdater.h
+++ b/tools/aapt/CacheUpdater.h
@@ -66,7 +66,7 @@
         // Check optomistically to see if all directories exist.
         // If something in the path doesn't exist, then walk the path backwards
         // and find the place to start creating directories forward.
-        if (stat(path.string(),&s) == -1) {
+        if (stat(path.c_str(),&s) == -1) {
             // Walk backwards to find place to start creating directories
             existsPath = path;
             do {
@@ -74,7 +74,7 @@
                 // the string of paths to create.
                 toCreate = existsPath.getPathLeaf().appendPath(toCreate);
                 existsPath = existsPath.getPathDir();
-            } while (stat(existsPath.string(),&s) == -1);
+            } while (stat(existsPath.c_str(),&s) == -1);
 
             // Walk forwards and build directories as we go
             do {
@@ -82,9 +82,9 @@
                 existsPath.appendPath(toCreate.walkPath(&remains));
                 toCreate = remains;
 #ifdef _WIN32
-                _mkdir(existsPath.string());
+                _mkdir(existsPath.c_str());
 #else
-                mkdir(existsPath.string(), S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IXGRP);
+                mkdir(existsPath.c_str(), S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IXGRP);
 #endif
             } while (remains.length() > 0);
         } //if
@@ -93,8 +93,8 @@
     // Delete a file
     virtual void deleteFile(String8 path)
     {
-        if (remove(path.string()) != 0)
-            fprintf(stderr,"ERROR DELETING %s\n",path.string());
+        if (remove(path.c_str()) != 0)
+            fprintf(stderr,"ERROR DELETING %s\n",path.c_str());
     };
 
     // Process an image from source out to dest
diff --git a/tools/aapt/Command.cpp b/tools/aapt/Command.cpp
index 51cf38b..5a06b10 100644
--- a/tools/aapt/Command.cpp
+++ b/tools/aapt/Command.cpp
@@ -240,13 +240,13 @@
     }
     if (value.dataType == Res_value::TYPE_STRING) {
         String8 result = AaptXml::getResolvedAttribute(resTable, tree, attrRes, outError);
-        printf("%s='%s'", attrLabel.string(),
-                ResTable::normalizeForOutput(result.string()).string());
+        printf("%s='%s'", attrLabel.c_str(),
+                ResTable::normalizeForOutput(result.c_str()).c_str());
     } else if (Res_value::TYPE_FIRST_INT <= value.dataType &&
             value.dataType <= Res_value::TYPE_LAST_INT) {
-        printf("%s='%d'", attrLabel.string(), value.data);
+        printf("%s='%d'", attrLabel.c_str(), value.data);
     } else {
-        printf("%s='0x%x'", attrLabel.string(), (int)value.data);
+        printf("%s='0x%x'", attrLabel.c_str(), (int)value.data);
     }
 }
 
@@ -355,21 +355,21 @@
 static void printUsesPermission(const String8& name, bool optional=false, int maxSdkVersion=-1,
         const String8& requiredFeature = String8(),
         const String8& requiredNotFeature = String8()) {
-    printf("uses-permission: name='%s'", ResTable::normalizeForOutput(name.string()).string());
+    printf("uses-permission: name='%s'", ResTable::normalizeForOutput(name.c_str()).c_str());
     if (maxSdkVersion != -1) {
          printf(" maxSdkVersion='%d'", maxSdkVersion);
     }
     if (requiredFeature.length() > 0) {
-         printf(" requiredFeature='%s'", requiredFeature.string());
+         printf(" requiredFeature='%s'", requiredFeature.c_str());
     }
     if (requiredNotFeature.length() > 0) {
-         printf(" requiredNotFeature='%s'", requiredNotFeature.string());
+         printf(" requiredNotFeature='%s'", requiredNotFeature.c_str());
     }
     printf("\n");
 
     if (optional) {
         printf("optional-permission: name='%s'",
-                ResTable::normalizeForOutput(name.string()).string());
+                ResTable::normalizeForOutput(name.c_str()).c_str());
         if (maxSdkVersion != -1) {
             printf(" maxSdkVersion='%d'", maxSdkVersion);
         }
@@ -380,7 +380,7 @@
 static void printUsesPermissionSdk23(const String8& name, int maxSdkVersion=-1) {
     printf("uses-permission-sdk-23: ");
 
-    printf("name='%s'", ResTable::normalizeForOutput(name.string()).string());
+    printf("name='%s'", ResTable::normalizeForOutput(name.c_str()).c_str());
     if (maxSdkVersion != -1) {
         printf(" maxSdkVersion='%d'", maxSdkVersion);
     }
@@ -390,11 +390,11 @@
 static void printUsesImpliedPermission(const String8& name, const String8& reason,
         const int32_t maxSdkVersion = -1) {
     printf("uses-implied-permission: name='%s'",
-            ResTable::normalizeForOutput(name.string()).string());
+            ResTable::normalizeForOutput(name.c_str()).c_str());
     if (maxSdkVersion != -1) {
         printf(" maxSdkVersion='%d'", maxSdkVersion);
     }
-    printf(" reason='%s'\n", ResTable::normalizeForOutput(reason.string()).string());
+    printf(" reason='%s'\n", ResTable::normalizeForOutput(reason.c_str()).c_str());
 }
 
 Vector<String8> getNfcAidCategories(AssetManager& assets, const String8& xmlPath, bool offHost,
@@ -556,7 +556,7 @@
 
 static void printFeatureGroupImpl(const FeatureGroup& grp,
                                   const KeyedVector<String8, ImpliedFeature>* impliedFeatures) {
-    printf("feature-group: label='%s'\n", grp.label.string());
+    printf("feature-group: label='%s'\n", grp.label.c_str());
 
     if (grp.openGLESVersion > 0) {
         printf("  uses-gl-es: '0x%x'\n", grp.openGLESVersion);
@@ -570,7 +570,7 @@
 
         const String8& featureName = grp.features.keyAt(i);
         printf("  uses-feature%s: name='%s'", (required ? "" : "-not-required"),
-                ResTable::normalizeForOutput(featureName.string()).string());
+                ResTable::normalizeForOutput(featureName.c_str()).c_str());
 
         if (version > 0) {
             printf(" version='%d'", version);
@@ -589,15 +589,15 @@
         }
 
         String8 printableFeatureName(ResTable::normalizeForOutput(
-                    impliedFeature.name.string()));
+                    impliedFeature.name.c_str()));
         const char* sdk23Suffix = impliedFeature.impliedBySdk23 ? "-sdk-23" : "";
 
-        printf("  uses-feature%s: name='%s'\n", sdk23Suffix, printableFeatureName.string());
+        printf("  uses-feature%s: name='%s'\n", sdk23Suffix, printableFeatureName.c_str());
         printf("  uses-implied-feature%s: name='%s' reason='", sdk23Suffix,
-               printableFeatureName.string());
+               printableFeatureName.c_str());
         const size_t numReasons = impliedFeature.reasons.size();
         for (size_t j = 0; j < numReasons; j++) {
-            printf("%s", impliedFeature.reasons[j].string());
+            printf("%s", impliedFeature.reasons[j].c_str());
             if (j + 2 < numReasons) {
                 printf(", ");
             } else if (j + 1 < numReasons) {
@@ -649,43 +649,43 @@
                                             bool impliedBySdk23Permission) {
     if (name == "android.permission.CAMERA") {
         addImpliedFeature(impliedFeatures, "android.hardware.camera",
-                          String8::format("requested %s permission", name.string()),
+                          String8::format("requested %s permission", name.c_str()),
                           impliedBySdk23Permission);
     } else if (name == "android.permission.ACCESS_FINE_LOCATION") {
         if (targetSdk < SDK_LOLLIPOP) {
             addImpliedFeature(impliedFeatures, "android.hardware.location.gps",
-                              String8::format("requested %s permission", name.string()),
+                              String8::format("requested %s permission", name.c_str()),
                               impliedBySdk23Permission);
             addImpliedFeature(impliedFeatures, "android.hardware.location.gps",
                               String8::format("targetSdkVersion < %d", SDK_LOLLIPOP),
                               impliedBySdk23Permission);
         }
         addImpliedFeature(impliedFeatures, "android.hardware.location",
-                String8::format("requested %s permission", name.string()),
+                String8::format("requested %s permission", name.c_str()),
                 impliedBySdk23Permission);
     } else if (name == "android.permission.ACCESS_COARSE_LOCATION") {
         if (targetSdk < SDK_LOLLIPOP) {
             addImpliedFeature(impliedFeatures, "android.hardware.location.network",
-                              String8::format("requested %s permission", name.string()),
+                              String8::format("requested %s permission", name.c_str()),
                               impliedBySdk23Permission);
             addImpliedFeature(impliedFeatures, "android.hardware.location.network",
                               String8::format("targetSdkVersion < %d", SDK_LOLLIPOP),
                               impliedBySdk23Permission);
         }
         addImpliedFeature(impliedFeatures, "android.hardware.location",
-                          String8::format("requested %s permission", name.string()),
+                          String8::format("requested %s permission", name.c_str()),
                           impliedBySdk23Permission);
     } else if (name == "android.permission.ACCESS_MOCK_LOCATION" ||
                name == "android.permission.ACCESS_LOCATION_EXTRA_COMMANDS" ||
                name == "android.permission.INSTALL_LOCATION_PROVIDER") {
         addImpliedFeature(impliedFeatures, "android.hardware.location",
-                          String8::format("requested %s permission", name.string()),
+                          String8::format("requested %s permission", name.c_str()),
                           impliedBySdk23Permission);
     } else if (name == "android.permission.BLUETOOTH" ||
                name == "android.permission.BLUETOOTH_ADMIN") {
         if (targetSdk > SDK_DONUT) {
             addImpliedFeature(impliedFeatures, "android.hardware.bluetooth",
-                              String8::format("requested %s permission", name.string()),
+                              String8::format("requested %s permission", name.c_str()),
                               impliedBySdk23Permission);
             addImpliedFeature(impliedFeatures, "android.hardware.bluetooth",
                               String8::format("targetSdkVersion > %d", SDK_DONUT),
@@ -693,13 +693,13 @@
         }
     } else if (name == "android.permission.RECORD_AUDIO") {
         addImpliedFeature(impliedFeatures, "android.hardware.microphone",
-                          String8::format("requested %s permission", name.string()),
+                          String8::format("requested %s permission", name.c_str()),
                           impliedBySdk23Permission);
     } else if (name == "android.permission.ACCESS_WIFI_STATE" ||
                name == "android.permission.CHANGE_WIFI_STATE" ||
                name == "android.permission.CHANGE_WIFI_MULTICAST_STATE") {
         addImpliedFeature(impliedFeatures, "android.hardware.wifi",
-                          String8::format("requested %s permission", name.string()),
+                          String8::format("requested %s permission", name.c_str()),
                           impliedBySdk23Permission);
     } else if (name == "android.permission.CALL_PHONE" ||
                name == "android.permission.CALL_PRIVILEGED" ||
@@ -746,7 +746,7 @@
     for (size_t i = 0; i < bundle->getPackageIncludes().size(); i++) {
       const String8& assetPath = bundle->getPackageIncludes()[i];
       if (!assets.addAssetPath(assetPath, NULL)) {
-        fprintf(stderr, "ERROR: included asset path %s could not be loaded\n", assetPath.string());
+        fprintf(stderr, "ERROR: included asset path %s could not be loaded\n", assetPath.c_str());
         return 1;
       }
     }
@@ -890,7 +890,7 @@
                     goto bail;
                 }
                 String8 tag(ctag16);
-                //printf("Depth %d tag %s\n", depth, tag.string());
+                //printf("Depth %d tag %s\n", depth, tag.c_str());
                 if (depth == 1) {
                     if (tag != "manifest") {
                         SourcePos(manifestFile, tree.getLineNumber()).error(
@@ -898,14 +898,14 @@
                         goto bail;
                     }
                     String8 pkg = AaptXml::getAttribute(tree, NULL, "package", NULL);
-                    printf("package: %s\n", ResTable::normalizeForOutput(pkg.string()).string());
+                    printf("package: %s\n", ResTable::normalizeForOutput(pkg.c_str()).c_str());
                 } else if (depth == 2) {
                     if (tag == "permission") {
                         String8 error;
                         String8 name = AaptXml::getAttribute(tree, NAME_ATTR, &error);
                         if (error != "") {
                             SourcePos(manifestFile, tree.getLineNumber()).error(
-                                    "ERROR getting 'android:name': %s", error.string());
+                                    "ERROR getting 'android:name': %s", error.c_str());
                             goto bail;
                         }
 
@@ -915,13 +915,13 @@
                             goto bail;
                         }
                         printf("permission: %s\n",
-                                ResTable::normalizeForOutput(name.string()).string());
+                                ResTable::normalizeForOutput(name.c_str()).c_str());
                     } else if (tag == "uses-permission") {
                         String8 error;
                         String8 name = AaptXml::getAttribute(tree, NAME_ATTR, &error);
                         if (error != "") {
                             SourcePos(manifestFile, tree.getLineNumber()).error(
-                                    "ERROR getting 'android:name' attribute: %s", error.string());
+                                    "ERROR getting 'android:name' attribute: %s", error.c_str());
                             goto bail;
                         }
 
@@ -938,7 +938,7 @@
                         String8 name = AaptXml::getAttribute(tree, NAME_ATTR, &error);
                         if (error != "") {
                             SourcePos(manifestFile, tree.getLineNumber()).error(
-                                    "ERROR getting 'android:name' attribute: %s", error.string());
+                                    "ERROR getting 'android:name' attribute: %s", error.c_str());
                             goto bail;
                         }
 
@@ -1138,7 +1138,7 @@
                             const size_t N = supportedInput.size();
                             for (size_t i=0; i<N; i++) {
                                 printf("%s", ResTable::normalizeForOutput(
-                                        supportedInput[i].string()).string());
+                                        supportedInput[i].c_str()).c_str());
                                 if (i != N - 1) {
                                     printf("' '");
                                 } else {
@@ -1157,27 +1157,27 @@
                                 printf("launchable-activity:");
                                 if (aName.length() > 0) {
                                     printf(" name='%s' ",
-                                            ResTable::normalizeForOutput(aName.string()).string());
+                                            ResTable::normalizeForOutput(aName.c_str()).c_str());
                                 }
                                 printf(" label='%s' icon='%s'\n",
-                                       ResTable::normalizeForOutput(activityLabel.string())
-                                                .string(),
-                                       ResTable::normalizeForOutput(activityIcon.string())
-                                                .string());
+                                       ResTable::normalizeForOutput(activityLabel.c_str())
+                                                .c_str(),
+                                       ResTable::normalizeForOutput(activityIcon.c_str())
+                                                .c_str());
                             }
                             if (isLeanbackLauncherActivity) {
                                 printf("leanback-launchable-activity:");
                                 if (aName.length() > 0) {
                                     printf(" name='%s' ",
-                                            ResTable::normalizeForOutput(aName.string()).string());
+                                            ResTable::normalizeForOutput(aName.c_str()).c_str());
                                 }
                                 printf(" label='%s' icon='%s' banner='%s'\n",
-                                       ResTable::normalizeForOutput(activityLabel.string())
-                                                .string(),
-                                       ResTable::normalizeForOutput(activityIcon.string())
-                                                .string(),
-                                       ResTable::normalizeForOutput(activityBanner.string())
-                                                .string());
+                                       ResTable::normalizeForOutput(activityLabel.c_str())
+                                                .c_str(),
+                                       ResTable::normalizeForOutput(activityIcon.c_str())
+                                                .c_str(),
+                                       ResTable::normalizeForOutput(activityBanner.c_str())
+                                                .c_str());
                             }
                         }
                         if (!hasIntentFilter) {
@@ -1265,7 +1265,7 @@
                     goto bail;
                 }
                 String8 tag(ctag16);
-                //printf("Depth %d,  %s\n", depth, tag.string());
+                //printf("Depth %d,  %s\n", depth, tag.c_str());
                 if (depth == 1) {
                     if (tag != "manifest") {
                         SourcePos(manifestFile, tree.getLineNumber()).error(
@@ -1274,13 +1274,13 @@
                     }
                     pkg = AaptXml::getAttribute(tree, NULL, "package", NULL);
                     printf("package: name='%s' ",
-                            ResTable::normalizeForOutput(pkg.string()).string());
+                            ResTable::normalizeForOutput(pkg.c_str()).c_str());
                     int32_t versionCode = AaptXml::getIntegerAttribute(tree, VERSION_CODE_ATTR,
                             &error);
                     if (error != "") {
                         SourcePos(manifestFile, tree.getLineNumber()).error(
                                 "ERROR getting 'android:versionCode' attribute: %s",
-                                error.string());
+                                error.c_str());
                         goto bail;
                     }
                     if (versionCode > 0) {
@@ -1293,16 +1293,16 @@
                     if (error != "") {
                         SourcePos(manifestFile, tree.getLineNumber()).error(
                                 "ERROR getting 'android:versionName' attribute: %s",
-                                error.string());
+                                error.c_str());
                         goto bail;
                     }
                     printf("versionName='%s'",
-                            ResTable::normalizeForOutput(versionName.string()).string());
+                            ResTable::normalizeForOutput(versionName.c_str()).c_str());
 
                     String8 splitName = AaptXml::getAttribute(tree, NULL, "split");
                     if (!splitName.isEmpty()) {
                         printf(" split='%s'", ResTable::normalizeForOutput(
-                                    splitName.string()).string());
+                                    splitName.c_str()).c_str());
                     }
 
                     // For 'platformBuildVersionName', using both string and int type as a fallback
@@ -1313,7 +1313,7 @@
                             AaptXml::getIntegerAttribute(tree, NULL, "platformBuildVersionName", 0,
                                                          NULL);
                     if (platformBuildVersionName != "") {
-                        printf(" platformBuildVersionName='%s'", platformBuildVersionName.string());
+                        printf(" platformBuildVersionName='%s'", platformBuildVersionName.c_str());
                     } else if (platformBuildVersionNameInt > 0) {
                         printf(" platformBuildVersionName='%d'", platformBuildVersionNameInt);
                     }
@@ -1326,7 +1326,7 @@
                             AaptXml::getIntegerAttribute(tree, NULL, "platformBuildVersionCode", 0,
                                                          NULL);
                     if (platformBuildVersionCode != "") {
-                        printf(" platformBuildVersionCode='%s'", platformBuildVersionCode.string());
+                        printf(" platformBuildVersionCode='%s'", platformBuildVersionCode.c_str());
                     } else if (platformBuildVersionCodeInt > 0) {
                         printf(" platformBuildVersionCode='%d'", platformBuildVersionCodeInt);
                     }
@@ -1336,7 +1336,7 @@
                     if (error != "") {
                         SourcePos(manifestFile, tree.getLineNumber()).error(
                                 "ERROR getting 'android:compileSdkVersion' attribute: %s",
-                                error.string());
+                                error.c_str());
                         goto bail;
                     }
                     if (compileSdkVersion > 0) {
@@ -1347,7 +1347,7 @@
                             COMPILE_SDK_VERSION_CODENAME_ATTR, &error);
                     if (compileSdkVersionCodename != "") {
                         printf(" compileSdkVersionCodename='%s'", ResTable::normalizeForOutput(
-                                compileSdkVersionCodename.string()).string());
+                                compileSdkVersionCodename.c_str()).c_str());
                     }
 
                     printf("\n");
@@ -1357,7 +1357,7 @@
                     if (error != "") {
                         SourcePos(manifestFile, tree.getLineNumber()).error(
                                 "ERROR getting 'android:installLocation' attribute: %s",
-                                error.string());
+                                error.c_str());
                         goto bail;
                     }
 
@@ -1387,7 +1387,7 @@
                         String8 label;
                         const size_t NL = locales.size();
                         for (size_t i=0; i<NL; i++) {
-                            const char* localeStr =  locales[i].string();
+                            const char* localeStr =  locales[i].c_str();
                             assets.setConfiguration(config, localeStr != NULL ? localeStr : "");
                             String8 llabel = AaptXml::getResolvedAttribute(res, tree, LABEL_ATTR,
                                     &error);
@@ -1395,13 +1395,13 @@
                                 if (localeStr == NULL || strlen(localeStr) == 0) {
                                     label = llabel;
                                     printf("application-label:'%s'\n",
-                                            ResTable::normalizeForOutput(llabel.string()).string());
+                                            ResTable::normalizeForOutput(llabel.c_str()).c_str());
                                 } else {
                                     if (label == "") {
                                         label = llabel;
                                     }
                                     printf("application-label-%s:'%s'\n", localeStr,
-                                           ResTable::normalizeForOutput(llabel.string()).string());
+                                           ResTable::normalizeForOutput(llabel.c_str()).c_str());
                                 }
                             }
                         }
@@ -1415,7 +1415,7 @@
                                     &error);
                             if (icon != "") {
                                 printf("application-icon-%d:'%s'\n", densities[i],
-                                        ResTable::normalizeForOutput(icon.string()).string());
+                                        ResTable::normalizeForOutput(icon.c_str()).c_str());
                             }
                         }
                         assets.setConfiguration(config);
@@ -1423,7 +1423,7 @@
                         String8 icon = AaptXml::getResolvedAttribute(res, tree, ICON_ATTR, &error);
                         if (error != "") {
                             SourcePos(manifestFile, tree.getLineNumber()).error(
-                                    "ERROR getting 'android:icon' attribute: %s", error.string());
+                                    "ERROR getting 'android:icon' attribute: %s", error.c_str());
                             goto bail;
                         }
                         int32_t testOnly = AaptXml::getIntegerAttribute(tree, TEST_ONLY_ATTR, 0,
@@ -1431,7 +1431,7 @@
                         if (error != "") {
                             SourcePos(manifestFile, tree.getLineNumber()).error(
                                     "ERROR getting 'android:testOnly' attribute: %s",
-                                    error.string());
+                                    error.c_str());
                             goto bail;
                         }
 
@@ -1439,15 +1439,15 @@
                                                                        &error);
                         if (error != "") {
                             SourcePos(manifestFile, tree.getLineNumber()).error(
-                                    "ERROR getting 'android:banner' attribute: %s", error.string());
+                                    "ERROR getting 'android:banner' attribute: %s", error.c_str());
                             goto bail;
                         }
                         printf("application: label='%s' ",
-                                ResTable::normalizeForOutput(label.string()).string());
-                        printf("icon='%s'", ResTable::normalizeForOutput(icon.string()).string());
+                                ResTable::normalizeForOutput(label.c_str()).c_str());
+                        printf("icon='%s'", ResTable::normalizeForOutput(icon.c_str()).c_str());
                         if (banner != "") {
                             printf(" banner='%s'",
-                                   ResTable::normalizeForOutput(banner.string()).string());
+                                   ResTable::normalizeForOutput(banner.c_str()).c_str());
                         }
                         printf("\n");
                         if (testOnly != 0) {
@@ -1458,7 +1458,7 @@
                                 ISGAME_ATTR, 0, &error);
                         if (error != "") {
                             SourcePos(manifestFile, tree.getLineNumber()).error(
-                                    "ERROR getting 'android:isGame' attribute: %s", error.string());
+                                    "ERROR getting 'android:isGame' attribute: %s", error.c_str());
                             goto bail;
                         }
                         if (isGame != 0) {
@@ -1470,7 +1470,7 @@
                         if (error != "") {
                             SourcePos(manifestFile, tree.getLineNumber()).error(
                                     "ERROR getting 'android:debuggable' attribute: %s",
-                                    error.string());
+                                    error.c_str());
                             goto bail;
                         }
                         if (debuggable != 0) {
@@ -1500,12 +1500,12 @@
                             if (error != "") {
                                 SourcePos(manifestFile, tree.getLineNumber()).error(
                                         "ERROR getting 'android:minSdkVersion' attribute: %s",
-                                        error.string());
+                                        error.c_str());
                                 goto bail;
                             }
                             if (name == "Donut") targetSdk = SDK_DONUT;
                             printf("sdkVersion:'%s'\n",
-                                    ResTable::normalizeForOutput(name.string()).string());
+                                    ResTable::normalizeForOutput(name.c_str()).c_str());
                         } else if (code != -1) {
                             targetSdk = code;
                             printf("sdkVersion:'%d'\n", code);
@@ -1522,7 +1522,7 @@
                             if (error != "") {
                                 SourcePos(manifestFile, tree.getLineNumber()).error(
                                         "ERROR getting 'android:targetSdkVersion' attribute: %s",
-                                        error.string());
+                                        error.c_str());
                                 goto bail;
                             }
                             if (name == "Donut" && targetSdk < SDK_DONUT) {
@@ -1532,7 +1532,7 @@
                                 targetSdk = SDK_CUR_DEVELOPMENT;
                             }
                             printf("targetSdkVersion:'%s'\n",
-                                    ResTable::normalizeForOutput(name.string()).string());
+                                    ResTable::normalizeForOutput(name.c_str()).c_str());
                         } else if (code != -1) {
                             if (targetSdk < code) {
                                 targetSdk = code;
@@ -1592,7 +1592,7 @@
                         group.label = AaptXml::getResolvedAttribute(res, tree, LABEL_ATTR, &error);
                         if (error != "") {
                             SourcePos(manifestFile, tree.getLineNumber()).error(
-                                    "ERROR getting 'android:label' attribute: %s", error.string());
+                                    "ERROR getting 'android:label' attribute: %s", error.c_str());
                             goto bail;
                         }
                         featureGroups.add(group);
@@ -1608,7 +1608,7 @@
                             if (error != "") {
                                 SourcePos(manifestFile, tree.getLineNumber()).error(
                                         "failed to read attribute 'android:required': %s",
-                                        error.string());
+                                        error.c_str());
                                 goto bail;
                             }
 
@@ -1617,7 +1617,7 @@
                             if (error != "") {
                                 SourcePos(manifestFile, tree.getLineNumber()).error(
                                         "failed to read attribute 'android:version': %s",
-                                        error.string());
+                                        error.c_str());
                                 goto bail;
                             }
 
@@ -1638,7 +1638,7 @@
                         String8 name = AaptXml::getAttribute(tree, NAME_ATTR, &error);
                         if (error != "") {
                             SourcePos(manifestFile, tree.getLineNumber()).error(
-                                    "ERROR getting 'android:name' attribute: %s", error.string());
+                                    "ERROR getting 'android:name' attribute: %s", error.c_str());
                             goto bail;
                         }
 
@@ -1682,7 +1682,7 @@
                         String8 name = AaptXml::getAttribute(tree, NAME_ATTR, &error);
                         if (error != "") {
                             SourcePos(manifestFile, tree.getLineNumber()).error(
-                                    "ERROR getting 'android:name' attribute: %s", error.string());
+                                    "ERROR getting 'android:name' attribute: %s", error.c_str());
                             goto bail;
                         }
 
@@ -1701,37 +1701,37 @@
                         String8 name = AaptXml::getAttribute(tree, NAME_ATTR, &error);
                         if (name != "" && error == "") {
                             printf("uses-package:'%s'\n",
-                                    ResTable::normalizeForOutput(name.string()).string());
+                                    ResTable::normalizeForOutput(name.c_str()).c_str());
                         } else {
                             SourcePos(manifestFile, tree.getLineNumber()).error(
-                                    "ERROR getting 'android:name' attribute: %s", error.string());
+                                    "ERROR getting 'android:name' attribute: %s", error.c_str());
                             goto bail;
                         }
                     } else if (tag == "original-package") {
                         String8 name = AaptXml::getAttribute(tree, NAME_ATTR, &error);
                         if (name != "" && error == "") {
                             printf("original-package:'%s'\n",
-                                    ResTable::normalizeForOutput(name.string()).string());
+                                    ResTable::normalizeForOutput(name.c_str()).c_str());
                         } else {
                             SourcePos(manifestFile, tree.getLineNumber()).error(
-                                    "ERROR getting 'android:name' attribute: %s", error.string());
+                                    "ERROR getting 'android:name' attribute: %s", error.c_str());
                             goto bail;
                         }
                     } else if (tag == "supports-gl-texture") {
                         String8 name = AaptXml::getAttribute(tree, NAME_ATTR, &error);
                         if (name != "" && error == "") {
                             printf("supports-gl-texture:'%s'\n",
-                                    ResTable::normalizeForOutput(name.string()).string());
+                                    ResTable::normalizeForOutput(name.c_str()).c_str());
                         } else {
                             SourcePos(manifestFile, tree.getLineNumber()).error(
-                                    "ERROR getting 'android:name' attribute: %s", error.string());
+                                    "ERROR getting 'android:name' attribute: %s", error.c_str());
                             goto bail;
                         }
                     } else if (tag == "compatible-screens") {
                         printCompatibleScreens(tree, &error);
                         if (error != "") {
                             SourcePos(manifestFile, tree.getLineNumber()).error(
-                                    "ERROR getting compatible screens: %s", error.string());
+                                    "ERROR getting compatible screens: %s", error.c_str());
                             goto bail;
                         }
                         depth--;
@@ -1742,8 +1742,8 @@
                                                                       &error);
                             if (publicKey != "" && error == "") {
                                 printf("package-verifier: name='%s' publicKey='%s'\n",
-                                        ResTable::normalizeForOutput(name.string()).string(),
-                                        ResTable::normalizeForOutput(publicKey.string()).string());
+                                        ResTable::normalizeForOutput(name.c_str()).c_str(),
+                                        ResTable::normalizeForOutput(publicKey.c_str()).c_str());
                             }
                         }
                     }
@@ -1769,7 +1769,7 @@
                             if (error != "") {
                                 SourcePos(manifestFile, tree.getLineNumber()).error(
                                         "ERROR getting 'android:name' attribute: %s",
-                                        error.string());
+                                        error.c_str());
                                 goto bail;
                             }
 
@@ -1778,7 +1778,7 @@
                             if (error != "") {
                                 SourcePos(manifestFile, tree.getLineNumber()).error(
                                         "ERROR getting 'android:label' attribute: %s",
-                                        error.string());
+                                        error.c_str());
                                 goto bail;
                             }
 
@@ -1787,7 +1787,7 @@
                             if (error != "") {
                                 SourcePos(manifestFile, tree.getLineNumber()).error(
                                         "ERROR getting 'android:icon' attribute: %s",
-                                        error.string());
+                                        error.c_str());
                                 goto bail;
                             }
 
@@ -1796,7 +1796,7 @@
                             if (error != "") {
                                 SourcePos(manifestFile, tree.getLineNumber()).error(
                                         "ERROR getting 'android:banner' attribute: %s",
-                                        error.string());
+                                        error.c_str());
                                 goto bail;
                             }
 
@@ -1824,14 +1824,14 @@
                             if (error != "") {
                                 SourcePos(manifestFile, tree.getLineNumber()).error(
                                         "ERROR getting 'android:name' attribute for uses-library"
-                                        " %s", error.string());
+                                        " %s", error.c_str());
                                 goto bail;
                             }
                             int req = AaptXml::getIntegerAttribute(tree,
                                     REQUIRED_ATTR, 1);
                             printf("uses-library%s:'%s'\n",
                                     req ? "" : "-not-required", ResTable::normalizeForOutput(
-                                            libraryName.string()).string());
+                                            libraryName.c_str()).c_str());
                         } else if (tag == "receiver") {
                             withinReceiver = true;
                             receiverName = AaptXml::getAttribute(tree, NAME_ATTR, &error);
@@ -1839,7 +1839,7 @@
                             if (error != "") {
                                 SourcePos(manifestFile, tree.getLineNumber()).error(
                                         "ERROR getting 'android:name' attribute for receiver:"
-                                        " %s", error.string());
+                                        " %s", error.c_str());
                                 goto bail;
                             }
 
@@ -1853,7 +1853,7 @@
                                 SourcePos(manifestFile, tree.getLineNumber()).error(
                                         "ERROR getting 'android:permission' attribute for"
                                         " receiver '%s': %s",
-                                        receiverName.string(), error.string());
+                                        receiverName.c_str(), error.c_str());
                             }
                         } else if (tag == "service") {
                             withinService = true;
@@ -1862,7 +1862,7 @@
                             if (error != "") {
                                 SourcePos(manifestFile, tree.getLineNumber()).error(
                                         "ERROR getting 'android:name' attribute for "
-                                        "service:%s", error.string());
+                                        "service:%s", error.c_str());
                                 goto bail;
                             }
 
@@ -1887,7 +1887,7 @@
                             } else {
                                 SourcePos(manifestFile, tree.getLineNumber()).error(
                                         "ERROR getting 'android:permission' attribute for "
-                                        "service '%s': %s", serviceName.string(), error.string());
+                                        "service '%s': %s", serviceName.c_str(), error.c_str());
                             }
                         } else if (tag == "provider") {
                             withinProvider = true;
@@ -1897,7 +1897,7 @@
                             if (error != "") {
                                 SourcePos(manifestFile, tree.getLineNumber()).error(
                                         "ERROR getting 'android:exported' attribute for provider:"
-                                        " %s", error.string());
+                                        " %s", error.c_str());
                                 goto bail;
                             }
 
@@ -1906,7 +1906,7 @@
                             if (error != "") {
                                 SourcePos(manifestFile, tree.getLineNumber()).error(
                                         "ERROR getting 'android:grantUriPermissions' attribute for "
-                                        "provider: %s", error.string());
+                                        "provider: %s", error.c_str());
                                 goto bail;
                             }
 
@@ -1915,7 +1915,7 @@
                             if (error != "") {
                                 SourcePos(manifestFile, tree.getLineNumber()).error(
                                         "ERROR getting 'android:permission' attribute for "
-                                        "provider: %s", error.string());
+                                        "provider: %s", error.c_str());
                                 goto bail;
                             }
 
@@ -1928,11 +1928,11 @@
                             if (error != "") {
                                 SourcePos(manifestFile, tree.getLineNumber()).error(
                                         "ERROR getting 'android:name' attribute for "
-                                        "meta-data: %s", error.string());
+                                        "meta-data: %s", error.c_str());
                                 goto bail;
                             }
                             printf("meta-data: name='%s' ",
-                                    ResTable::normalizeForOutput(metaDataName.string()).string());
+                                    ResTable::normalizeForOutput(metaDataName.c_str()).c_str());
                             printResolvedResourceAttribute(res, tree, VALUE_ATTR, String8("value"),
                                     &error);
                             if (error != "") {
@@ -1944,7 +1944,7 @@
                                     SourcePos(manifestFile, tree.getLineNumber()).error(
                                             "ERROR getting 'android:value' or "
                                             "'android:resource' attribute for "
-                                            "meta-data: %s", error.string());
+                                            "meta-data: %s", error.c_str());
                                     goto bail;
                                 }
                             }
@@ -1956,7 +1956,7 @@
                             } else {
                                 SourcePos(manifestFile, tree.getLineNumber()).error(
                                         "ERROR getting 'android:name' attribute: %s",
-                                        error.string());
+                                        error.c_str());
                                 goto bail;
                             }
                         }
@@ -1969,13 +1969,13 @@
                             Feature feature(true);
 
                             int32_t featureVers = AaptXml::getIntegerAttribute(
-                                    tree, androidSchema.string(), "version", 0, &error);
+                                    tree, androidSchema.c_str(), "version", 0, &error);
                             if (error == "") {
                                 feature.version = featureVers;
                             } else {
                                 SourcePos(manifestFile, tree.getLineNumber()).error(
                                         "failed to read attribute 'android:version': %s",
-                                        error.string());
+                                        error.c_str());
                                 goto bail;
                             }
 
@@ -2016,8 +2016,8 @@
                         if (error != "") {
                             SourcePos(manifestFile, tree.getLineNumber()).error(
                                     "ERROR getting 'android:name' attribute for "
-                                    "meta-data tag in service '%s': %s", serviceName.string(),
-                                    error.string());
+                                    "meta-data tag in service '%s': %s", serviceName.c_str(),
+                                    error.c_str());
                             goto bail;
                         }
 
@@ -2034,7 +2034,7 @@
                                 SourcePos(manifestFile, tree.getLineNumber()).error(
                                         "ERROR getting 'android:resource' attribute for "
                                         "meta-data tag in service '%s': %s",
-                                        serviceName.string(), error.string());
+                                        serviceName.c_str(), error.c_str());
                                 goto bail;
                             }
 
@@ -2043,7 +2043,7 @@
                             if (error != "") {
                                 SourcePos(manifestFile, tree.getLineNumber()).error(
                                         "ERROR getting AID category for service '%s'",
-                                        serviceName.string());
+                                        serviceName.c_str());
                                 goto bail;
                             }
 
@@ -2064,7 +2064,7 @@
                         action = AaptXml::getAttribute(tree, NAME_ATTR, &error);
                         if (error != "") {
                             SourcePos(manifestFile, tree.getLineNumber()).error(
-                                    "ERROR getting 'android:name' attribute: %s", error.string());
+                                    "ERROR getting 'android:name' attribute: %s", error.c_str());
                             goto bail;
                         }
 
@@ -2120,7 +2120,7 @@
                         String8 category = AaptXml::getAttribute(tree, NAME_ATTR, &error);
                         if (error != "") {
                             SourcePos(manifestFile, tree.getLineNumber()).error(
-                                    "ERROR getting 'name' attribute: %s", error.string());
+                                    "ERROR getting 'name' attribute: %s", error.c_str());
                             goto bail;
                         }
                         if (withinActivity) {
@@ -2352,7 +2352,7 @@
             printf("locales:");
             const size_t NL = locales.size();
             for (size_t i=0; i<NL; i++) {
-                const char* localeStr =  locales[i].string();
+                const char* localeStr =  locales[i].c_str();
                 if (localeStr == NULL || strlen(localeStr) == 0) {
                     localeStr = "--_--";
                 }
@@ -2373,7 +2373,7 @@
                     SortedVector<String8> architectures;
                     for (size_t i=0; i<dir->getFileCount(); i++) {
                         architectures.add(ResTable::normalizeForOutput(
-                                dir->getFileName(i).string()));
+                                dir->getFileName(i).c_str()));
                     }
 
                     bool outputAltNativeCode = false;
@@ -2401,7 +2401,7 @@
                         }
 
                         if (index >= 0) {
-                            printf("native-code: '%s'\n", architectures[index].string());
+                            printf("native-code: '%s'\n", architectures[index].c_str());
                             architectures.removeAt(index);
                             outputAltNativeCode = true;
                         }
@@ -2414,7 +2414,7 @@
                         }
                         printf("native-code:");
                         for (size_t i = 0; i < archCount; i++) {
-                            printf(" '%s'", architectures[i].string());
+                            printf(" '%s'", architectures[i].c_str());
                         }
                         printf("\n");
                     }
@@ -2428,7 +2428,7 @@
             res.getConfigurations(&configs);
             const size_t N = configs.size();
             for (size_t i=0; i<N; i++) {
-                printf("%s\n", configs[i].toString().string());
+                printf("%s\n", configs[i].toString().c_str());
             }
         } else {
             fprintf(stderr, "ERROR: unknown dump option '%s'\n", option);
@@ -2486,15 +2486,15 @@
     for (int i = 1; i < bundle->getFileSpecCount(); i++) {
         const char* fileName = bundle->getFileSpecEntry(i);
 
-        if (strcasecmp(String8(fileName).getPathExtension().string(), ".gz") == 0) {
+        if (strcasecmp(String8(fileName).getPathExtension().c_str(), ".gz") == 0) {
             printf(" '%s'... (from gzip)\n", fileName);
-            result = zip->addGzip(fileName, String8(fileName).getBasePath().string(), NULL);
+            result = zip->addGzip(fileName, String8(fileName).getBasePath().c_str(), NULL);
         } else {
             if (bundle->getJunkPath()) {
                 String8 storageName = String8(fileName).getPathLeaf();
                 printf(" '%s' as '%s'...\n", fileName,
-                        ResTable::normalizeForOutput(storageName.string()).string());
-                result = zip->add(fileName, storageName.string(),
+                        ResTable::normalizeForOutput(storageName.c_str()).c_str());
+                result = zip->add(fileName, storageName.c_str(),
                                   bundle->getCompressionMethod(), NULL);
             } else {
                 printf(" '%s'...\n", fileName);
@@ -2581,7 +2581,7 @@
     for (size_t i = 0; i < numDirs; i++) {
         bool ignore = ignoreConfig;
         const sp<AaptDir>& subDir = dir->getDirs().valueAt(i);
-        const char* dirStr = subDir->getLeaf().string();
+        const char* dirStr = subDir->getLeaf().c_str();
         if (!ignore && strstr(dirStr, "mipmap") == dirStr) {
             ignore = true;
         }
@@ -2604,7 +2604,7 @@
             }
             if (err != NO_ERROR) {
                 fprintf(stderr, "Failed to add %s (%s) to builder.\n",
-                        gp->getPath().string(), gp->getFiles()[j]->getPrintableSource().string());
+                        gp->getPath().c_str(), gp->getFiles()[j]->getPrintableSource().c_str());
                 return err;
             }
         }
@@ -2620,13 +2620,13 @@
     String8 ext(original.getPathExtension());
     if (ext == String8(".apk")) {
         return String8::format("%s_%s%s",
-                original.getBasePath().string(),
-                split->getDirectorySafeName().string(),
-                ext.string());
+                original.getBasePath().c_str(),
+                split->getDirectorySafeName().c_str(),
+                ext.c_str());
     }
 
-    return String8::format("%s_%s", original.string(),
-            split->getDirectorySafeName().string());
+    return String8::format("%s_%s", original.c_str(),
+            split->getDirectorySafeName().c_str());
 }
 
 /*
@@ -2712,7 +2712,7 @@
         for (size_t i = 0; i < numSplits; i++) {
             std::set<ConfigDescription> configs;
             if (!AaptConfig::parseCommaSeparatedList(splitStrs[i], &configs)) {
-                fprintf(stderr, "ERROR: failed to parse split configuration '%s'\n", splitStrs[i].string());
+                fprintf(stderr, "ERROR: failed to parse split configuration '%s'\n", splitStrs[i].c_str());
                 goto bail;
             }
 
@@ -2835,7 +2835,7 @@
             String8 outputPath = buildApkName(String8(outputAPKFile), split);
             err = writeAPK(bundle, outputPath, split);
             if (err != NO_ERROR) {
-                fprintf(stderr, "ERROR: packaging of '%s' failed\n", outputPath.string());
+                fprintf(stderr, "ERROR: packaging of '%s' failed\n", outputPath.c_str());
                 goto bail;
             }
         }
diff --git a/tools/aapt/CrunchCache.cpp b/tools/aapt/CrunchCache.cpp
index 7b8a576..1f2febe 100644
--- a/tools/aapt/CrunchCache.cpp
+++ b/tools/aapt/CrunchCache.cpp
@@ -44,7 +44,7 @@
         // This efficiently strips the source directory prefix from our path.
         // Also, String8 doesn't have a substring method so this is what we've
         // got to work with.
-        const char* rPathPtr = mSourceFiles.keyAt(0).string()+mSourcePath.length();
+        const char* rPathPtr = mSourceFiles.keyAt(0).c_str()+mSourcePath.length();
         // Strip leading slash if present
         int offset = 0;
         if (rPathPtr[0] == OS_PATH_SEPARATOR)
diff --git a/tools/aapt/DirectoryWalker.h b/tools/aapt/DirectoryWalker.h
index 88031d0..cea3a6e 100644
--- a/tools/aapt/DirectoryWalker.h
+++ b/tools/aapt/DirectoryWalker.h
@@ -57,7 +57,7 @@
     virtual bool openDir(String8 path) {
         mBasePath = path;
         dir = NULL;
-        dir = opendir(mBasePath.string() );
+        dir = opendir(mBasePath.c_str() );
 
         if (dir == NULL)
             return false;
@@ -78,7 +78,7 @@
         mEntry = *entryPtr;
         // Get stats
         String8 fullPath = mBasePath.appendPathCopy(mEntry.d_name);
-        stat(fullPath.string(),&mStats);
+        stat(fullPath.c_str(),&mStats);
         return &mEntry;
     };
     // Get the stats for the current entry
diff --git a/tools/aapt/FileFinder.cpp b/tools/aapt/FileFinder.cpp
index c9d0744..a5c19806 100644
--- a/tools/aapt/FileFinder.cpp
+++ b/tools/aapt/FileFinder.cpp
@@ -59,14 +59,14 @@
 
         String8 fullPath = basePath.appendPathCopy(entryName);
         // If this entry is a directory we'll recurse into it
-        if (isDirectory(fullPath.string()) ) {
+        if (isDirectory(fullPath.c_str()) ) {
             DirectoryWalker* copy = dw->clone();
             findFiles(fullPath, extensions, fileStore,copy);
             delete copy;
         }
 
         // If this entry is a file, we'll pass it over to checkAndAddFile
-        if (isFile(fullPath.string()) ) {
+        if (isFile(fullPath.c_str()) ) {
             checkAndAddFile(fullPath,dw->entryStats(),extensions,fileStore);
         }
     }
diff --git a/tools/aapt/Images.cpp b/tools/aapt/Images.cpp
index 627a231..c6c7e96 100644
--- a/tools/aapt/Images.cpp
+++ b/tools/aapt/Images.cpp
@@ -1328,13 +1328,13 @@
 
     png_init_io(read_ptr, fp);
 
-    read_png(printableName.string(), read_ptr, read_info, imageInfo);
+    read_png(printableName.c_str(), read_ptr, read_info, imageInfo);
 
     const size_t nameLen = file->getPath().length();
     if (nameLen > 6) {
-        const char* name = file->getPath().string();
+        const char* name = file->getPath().c_str();
         if (name[nameLen-5] == '9' && name[nameLen-6] == '.') {
-            if (do_9patch(printableName.string(), imageInfo) != NO_ERROR) {
+            if (do_9patch(printableName.c_str(), imageInfo) != NO_ERROR) {
                 return false;
             }
         }
@@ -1349,7 +1349,7 @@
         return false;
     }
 
-    write_png(printableName.string(), write_ptr, write_info, *imageInfo, bundle);
+    write_png(printableName.c_str(), write_ptr, write_info, *imageInfo, bundle);
 
     return true;
 }
@@ -1360,7 +1360,7 @@
     String8 ext(file->getPath().getPathExtension());
 
     // We currently only process PNG images.
-    if (strcmp(ext.string(), ".png") != 0) {
+    if (strcmp(ext.c_str(), ".png") != 0) {
         return NO_ERROR;
     }
 
@@ -1371,7 +1371,7 @@
     String8 printableName(file->getPrintableSource());
 
     if (bundle->getVerbose()) {
-        printf("Processing image: %s\n", printableName.string());
+        printf("Processing image: %s\n", printableName.c_str());
     }
 
     png_structp read_ptr = NULL;
@@ -1385,9 +1385,9 @@
 
     status_t error = UNKNOWN_ERROR;
 
-    fp = fopen(file->getSourceFile().string(), "rb");
+    fp = fopen(file->getSourceFile().c_str(), "rb");
     if (fp == NULL) {
-        fprintf(stderr, "%s: ERROR: Unable to open PNG file\n", printableName.string());
+        fprintf(stderr, "%s: ERROR: Unable to open PNG file\n", printableName.c_str());
         goto bail;
     }
 
@@ -1434,7 +1434,7 @@
         size_t newSize = file->getSize();
         float factor = ((float)newSize)/oldSize;
         int percent = (int)(factor*100);
-        printf("    (processed image %s: %d%% size of source)\n", printableName.string(), percent);
+        printf("    (processed image %s: %d%% size of source)\n", printableName.c_str(), percent);
     }
 
 bail:
@@ -1450,7 +1450,7 @@
 
     if (error != NO_ERROR) {
         fprintf(stderr, "ERROR: Failure processing PNG image %s\n",
-                file->getPrintableSource().string());
+                file->getPrintableSource().c_str());
     }
     return error;
 }
@@ -1470,13 +1470,13 @@
     status_t error = UNKNOWN_ERROR;
 
     if (bundle->getVerbose()) {
-        printf("Processing image to cache: %s => %s\n", source.string(), dest.string());
+        printf("Processing image to cache: %s => %s\n", source.c_str(), dest.c_str());
     }
 
     // Get a file handler to read from
-    fp = fopen(source.string(),"rb");
+    fp = fopen(source.c_str(),"rb");
     if (fp == NULL) {
-        fprintf(stderr, "%s ERROR: Unable to open PNG file\n", source.string());
+        fprintf(stderr, "%s ERROR: Unable to open PNG file\n", source.c_str());
         return error;
     }
 
@@ -1507,7 +1507,7 @@
     png_init_io(read_ptr,fp);
 
     // Actually read data from the file
-    read_png(source.string(), read_ptr, read_info, &imageInfo);
+    read_png(source.c_str(), read_ptr, read_info, &imageInfo);
 
     // We're done reading so we can clean up
     // Find old file size before releasing handle
@@ -1519,7 +1519,7 @@
     // Check to see if we're dealing with a 9-patch
     // If we are, process appropriately
     if (source.getBasePath().getPathExtension() == ".9")  {
-        if (do_9patch(source.string(), &imageInfo) != NO_ERROR) {
+        if (do_9patch(source.c_str(), &imageInfo) != NO_ERROR) {
             return error;
         }
     }
@@ -1541,9 +1541,9 @@
     }
 
     // Open up our destination file for writing
-    fp = fopen(dest.string(), "wb");
+    fp = fopen(dest.c_str(), "wb");
     if (!fp) {
-        fprintf(stderr, "%s ERROR: Unable to open PNG file\n", dest.string());
+        fprintf(stderr, "%s ERROR: Unable to open PNG file\n", dest.c_str());
         png_destroy_write_struct(&write_ptr, &write_info);
         return error;
     }
@@ -1559,11 +1559,11 @@
     }
 
     // Actually write out to the new png
-    write_png(dest.string(), write_ptr, write_info, imageInfo, bundle);
+    write_png(dest.c_str(), write_ptr, write_info, imageInfo, bundle);
 
     if (bundle->getVerbose()) {
         // Find the size of our new file
-        FILE* reader = fopen(dest.string(), "rb");
+        FILE* reader = fopen(dest.c_str(), "rb");
         fseek(reader, 0, SEEK_END);
         size_t newSize = (size_t)ftell(reader);
         fclose(reader);
@@ -1571,7 +1571,7 @@
         float factor = ((float)newSize)/oldSize;
         int percent = (int)(factor*100);
         printf("  (processed image to cache entry %s: %d%% size of source)\n",
-               dest.string(), percent);
+               dest.c_str(), percent);
     }
 
     //Clean up
@@ -1588,7 +1588,7 @@
 
     // At this point, now that we have all the resource data, all we need to
     // do is compile XML files.
-    if (strcmp(ext.string(), ".xml") == 0) {
+    if (strcmp(ext.c_str(), ".xml") == 0) {
         String16 resourceName(parseResourceName(file->getSourceFile().getPathLeaf()));
         return compileXmlFile(bundle, assets, resourceName, file, table);
     }
diff --git a/tools/aapt/Package.cpp b/tools/aapt/Package.cpp
index f06643dc..965655b 100644
--- a/tools/aapt/Package.cpp
+++ b/tools/aapt/Package.cpp
@@ -69,39 +69,39 @@
      * If "update" is set, update the contents of the existing archive.
      * Else, if "force" is set, remove the existing archive.
      */
-    FileType fileType = getFileType(outputFile.string());
+    FileType fileType = getFileType(outputFile.c_str());
     if (fileType == kFileTypeNonexistent) {
         // okay, create it below
     } else if (fileType == kFileTypeRegular) {
         if (bundle->getUpdate()) {
             // okay, open it below
         } else if (bundle->getForce()) {
-            if (unlink(outputFile.string()) != 0) {
-                fprintf(stderr, "ERROR: unable to remove '%s': %s\n", outputFile.string(),
+            if (unlink(outputFile.c_str()) != 0) {
+                fprintf(stderr, "ERROR: unable to remove '%s': %s\n", outputFile.c_str(),
                         strerror(errno));
                 goto bail;
             }
         } else {
             fprintf(stderr, "ERROR: '%s' exists (use '-f' to force overwrite)\n",
-                    outputFile.string());
+                    outputFile.c_str());
             goto bail;
         }
     } else {
-        fprintf(stderr, "ERROR: '%s' exists and is not a regular file\n", outputFile.string());
+        fprintf(stderr, "ERROR: '%s' exists and is not a regular file\n", outputFile.c_str());
         goto bail;
     }
 
     if (bundle->getVerbose()) {
         printf("%s '%s'\n", (fileType == kFileTypeNonexistent) ? "Creating" : "Opening",
-                outputFile.string());
+                outputFile.c_str());
     }
 
     status_t status;
     zip = new ZipFile;
-    status = zip->open(outputFile.string(), ZipFile::kOpenReadWrite | ZipFile::kOpenCreate);
+    status = zip->open(outputFile.c_str(), ZipFile::kOpenReadWrite | ZipFile::kOpenCreate);
     if (status != NO_ERROR) {
         fprintf(stderr, "ERROR: unable to open '%s' as Zip file for writing\n",
-                outputFile.string());
+                outputFile.c_str());
         goto bail;
     }
 
@@ -112,7 +112,7 @@
     count = processAssets(bundle, zip, outputSet);
     if (count < 0) {
         fprintf(stderr, "ERROR: unable to process assets while packaging '%s'\n",
-                outputFile.string());
+                outputFile.c_str());
         result = count;
         goto bail;
     }
@@ -124,7 +124,7 @@
     count = processJarFiles(bundle, zip);
     if (count < 0) {
         fprintf(stderr, "ERROR: unable to process jar files while packaging '%s'\n",
-                outputFile.string());
+                outputFile.c_str());
         result = count;
         goto bail;
     }
@@ -169,12 +169,12 @@
     /* anything here? */
     if (zip->getNumEntries() == 0) {
         if (bundle->getVerbose()) {
-            printf("Archive is empty -- removing %s\n", outputFile.getPathLeaf().string());
+            printf("Archive is empty -- removing %s\n", outputFile.getPathLeaf().c_str());
         }
         delete zip;        // close the file so we can remove it in Win32
         zip = NULL;
-        if (unlink(outputFile.string()) != 0) {
-            fprintf(stderr, "warning: could not unlink '%s'\n", outputFile.string());
+        if (unlink(outputFile.c_str()) != 0) {
+            fprintf(stderr, "warning: could not unlink '%s'\n", outputFile.c_str());
         }
     }
 
@@ -187,9 +187,9 @@
         String8 dependencyFile = outputFile;
         dependencyFile.append(".d");
 
-        FILE* fp = fopen(dependencyFile.string(), "a");
+        FILE* fp = fopen(dependencyFile.c_str(), "a");
         // Add this file to the dependency file
-        fprintf(fp, "%s \\\n", outputFile.string());
+        fprintf(fp, "%s \\\n", outputFile.c_str());
         fclose(fp);
     }
 
@@ -199,10 +199,10 @@
     delete zip;        // must close before remove in Win32
     if (result != NO_ERROR) {
         if (bundle->getVerbose()) {
-            printf("Removing %s due to earlier failures\n", outputFile.string());
+            printf("Removing %s due to earlier failures\n", outputFile.c_str());
         }
-        if (unlink(outputFile.string()) != 0) {
-            fprintf(stderr, "warning: could not unlink '%s'\n", outputFile.string());
+        if (unlink(outputFile.c_str()) != 0) {
+            fprintf(stderr, "warning: could not unlink '%s'\n", outputFile.c_str());
         }
     }
 
@@ -267,31 +267,31 @@
     int fileNameLen = storageName.length();
     int excludeExtensionLen = strlen(kExcludeExtension);
     if (fileNameLen > excludeExtensionLen
-            && (0 == strcmp(storageName.string() + (fileNameLen - excludeExtensionLen),
+            && (0 == strcmp(storageName.c_str() + (fileNameLen - excludeExtensionLen),
                             kExcludeExtension))) {
-        fprintf(stderr, "warning: '%s' not added to Zip\n", storageName.string());
+        fprintf(stderr, "warning: '%s' not added to Zip\n", storageName.c_str());
         return true;
     }
 
-    if (strcasecmp(storageName.getPathExtension().string(), ".gz") == 0) {
+    if (strcasecmp(storageName.getPathExtension().c_str(), ".gz") == 0) {
         fromGzip = true;
         storageName = storageName.getBasePath();
     }
 
     if (bundle->getUpdate()) {
-        entry = zip->getEntryByName(storageName.string());
+        entry = zip->getEntryByName(storageName.c_str());
         if (entry != NULL) {
             /* file already exists in archive; there can be only one */
             if (entry->getMarked()) {
                 fprintf(stderr,
                         "ERROR: '%s' exists twice (check for with & w/o '.gz'?)\n",
-                        file->getPrintableSource().string());
+                        file->getPrintableSource().c_str());
                 return false;
             }
             if (!hasData) {
                 const String8& srcName = file->getSourceFile();
                 time_t fileModWhen;
-                fileModWhen = getFileModDate(srcName.string());
+                fileModWhen = getFileModDate(srcName.c_str());
                 if (fileModWhen == (time_t) -1) { // file existence tested earlier,
                     return false;                 //  not expecting an error here
                 }
@@ -299,14 +299,14 @@
                 if (fileModWhen > entry->getModWhen()) {
                     // mark as deleted so add() will succeed
                     if (bundle->getVerbose()) {
-                        printf("      (removing old '%s')\n", storageName.string());
+                        printf("      (removing old '%s')\n", storageName.c_str());
                     }
     
                     zip->remove(entry);
                 } else {
                     // version in archive is newer
                     if (bundle->getVerbose()) {
-                        printf("      (not updating '%s')\n", storageName.string());
+                        printf("      (not updating '%s')\n", storageName.c_str());
                     }
                     entry->setMarked(true);
                     return true;
@@ -321,22 +321,22 @@
     //android_setMinPriority(NULL, ANDROID_LOG_VERBOSE);
 
     if (fromGzip) {
-        result = zip->addGzip(file->getSourceFile().string(), storageName.string(), &entry);
+        result = zip->addGzip(file->getSourceFile().c_str(), storageName.c_str(), &entry);
     } else if (!hasData) {
         /* don't compress certain files, e.g. PNGs */
         int compressionMethod = bundle->getCompressionMethod();
         if (!okayToCompress(bundle, storageName)) {
             compressionMethod = ZipEntry::kCompressStored;
         }
-        result = zip->add(file->getSourceFile().string(), storageName.string(), compressionMethod,
+        result = zip->add(file->getSourceFile().c_str(), storageName.c_str(), compressionMethod,
                             &entry);
     } else {
-        result = zip->add(file->getData(), file->getSize(), storageName.string(),
+        result = zip->add(file->getData(), file->getSize(), storageName.c_str(),
                            file->getCompressionMethod(), &entry);
     }
     if (result == NO_ERROR) {
         if (bundle->getVerbose()) {
-            printf("      '%s'%s", storageName.string(), fromGzip ? " (from .gz)" : "");
+            printf("      '%s'%s", storageName.c_str(), fromGzip ? " (from .gz)" : "");
             if (entry->getCompressionMethod() == ZipEntry::kCompressStored) {
                 printf(" (not compressed)\n");
             } else {
@@ -348,10 +348,10 @@
     } else {
         if (result == ALREADY_EXISTS) {
             fprintf(stderr, "      Unable to add '%s': file already in archive (try '-u'?)\n",
-                    file->getPrintableSource().string());
+                    file->getPrintableSource().c_str());
         } else {
             fprintf(stderr, "      Unable to add '%s': Zip add failed (%d)\n",
-                    file->getPrintableSource().string(), result);
+                    file->getPrintableSource().c_str(), result);
         }
         return false;
     }
@@ -372,7 +372,7 @@
         return true;
 
     for (i = 0; i < NELEM(kNoCompressExt); i++) {
-        if (strcasecmp(ext.string(), kNoCompressExt[i]) == 0)
+        if (strcasecmp(ext.c_str(), kNoCompressExt[i]) == 0)
             return false;
     }
 
@@ -383,7 +383,7 @@
         if (pos < 0) {
             continue;
         }
-        const char* path = pathName.string();
+        const char* path = pathName.c_str();
         if (strcasecmp(path + pos, str) == 0) {
             return false;
         }
diff --git a/tools/aapt/Resource.cpp b/tools/aapt/Resource.cpp
index dd3ebdb..4ca3a68 100644
--- a/tools/aapt/Resource.cpp
+++ b/tools/aapt/Resource.cpp
@@ -57,8 +57,8 @@
 
 String8 parseResourceName(const String8& leaf)
 {
-    const char* firstDot = strchr(leaf.string(), '.');
-    const char* str = leaf.string();
+    const char* firstDot = strchr(leaf.c_str(), '.');
+    const char* str = leaf.c_str();
 
     if (firstDot) {
         return String8(str, firstDot-str);
@@ -132,7 +132,7 @@
             mParams = file->getGroupEntry().toParams();
             if (kIsDebug) {
                 printf("Dir %s: mcc=%d mnc=%d lang=%c%c cnt=%c%c orient=%d ui=%d density=%d touch=%d key=%d inp=%d nav=%d\n",
-                        group->getPath().string(), mParams.mcc, mParams.mnc,
+                        group->getPath().c_str(), mParams.mcc, mParams.mnc,
                         mParams.language[0] ? mParams.language[0] : '-',
                         mParams.language[1] ? mParams.language[1] : '-',
                         mParams.country[0] ? mParams.country[0] : '-',
@@ -147,12 +147,12 @@
             mBaseName = parseResourceName(leaf);
             if (mBaseName == "") {
                 fprintf(stderr, "Error: malformed resource filename %s\n",
-                        file->getPrintableSource().string());
+                        file->getPrintableSource().c_str());
                 return UNKNOWN_ERROR;
             }
 
             if (kIsDebug) {
-                printf("file name=%s\n", mBaseName.string());
+                printf("file name=%s\n", mBaseName.c_str());
             }
 
             return NO_ERROR;
@@ -222,7 +222,7 @@
 {
     if (grp->getFiles().size() != 1) {
         fprintf(stderr, "warning: Multiple AndroidManifest.xml files found, using %s\n",
-                grp->getFiles().valueAt(0)->getPrintableSource().string());
+                grp->getFiles().valueAt(0)->getPrintableSource().c_str());
     }
 
     sp<AaptFile> file = grp->getFiles().valueAt(0);
@@ -243,20 +243,20 @@
     size_t len;
     if (code != ResXMLTree::START_TAG) {
         fprintf(stderr, "%s:%d: No start tag found\n",
-                file->getPrintableSource().string(), block.getLineNumber());
+                file->getPrintableSource().c_str(), block.getLineNumber());
         return UNKNOWN_ERROR;
     }
-    if (strcmp16(block.getElementName(&len), String16("manifest").string()) != 0) {
+    if (strcmp16(block.getElementName(&len), String16("manifest").c_str()) != 0) {
         fprintf(stderr, "%s:%d: Invalid start tag %s, expected <manifest>\n",
-                file->getPrintableSource().string(), block.getLineNumber(),
-                String8(block.getElementName(&len)).string());
+                file->getPrintableSource().c_str(), block.getLineNumber(),
+                String8(block.getElementName(&len)).c_str());
         return UNKNOWN_ERROR;
     }
 
     ssize_t nameIndex = block.indexOfAttribute(NULL, "package");
     if (nameIndex < 0) {
         fprintf(stderr, "%s:%d: <manifest> does not have package attribute.\n",
-                file->getPrintableSource().string(), block.getLineNumber());
+                file->getPrintableSource().c_str(), block.getLineNumber());
         return UNKNOWN_ERROR;
     }
 
@@ -264,19 +264,19 @@
 
     ssize_t revisionCodeIndex = block.indexOfAttribute(RESOURCES_ANDROID_NAMESPACE, "revisionCode");
     if (revisionCodeIndex >= 0) {
-        bundle->setRevisionCode(String8(block.getAttributeStringValue(revisionCodeIndex, &len)).string());
+        bundle->setRevisionCode(String8(block.getAttributeStringValue(revisionCodeIndex, &len)).c_str());
     }
 
     String16 uses_sdk16("uses-sdk");
     while ((code=block.next()) != ResXMLTree::END_DOCUMENT
            && code != ResXMLTree::BAD_DOCUMENT) {
         if (code == ResXMLTree::START_TAG) {
-            if (strcmp16(block.getElementName(&len), uses_sdk16.string()) == 0) {
+            if (strcmp16(block.getElementName(&len), uses_sdk16.c_str()) == 0) {
                 ssize_t minSdkIndex = block.indexOfAttribute(RESOURCES_ANDROID_NAMESPACE,
                                                              "minSdkVersion");
                 if (minSdkIndex >= 0) {
                     const char16_t* minSdk16 = block.getAttributeStringValue(minSdkIndex, &len);
-                    const char* minSdk8 = strdup(String8(minSdk16).string());
+                    const char* minSdk8 = strdup(String8(minSdk16).c_str());
                     bundle->setManifestMinSdkVersion(minSdk8);
                 }
             }
@@ -305,17 +305,17 @@
     while ((res=it.next()) == NO_ERROR) {
         if (bundle->getVerbose()) {
             printf("    (new resource id %s from %s)\n",
-                   it.getBaseName().string(), it.getFile()->getPrintableSource().string());
+                   it.getBaseName().c_str(), it.getFile()->getPrintableSource().c_str());
         }
         String16 baseName(it.getBaseName());
-        const char16_t* str = baseName.string();
+        const char16_t* str = baseName.c_str();
         const char16_t* const end = str + baseName.size();
         while (str < end) {
             if (!((*str >= 'a' && *str <= 'z')
                     || (*str >= '0' && *str <= '9')
                     || *str == '_' || *str == '.')) {
                 fprintf(stderr, "%s: Invalid file name: must contain only [a-z0-9_.]\n",
-                        it.getPath().string());
+                        it.getPath().c_str());
                 hasErrors = true;
             }
             str++;
@@ -413,7 +413,7 @@
             sp<ResourceTypeSet> set = new ResourceTypeSet();
             if (kIsDebug) {
                 printf("Creating new resource type set for leaf %s with group %s (%p)\n",
-                        leafName.string(), group->getPath().string(), group.get());
+                        leafName.c_str(), group->getPath().c_str(), group.get());
             }
             set->add(leafName, group);
             resources->add(resType, set);
@@ -423,21 +423,21 @@
             if (index < 0) {
                 if (kIsDebug) {
                     printf("Adding to resource type set for leaf %s group %s (%p)\n",
-                            leafName.string(), group->getPath().string(), group.get());
+                            leafName.c_str(), group->getPath().c_str(), group.get());
                 }
                 set->add(leafName, group);
             } else {
                 sp<AaptGroup> existingGroup = set->valueAt(index);
                 if (kIsDebug) {
                     printf("Extending to resource type set for leaf %s group %s (%p)\n",
-                            leafName.string(), group->getPath().string(), group.get());
+                            leafName.c_str(), group->getPath().c_str(), group.get());
                 }
                 for (size_t j=0; j<files.size(); j++) {
                     if (kIsDebug) {
                         printf("Adding file %s in group %s resType %s\n",
-                                files.valueAt(j)->getSourceFile().string(),
-                                files.keyAt(j).toDirName(String8()).string(),
-                                resType.string());
+                                files.valueAt(j)->getSourceFile().c_str(),
+                                files.keyAt(j).toDirName(String8()).c_str(),
+                                resType.c_str());
                     }
                     existingGroup->addFile(files.valueAt(j));
                 }
@@ -455,14 +455,14 @@
     for (int i=0; i<N; i++) {
         const sp<AaptDir>& d = dirs.itemAt(i);
         if (kIsDebug) {
-            printf("Collecting dir #%d %p: %s, leaf %s\n", i, d.get(), d->getPath().string(),
-                    d->getLeaf().string());
+            printf("Collecting dir #%d %p: %s, leaf %s\n", i, d.get(), d->getPath().c_str(),
+                    d->getLeaf().c_str());
         }
         collect_files(d, resources);
 
         // don't try to include the res dir
         if (kIsDebug) {
-            printf("Removing dir leaf %s\n", d->getLeaf().string());
+            printf("Removing dir leaf %s\n", d->getLeaf().c_str());
         }
         ass->removeDir(d->getLeaf());
     }
@@ -490,8 +490,8 @@
             int strIdx;
             if ((strIdx=table.resolveReference(&value, 0x10000000, NULL, &specFlags)) < 0) {
                 fprintf(stderr, "%s:%d: Tag <%s> attribute %s references unknown resid 0x%08x.\n",
-                        path.string(), parser.getLineNumber(),
-                        String8(parser.getElementName(&len)).string(), attr,
+                        path.c_str(), parser.getLineNumber(),
+                        String8(parser.getElementName(&len)).c_str(), attr,
                         value.data);
                 return ATTR_NOT_FOUND;
             }
@@ -502,12 +502,12 @@
                 str = pool->stringAt(value.data, &len);
             }
             printf("***** RES ATTR: %s specFlags=0x%x strIdx=%d: %s\n", attr,
-                    specFlags, strIdx, str != NULL ? String8(str).string() : "???");
+                    specFlags, strIdx, str != NULL ? String8(str).c_str() : "???");
             #endif
             if ((specFlags&~ResTable_typeSpec::SPEC_PUBLIC) != 0 && false) {
                 fprintf(stderr, "%s:%d: Tag <%s> attribute %s varies by configurations 0x%x.\n",
-                        path.string(), parser.getLineNumber(),
-                        String8(parser.getElementName(&len)).string(), attr,
+                        path.c_str(), parser.getLineNumber(),
+                        String8(parser.getElementName(&len)).c_str(), attr,
                         specFlags);
                 return ATTR_NOT_FOUND;
             }
@@ -515,20 +515,20 @@
         if (value.dataType == Res_value::TYPE_STRING) {
             if (pool == NULL) {
                 fprintf(stderr, "%s:%d: Tag <%s> attribute %s has no string block.\n",
-                        path.string(), parser.getLineNumber(),
-                        String8(parser.getElementName(&len)).string(), attr);
+                        path.c_str(), parser.getLineNumber(),
+                        String8(parser.getElementName(&len)).c_str(), attr);
                 return ATTR_NOT_FOUND;
             }
             if ((str = UnpackOptionalString(pool->stringAt(value.data), &len)) == NULL) {
                 fprintf(stderr, "%s:%d: Tag <%s> attribute %s has corrupt string value.\n",
-                        path.string(), parser.getLineNumber(),
-                        String8(parser.getElementName(&len)).string(), attr);
+                        path.c_str(), parser.getLineNumber(),
+                        String8(parser.getElementName(&len)).c_str(), attr);
                 return ATTR_NOT_FOUND;
             }
         } else {
             fprintf(stderr, "%s:%d: Tag <%s> attribute %s has invalid type %d.\n",
-                    path.string(), parser.getLineNumber(),
-                    String8(parser.getElementName(&len)).string(), attr,
+                    path.c_str(), parser.getLineNumber(),
+                    String8(parser.getElementName(&len)).c_str(), attr,
                     value.dataType);
             return ATTR_NOT_FOUND;
         }
@@ -546,30 +546,30 @@
                 }
                 if (!okay) {
                     fprintf(stderr, "%s:%d: Tag <%s> attribute %s has invalid character '%c'.\n",
-                            path.string(), parser.getLineNumber(),
-                            String8(parser.getElementName(&len)).string(), attr, (char)str[i]);
+                            path.c_str(), parser.getLineNumber(),
+                            String8(parser.getElementName(&len)).c_str(), attr, (char)str[i]);
                     return (int)i;
                 }
             }
         }
         if (*str == ' ') {
             fprintf(stderr, "%s:%d: Tag <%s> attribute %s can not start with a space.\n",
-                    path.string(), parser.getLineNumber(),
-                    String8(parser.getElementName(&len)).string(), attr);
+                    path.c_str(), parser.getLineNumber(),
+                    String8(parser.getElementName(&len)).c_str(), attr);
             return ATTR_LEADING_SPACES;
         }
         if (len != 0 && str[len-1] == ' ') {
             fprintf(stderr, "%s:%d: Tag <%s> attribute %s can not end with a space.\n",
-                    path.string(), parser.getLineNumber(),
-                    String8(parser.getElementName(&len)).string(), attr);
+                    path.c_str(), parser.getLineNumber(),
+                    String8(parser.getElementName(&len)).c_str(), attr);
             return ATTR_TRAILING_SPACES;
         }
         return ATTR_OKAY;
     }
     if (required) {
         fprintf(stderr, "%s:%d: Tag <%s> missing required attribute %s.\n",
-                path.string(), parser.getLineNumber(),
-                String8(parser.getElementName(&len)).string(), attr);
+                path.c_str(), parser.getLineNumber(),
+                String8(parser.getElementName(&len)).c_str(), attr);
         return ATTR_NOT_FOUND;
     }
     return ATTR_OKAY;
@@ -584,7 +584,7 @@
             ssize_t index = parser.indexOfAttribute(NULL, "id");
             if (index >= 0) {
                 fprintf(stderr, "%s:%d: warning: found plain 'id' attribute; did you mean the new 'android:id' name?\n",
-                        path.string(), parser.getLineNumber());
+                        path.c_str(), parser.getLineNumber());
             }
         }
     }
@@ -618,7 +618,7 @@
             size_t overlayCount = overlaySet->size();
             for (size_t overlayIndex=0; overlayIndex<overlayCount; overlayIndex++) {
                 if (bundle->getVerbose()) {
-                    printf("trying overlaySet Key=%s\n",overlaySet->keyAt(overlayIndex).string());
+                    printf("trying overlaySet Key=%s\n",overlaySet->keyAt(overlayIndex).c_str());
                 }
                 ssize_t baseIndex = -1;
                 if (baseSet->get() != NULL) {
@@ -638,11 +638,11 @@
                                 baseGroup->getFiles();
                         for (size_t i=0; i < baseFiles.size(); i++) {
                             printf("baseFile " ZD " has flavor %s\n", (ZD_TYPE) i,
-                                    baseFiles.keyAt(i).toString().string());
+                                    baseFiles.keyAt(i).toString().c_str());
                         }
                         for (size_t i=0; i < overlayFiles.size(); i++) {
                             printf("overlayFile " ZD " has flavor %s\n", (ZD_TYPE) i,
-                                    overlayFiles.keyAt(i).toString().string());
+                                    overlayFiles.keyAt(i).toString().c_str());
                         }
                     }
 
@@ -657,16 +657,16 @@
                             if (bundle->getVerbose()) {
                                 printf("found a match (" ZD ") for overlay file %s, for flavor %s\n",
                                         (ZD_TYPE) baseFileIndex,
-                                        overlayGroup->getLeaf().string(),
-                                        overlayFiles.keyAt(overlayGroupIndex).toString().string());
+                                        overlayGroup->getLeaf().c_str(),
+                                        overlayFiles.keyAt(overlayGroupIndex).toString().c_str());
                             }
                             baseGroup->removeFile(baseFileIndex);
                         } else {
                             // didn't find a match fall through and add it..
                             if (true || bundle->getVerbose()) {
                                 printf("nothing matches overlay file %s, for flavor %s\n",
-                                        overlayGroup->getLeaf().string(),
-                                        overlayFiles.keyAt(overlayGroupIndex).toString().string());
+                                        overlayGroup->getLeaf().c_str(),
+                                        overlayFiles.keyAt(overlayGroupIndex).toString().c_str());
                             }
                         }
                         baseGroup->addFile(overlayFiles.valueAt(overlayGroupIndex));
@@ -728,7 +728,7 @@
         if (errorOnFailedInsert) {
             fprintf(stderr, "Error: AndroidManifest.xml already defines %s (in %s);"
                             " cannot insert new value %s.\n",
-                    String8(attr).string(), String8(ns).string(), value);
+                    String8(attr).c_str(), String8(ns).c_str(), value);
             return false;
         }
 
@@ -763,7 +763,7 @@
         // .asdf  .a.b  --> package.asdf package.a.b
         // asdf.adsf --> asdf.asdf
         String8 className;
-        const char* p = name.string();
+        const char* p = name.c_str();
         const char* q = strchr(p, '.');
         if (p == q) {
             className += package;
@@ -776,7 +776,7 @@
             className += name;
         }
         if (kIsDebug) {
-            printf("Qualifying class '%s' to '%s'", name.string(), className.string());
+            printf("Qualifying class '%s' to '%s'", name.c_str(), className.c_str());
         }
         attr->string.setTo(String16(className));
     }
@@ -810,7 +810,7 @@
   const char* err;
 
   String16 iconPackage, iconType, iconName;
-  if (!ResTable::expandResourceRef(iconRef.string(), iconRef.size(), &iconPackage, &iconType,
+  if (!ResTable::expandResourceRef(iconRef.c_str(), iconRef.size(), &iconPackage, &iconType,
                                    &iconName, NULL, &table->getAssetsPackage(), &err,
                                    &publicOnly)) {
       // Errors will be raised in later XML compilation.
@@ -824,7 +824,7 @@
   }
 
   String16 roundIconPackage, roundIconType, roundIconName;
-  if (!ResTable::expandResourceRef(roundIconRef.string(), roundIconRef.size(), &roundIconPackage,
+  if (!ResTable::expandResourceRef(roundIconRef.c_str(), roundIconRef.size(), &roundIconPackage,
                                    &roundIconType, &roundIconName, NULL, &table->getAssetsPackage(),
                                    &err, &publicOnly)) {
       // Errors will be raised in later XML compilation.
@@ -839,9 +839,9 @@
       return;
   }
 
-  String16 aliasValue = String16(String8::format("@%s:%s/%s", String8(iconPackage).string(),
-                                                 String8(iconType).string(),
-                                                 String8(iconName).string()));
+  String16 aliasValue = String16(String8::format("@%s:%s/%s", String8(iconPackage).c_str(),
+                                                 String8(iconType).c_str(),
+                                                 String8(iconName).c_str()));
 
   // Add an equivalent v26 entry to the roundIcon for each v26 variant of the regular icon.
   const DefaultKeyedVector<ConfigDescription, sp<ResourceTable::Entry>>& configList =
@@ -872,7 +872,7 @@
         const XMLNode::attribute_entry* attr = root->getAttribute(
                 String16(RESOURCES_ANDROID_NAMESPACE), String16("versionCode"));
         if (attr != NULL) {
-            bundle->setVersionCode(strdup(String8(attr->string).string()));
+            bundle->setVersionCode(strdup(String8(attr->string).c_str()));
         }
     }
 
@@ -883,7 +883,7 @@
         const XMLNode::attribute_entry* attr = root->getAttribute(
                 String16(RESOURCES_ANDROID_NAMESPACE), String16("versionName"));
         if (attr != NULL) {
-            bundle->setVersionName(strdup(String8(attr->string).string()));
+            bundle->setVersionName(strdup(String8(attr->string).c_str()));
         }
     }
     
@@ -914,7 +914,7 @@
         const XMLNode::attribute_entry* attr = vers->getAttribute(
                 String16(RESOURCES_ANDROID_NAMESPACE), String16("minSdkVersion"));
         if (attr != NULL) {
-            bundle->setMinSdkVersion(strdup(String8(attr->string).string()));
+            bundle->setMinSdkVersion(strdup(String8(attr->string).c_str()));
         }
     }
 
@@ -970,7 +970,7 @@
         String8 origPackage(attr->string);
         attr->string.setTo(String16(manifestPackageNameOverride));
         if (kIsDebug) {
-            printf("Overriding package '%s' to be '%s'\n", origPackage.string(),
+            printf("Overriding package '%s' to be '%s'\n", origPackage.c_str(),
                     manifestPackageNameOverride);
         }
 
@@ -1071,7 +1071,7 @@
 static ssize_t extractPlatformBuildVersion(const ResTable& table, ResXMLTree& tree, Bundle* bundle) {
     // First check if we should be recording the compileSdkVersion* attributes.
     static const String16 compileSdkVersionName("android:attr/compileSdkVersion");
-    const bool useCompileSdkVersion = table.identifierForName(compileSdkVersionName.string(),
+    const bool useCompileSdkVersion = table.identifierForName(compileSdkVersionName.c_str(),
                                                               compileSdkVersionName.size()) != 0u;
 
     size_t len;
@@ -1223,7 +1223,7 @@
     // Add the 'revisionCode' attribute, which is set to the original revisionCode.
     if (bundle->getRevisionCode().size() > 0) {
         if (!addTagAttribute(manifest, RESOURCES_ANDROID_NAMESPACE, "revisionCode",
-                    bundle->getRevisionCode().string(), true, true)) {
+                    bundle->getRevisionCode().c_str(), true, true)) {
             return UNKNOWN_ERROR;
         }
     }
@@ -1270,7 +1270,7 @@
     }
 
     if (kIsDebug) {
-        printf("Creating resources for package %s\n", assets->getPackage().string());
+        printf("Creating resources for package %s\n", assets->getPackage().c_str());
     }
 
     // Set the private symbols package if it was declared.
@@ -1804,7 +1804,7 @@
                     flattenedTable, split->isBase());
             if (err != NO_ERROR) {
                 fprintf(stderr, "Failed to generate resource table for split '%s'\n",
-                        split->getPrintableName().string());
+                        split->getPrintableName().c_str());
                 return err;
             }
             split->addEntry(String8("resources.arsc"), flattenedTable);
@@ -1821,7 +1821,7 @@
                 err = resTable.add(flattenedTable->getData(), flattenedTable->getSize());
                 if (err != NO_ERROR) {
                     fprintf(stderr, "Generated resource table for split '%s' is corrupt.\n",
-                            split->getPrintableName().string());
+                            split->getPrintableName().c_str());
                     return err;
                 }
 
@@ -1849,7 +1849,7 @@
                             if (block < 0) {
                                 hasError = true;
                                 SourcePos().error("%s has no definition for density split '%s'",
-                                        symbol.toString().string(), config.toString().string());
+                                        symbol.toString().c_str(), config.toString().c_str());
 
                                 if (bundle->getVerbose()) {
                                     const Vector<SymbolDefinition>& defs = densityVaryingResources[k];
@@ -1857,7 +1857,7 @@
                                     for (size_t d = 0; d < defCount; d++) {
                                         const SymbolDefinition& def = defs[d];
                                         def.source.error("%s has definition for %s",
-                                                symbol.toString().string(), def.config.toString().string());
+                                                symbol.toString().c_str(), def.config.toString().c_str());
                                     }
 
                                     if (defCount < defs.size()) {
@@ -1880,7 +1880,7 @@
                         generatedManifest, &table);
                 if (err != NO_ERROR) {
                     fprintf(stderr, "Failed to generate AndroidManifest.xml for split '%s'\n",
-                            split->getPrintableName().string());
+                            split->getPrintableName().c_str());
                     return err;
                 }
                 split->addEntry(String8("AndroidManifest.xml"), generatedManifest);
@@ -1960,7 +1960,7 @@
             if (block.getElementNamespace(&len) != NULL) {
                 continue;
             }
-            if (strcmp16(block.getElementName(&len), manifest16.string()) == 0) {
+            if (strcmp16(block.getElementName(&len), manifest16.c_str()) == 0) {
                 if (validateAttr(manifestPath, finalResTable, block, NULL, "package",
                                  packageIdentChars, true) != ATTR_OKAY) {
                     hasErrors = true;
@@ -1969,10 +1969,10 @@
                                  "sharedUserId", packageIdentChars, false) != ATTR_OKAY) {
                     hasErrors = true;
                 }
-            } else if (strcmp16(block.getElementName(&len), permission16.string()) == 0
-                    || strcmp16(block.getElementName(&len), permission_group16.string()) == 0) {
+            } else if (strcmp16(block.getElementName(&len), permission16.c_str()) == 0
+                    || strcmp16(block.getElementName(&len), permission_group16.c_str()) == 0) {
                 const bool isGroup = strcmp16(block.getElementName(&len),
-                        permission_group16.string()) == 0;
+                        permission_group16.c_str()) == 0;
                 if (validateAttr(manifestPath, finalResTable, block, RESOURCES_ANDROID_NAMESPACE,
                                  "name", isGroup ? packageIdentCharsWithTheStupid
                                  : packageIdentChars, true) != ATTR_OKAY) {
@@ -2002,8 +2002,8 @@
                 const char16_t* id = block.getAttributeStringValue(index, &len);
                 if (id == NULL) {
                     fprintf(stderr, "%s:%d: missing name attribute in element <%s>.\n", 
-                            manifestPath.string(), block.getLineNumber(),
-                            String8(block.getElementName(&len)).string());
+                            manifestPath.c_str(), block.getLineNumber(),
+                            String8(block.getElementName(&len)).c_str());
                     hasErrors = true;
                     break;
                 }
@@ -2038,23 +2038,23 @@
                 if (begins_with_digit || (e != p && *(e-1) != '.')) {
                   fprintf(stderr,
                           "%s:%d: Permission name <%s> is not a valid Java symbol\n",
-                          manifestPath.string(), block.getLineNumber(), idStr.string());
+                          manifestPath.c_str(), block.getLineNumber(), idStr.c_str());
                   hasErrors = true;
                 }
                 syms->addStringSymbol(String8(e), idStr, srcPos);
                 const char16_t* cmt = block.getComment(&len);
                 if (cmt != NULL && *cmt != 0) {
-                    //printf("Comment of %s: %s\n", String8(e).string(),
-                    //        String8(cmt).string());
+                    //printf("Comment of %s: %s\n", String8(e).c_str(),
+                    //        String8(cmt).c_str());
                     syms->appendComment(String8(e), String16(cmt), srcPos);
                 }
                 syms->makeSymbolPublic(String8(e), srcPos);
-            } else if (strcmp16(block.getElementName(&len), uses_permission16.string()) == 0) {
+            } else if (strcmp16(block.getElementName(&len), uses_permission16.c_str()) == 0) {
                 if (validateAttr(manifestPath, finalResTable, block, RESOURCES_ANDROID_NAMESPACE,
                                  "name", packageIdentChars, true) != ATTR_OKAY) {
                     hasErrors = true;
                 }
-            } else if (strcmp16(block.getElementName(&len), instrumentation16.string()) == 0) {
+            } else if (strcmp16(block.getElementName(&len), instrumentation16.c_str()) == 0) {
                 if (validateAttr(manifestPath, finalResTable, block, RESOURCES_ANDROID_NAMESPACE,
                                  "name", classIdentChars, true) != ATTR_OKAY) {
                     hasErrors = true;
@@ -2064,7 +2064,7 @@
                                  packageIdentChars, true) != ATTR_OKAY) {
                     hasErrors = true;
                 }
-            } else if (strcmp16(block.getElementName(&len), application16.string()) == 0) {
+            } else if (strcmp16(block.getElementName(&len), application16.c_str()) == 0) {
                 if (validateAttr(manifestPath, finalResTable, block, RESOURCES_ANDROID_NAMESPACE,
                                  "name", classIdentChars, false) != ATTR_OKAY) {
                     hasErrors = true;
@@ -2084,7 +2084,7 @@
                                  processIdentChars, false) != ATTR_OKAY) {
                     hasErrors = true;
                 }
-            } else if (strcmp16(block.getElementName(&len), provider16.string()) == 0) {
+            } else if (strcmp16(block.getElementName(&len), provider16.c_str()) == 0) {
                 if (validateAttr(manifestPath, finalResTable, block, RESOURCES_ANDROID_NAMESPACE,
                                  "name", classIdentChars, true) != ATTR_OKAY) {
                     hasErrors = true;
@@ -2104,9 +2104,9 @@
                                  processIdentChars, false) != ATTR_OKAY) {
                     hasErrors = true;
                 }
-            } else if (strcmp16(block.getElementName(&len), service16.string()) == 0
-                       || strcmp16(block.getElementName(&len), receiver16.string()) == 0
-                       || strcmp16(block.getElementName(&len), activity16.string()) == 0) {
+            } else if (strcmp16(block.getElementName(&len), service16.c_str()) == 0
+                       || strcmp16(block.getElementName(&len), receiver16.c_str()) == 0
+                       || strcmp16(block.getElementName(&len), activity16.c_str()) == 0) {
                 if (validateAttr(manifestPath, finalResTable, block, RESOURCES_ANDROID_NAMESPACE,
                                  "name", classIdentChars, true) != ATTR_OKAY) {
                     hasErrors = true;
@@ -2126,14 +2126,14 @@
                                  processIdentChars, false) != ATTR_OKAY) {
                     hasErrors = true;
                 }
-            } else if (strcmp16(block.getElementName(&len), action16.string()) == 0
-                       || strcmp16(block.getElementName(&len), category16.string()) == 0) {
+            } else if (strcmp16(block.getElementName(&len), action16.c_str()) == 0
+                       || strcmp16(block.getElementName(&len), category16.c_str()) == 0) {
                 if (validateAttr(manifestPath, finalResTable, block,
                                  RESOURCES_ANDROID_NAMESPACE, "name",
                                  packageIdentChars, true) != ATTR_OKAY) {
                     hasErrors = true;
                 }
-            } else if (strcmp16(block.getElementName(&len), data16.string()) == 0) {
+            } else if (strcmp16(block.getElementName(&len), data16.c_str()) == 0) {
                 if (validateAttr(manifestPath, finalResTable, block,
                                  RESOURCES_ANDROID_NAMESPACE, "mimeType",
                                  typeIdentChars, true) != ATTR_OKAY) {
@@ -2144,13 +2144,13 @@
                                  schemeIdentChars, true) != ATTR_OKAY) {
                     hasErrors = true;
                 }
-            } else if (strcmp16(block.getElementName(&len), feature_group16.string()) == 0) {
+            } else if (strcmp16(block.getElementName(&len), feature_group16.c_str()) == 0) {
                 int depth = 1;
                 while ((code=block.next()) != ResXMLTree::END_DOCUMENT
                        && code > ResXMLTree::BAD_DOCUMENT) {
                     if (code == ResXMLTree::START_TAG) {
                         depth++;
-                        if (strcmp16(block.getElementName(&len), uses_feature16.string()) == 0) {
+                        if (strcmp16(block.getElementName(&len), uses_feature16.c_str()) == 0) {
                             ssize_t idx = block.indexOfAttribute(
                                     RESOURCES_ANDROID_NAMESPACE, "required");
                             if (idx < 0) {
@@ -2162,7 +2162,7 @@
                                 fprintf(stderr, "%s:%d: Tag <uses-feature> can not have "
                                         "android:required=\"false\" when inside a "
                                         "<feature-group> tag.\n",
-                                        manifestPath.string(), block.getLineNumber());
+                                        manifestPath.c_str(), block.getLineNumber());
                                 hasErrors = true;
                             }
                         }
@@ -2222,7 +2222,7 @@
 static String8 getSymbolPackage(const String8& symbol, const sp<AaptAssets>& assets, bool pub) {
     ssize_t colon = symbol.find(":", 0);
     if (colon >= 0) {
-        return String8(symbol.string(), colon);
+        return String8(symbol.c_str(), colon);
     }
     return pub ? assets->getPackage() : assets->getSymbolsPrivatePackage();
 }
@@ -2230,7 +2230,7 @@
 static String8 getSymbolName(const String8& symbol) {
     ssize_t colon = symbol.find(":", 0);
     if (colon >= 0) {
-        return String8(symbol.string() + colon + 1);
+        return String8(symbol.c_str() + colon + 1);
     }
     return symbol;
 }
@@ -2245,7 +2245,7 @@
         asym = asym->getNestedSymbols().valueFor(String8("attr"));
         if (asym != NULL) {
             //printf("Got attrs symbols! comment %s=%s\n",
-            //     name.string(), String8(asym->getComment(name)).string());
+            //     name.c_str(), String8(asym->getComment(name)).c_str());
             if (outTypeComment != NULL) {
                 *outTypeComment = asym->getTypeComment(name);
             }
@@ -2276,8 +2276,8 @@
                 "%sfor(int i = 0; i < styleable.%s.length; ++i) {\n"
                 "%sstyleable.%s[i] = (styleable.%s[i] & 0x00ffffff) | (packageId << 24);\n"
                 "%s}\n",
-                indentStr, nclassName.string(),
-                getIndentSpace(indent+1), nclassName.string(), nclassName.string(),
+                indentStr, nclassName.c_str(),
+                getIndentSpace(indent+1), nclassName.c_str(), nclassName.c_str(),
                 indentStr);
     }
 
@@ -2303,8 +2303,8 @@
         String8 flat_name(flattenSymbol(sym.name));
         fprintf(fp,
                 "%s%s.%s = (%s.%s & 0x00ffffff) | (packageId << 24);\n",
-                getIndentSpace(indent), className.string(), flat_name.string(),
-                className.string(), flat_name.string());
+                getIndentSpace(indent), className.c_str(), flat_name.c_str(),
+                className.c_str(), flat_name.c_str());
     }
 
     N = symbols->getNestedSymbols().size();
@@ -2365,12 +2365,12 @@
                 String16 name16(sym.name);
                 uint32_t typeSpecFlags;
                 code = assets->getIncludedResources().identifierForName(
-                    name16.string(), name16.size(),
-                    attr16.string(), attr16.size(),
-                    package16.string(), package16.size(), &typeSpecFlags);
+                    name16.c_str(), name16.size(),
+                    attr16.c_str(), attr16.size(),
+                    package16.c_str(), package16.size(), &typeSpecFlags);
                 if (code == 0) {
                     fprintf(stderr, "ERROR: In <declare-styleable> %s, unable to find attribute %s\n",
-                            nclassName.string(), sym.name.string());
+                            nclassName.c_str(), sym.name.c_str());
                     hasErrors = true;
                 }
                 isPublic = (typeSpecFlags&ResTable_typeSpec::SPEC_PUBLIC) != 0;
@@ -2388,9 +2388,9 @@
         if (comment.size() > 0) {
             String8 cmt(comment);
             ann.preprocessComment(cmt);
-            fprintf(fp, "%s\n", cmt.string());
+            fprintf(fp, "%s\n", cmt.c_str());
         } else {
-            fprintf(fp, "Attributes that can be used with a %s.\n", nclassName.string());
+            fprintf(fp, "Attributes that can be used with a %s.\n", nclassName.c_str());
         }
         bool hasTable = false;
         for (a=0; a<NA; a++) {
@@ -2423,7 +2423,7 @@
                     continue;
                 }
                 if (comment.size() > 0) {
-                    const char16_t* p = comment.string();
+                    const char16_t* p = comment.c_str();
                     while (*p != 0 && *p != '.') {
                         if (*p == '{') {
                             while (*p != 0 && *p != '}') {
@@ -2436,14 +2436,14 @@
                     if (*p == '.') {
                         p++;
                     }
-                    comment = String16(comment.string(), p-comment.string());
+                    comment = String16(comment.c_str(), p-comment.c_str());
                 }
                 fprintf(fp, "%s   <tr><td><code>{@link #%s_%s %s:%s}</code></td><td>%s</td></tr>\n",
-                        indentStr, nclassName.string(),
-                        flattenSymbol(name8).string(),
-                        getSymbolPackage(name8, assets, true).string(),
-                        getSymbolName(name8).string(),
-                        String8(comment).string());
+                        indentStr, nclassName.c_str(),
+                        flattenSymbol(name8).c_str(),
+                        getSymbolPackage(name8, assets, true).c_str(),
+                        getSymbolName(name8).c_str(),
+                        String8(comment).c_str());
             }
         }
         if (hasTable) {
@@ -2457,8 +2457,8 @@
                     continue;
                 }
                 fprintf(fp, "%s   @see #%s_%s\n",
-                        indentStr, nclassName.string(),
-                        flattenSymbol(sym.name).string());
+                        indentStr, nclassName.c_str(),
+                        flattenSymbol(sym.name).c_str());
             }
         }
         fprintf(fp, "%s */\n", getIndentSpace(indent));
@@ -2468,7 +2468,7 @@
         fprintf(fp,
                 "%spublic static final int[] %s = {\n"
                 "%s",
-                indentStr, nclassName.string(),
+                indentStr, nclassName.c_str(),
                 getIndentSpace(indent+1));
 
         for (a=0; a<NA; a++) {
@@ -2503,11 +2503,11 @@
                 uint32_t typeSpecFlags = 0;
                 String16 name16(sym.name);
                 assets->getIncludedResources().identifierForName(
-                    name16.string(), name16.size(),
-                    attr16.string(), attr16.size(),
-                    package16.string(), package16.size(), &typeSpecFlags);
-                //printf("%s:%s/%s: 0x%08x\n", String8(package16).string(),
-                //    String8(attr16).string(), String8(name16).string(), typeSpecFlags);
+                    name16.c_str(), name16.size(),
+                    attr16.c_str(), attr16.size(),
+                    package16.c_str(), package16.size(), &typeSpecFlags);
+                //printf("%s:%s/%s: 0x%08x\n", String8(package16).c_str(),
+                //    String8(attr16).c_str(), String8(name16).c_str(), typeSpecFlags);
                 const bool pub = (typeSpecFlags&ResTable_typeSpec::SPEC_PUBLIC) != 0;
 
                 AnnotationProcessor ann;
@@ -2516,20 +2516,20 @@
                     String8 cmt(comment);
                     ann.preprocessComment(cmt);
                     fprintf(fp, "%s  <p>\n%s  @attr description\n", indentStr, indentStr);
-                    fprintf(fp, "%s  %s\n", indentStr, cmt.string());
+                    fprintf(fp, "%s  %s\n", indentStr, cmt.c_str());
                 } else {
                     fprintf(fp,
                             "%s  <p>This symbol is the offset where the {@link %s.R.attr#%s}\n"
                             "%s  attribute's value can be found in the {@link #%s} array.\n",
                             indentStr,
-                            getSymbolPackage(name8, assets, pub).string(),
-                            getSymbolName(name8).string(),
-                            indentStr, nclassName.string());
+                            getSymbolPackage(name8, assets, pub).c_str(),
+                            getSymbolName(name8).c_str(),
+                            indentStr, nclassName.c_str());
                 }
                 if (typeComment.size() > 0) {
                     String8 cmt(typeComment);
                     ann.preprocessComment(cmt);
-                    fprintf(fp, "\n\n%s  %s\n", indentStr, cmt.string());
+                    fprintf(fp, "\n\n%s  %s\n", indentStr, cmt.c_str());
                 }
                 if (comment.size() > 0) {
                     if (pub) {
@@ -2537,16 +2537,16 @@
                                 "%s  <p>This corresponds to the global attribute\n"
                                 "%s  resource symbol {@link %s.R.attr#%s}.\n",
                                 indentStr, indentStr,
-                                getSymbolPackage(name8, assets, true).string(),
-                                getSymbolName(name8).string());
+                                getSymbolPackage(name8, assets, true).c_str(),
+                                getSymbolName(name8).c_str());
                     } else {
                         fprintf(fp,
                                 "%s  <p>This is a private symbol.\n", indentStr);
                     }
                 }
                 fprintf(fp, "%s  @attr name %s:%s\n", indentStr,
-                        getSymbolPackage(name8, assets, pub).string(),
-                        getSymbolName(name8).string());
+                        getSymbolPackage(name8, assets, pub).c_str(),
+                        getSymbolName(name8).c_str());
                 fprintf(fp, "%s*/\n", indentStr);
                 ann.printAnnotations(fp, indentStr);
 
@@ -2556,8 +2556,8 @@
 
                 fprintf(fp,
                         id_format,
-                        indentStr, nclassName.string(),
-                        flattenSymbol(name8).string(), (int)pos);
+                        indentStr, nclassName.c_str(),
+                        flattenSymbol(name8).c_str(), (int)pos);
             }
         }
     }
@@ -2598,12 +2598,12 @@
                 String16 name16(sym.name);
                 uint32_t typeSpecFlags;
                 code = assets->getIncludedResources().identifierForName(
-                    name16.string(), name16.size(),
-                    attr16.string(), attr16.size(),
-                    package16.string(), package16.size(), &typeSpecFlags);
+                    name16.c_str(), name16.size(),
+                    attr16.c_str(), attr16.size(),
+                    package16.c_str(), package16.size(), &typeSpecFlags);
                 if (code == 0) {
                     fprintf(stderr, "ERROR: In <declare-styleable> %s, unable to find attribute %s\n",
-                            nclassName.string(), sym.name.string());
+                            nclassName.c_str(), sym.name.c_str());
                     hasErrors = true;
                 }
                 isPublic = (typeSpecFlags&ResTable_typeSpec::SPEC_PUBLIC) != 0;
@@ -2615,7 +2615,7 @@
 
         NA = idents.size();
 
-        fprintf(fp, "int[] styleable %s {", nclassName.string());
+        fprintf(fp, "int[] styleable %s {", nclassName.c_str());
 
         for (a=0; a<NA; a++) {
             if (a != 0) {
@@ -2645,17 +2645,17 @@
                 uint32_t typeSpecFlags = 0;
                 String16 name16(sym.name);
                 assets->getIncludedResources().identifierForName(
-                    name16.string(), name16.size(),
-                    attr16.string(), attr16.size(),
-                    package16.string(), package16.size(), &typeSpecFlags);
-                //printf("%s:%s/%s: 0x%08x\n", String8(package16).string(),
-                //    String8(attr16).string(), String8(name16).string(), typeSpecFlags);
+                    name16.c_str(), name16.size(),
+                    attr16.c_str(), attr16.size(),
+                    package16.c_str(), package16.size(), &typeSpecFlags);
+                //printf("%s:%s/%s: 0x%08x\n", String8(package16).c_str(),
+                //    String8(attr16).c_str(), String8(name16).c_str(), typeSpecFlags);
                 //const bool pub = (typeSpecFlags&ResTable_typeSpec::SPEC_PUBLIC) != 0;
 
                 fprintf(fp,
                         "int styleable %s_%s %d\n",
-                        nclassName.string(),
-                        flattenSymbol(name8).string(), (int)pos);
+                        nclassName.c_str(),
+                        flattenSymbol(name8).c_str(), (int)pos);
             }
         }
     }
@@ -2670,7 +2670,7 @@
 {
     fprintf(fp, "%spublic %sfinal class %s {\n",
             getIndentSpace(indent),
-            indent != 0 ? "static " : "", className.string());
+            indent != 0 ? "static " : "", className.c_str());
     indent++;
 
     size_t i;
@@ -2699,7 +2699,7 @@
             ann.preprocessComment(cmt);
             fprintf(fp,
                     "%s/** %s\n",
-                    getIndentSpace(indent), cmt.string());
+                    getIndentSpace(indent), cmt.c_str());
         }
         String16 typeComment(sym.typeComment);
         if (typeComment.size() > 0) {
@@ -2708,10 +2708,10 @@
             if (!haveComment) {
                 haveComment = true;
                 fprintf(fp,
-                        "%s/** %s\n", getIndentSpace(indent), cmt.string());
+                        "%s/** %s\n", getIndentSpace(indent), cmt.c_str());
             } else {
                 fprintf(fp,
-                        "%s %s\n", getIndentSpace(indent), cmt.string());
+                        "%s %s\n", getIndentSpace(indent), cmt.c_str());
             }
         }
         if (haveComment) {
@@ -2720,7 +2720,7 @@
         ann.printAnnotations(fp, getIndentSpace(indent));
         fprintf(fp, id_format,
                 getIndentSpace(indent),
-                flattenSymbol(name8).string(), (int)sym.int32Val);
+                flattenSymbol(name8).c_str(), (int)sym.int32Val);
     }
 
     for (i=0; i<N; i++) {
@@ -2740,13 +2740,13 @@
             fprintf(fp,
                     "%s/** %s\n"
                      "%s */\n",
-                    getIndentSpace(indent), cmt.string(),
+                    getIndentSpace(indent), cmt.c_str(),
                     getIndentSpace(indent));
         }
         ann.printAnnotations(fp, getIndentSpace(indent));
         fprintf(fp, "%spublic static final String %s=\"%s\";\n",
                 getIndentSpace(indent),
-                flattenSymbol(name8).string(), sym.stringVal.string());
+                flattenSymbol(name8).c_str(), sym.stringVal.c_str());
     }
 
     sp<AaptSymbols> styleableSymbols;
@@ -2805,8 +2805,8 @@
 
         String8 name8(sym.name);
         fprintf(fp, "int %s %s 0x%08x\n",
-                className.string(),
-                flattenSymbol(name8).string(), (int)sym.int32Val);
+                className.c_str(),
+                flattenSymbol(name8).c_str(), (int)sym.int32Val);
     }
 
     N = symbols->getNestedSymbols().size();
@@ -2844,7 +2844,7 @@
 
         if (bundle->getMakePackageDirs()) {
             const String8& pkg(package);
-            const char* last = pkg.string();
+            const char* last = pkg.c_str();
             const char* s = last-1;
             do {
                 s++;
@@ -2852,9 +2852,9 @@
                     String8 part(last, s-last);
                     dest.appendPath(part);
 #ifdef _WIN32
-                    _mkdir(dest.string());
+                    _mkdir(dest.c_str());
 #else
-                    mkdir(dest.string(), S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IXGRP);
+                    mkdir(dest.c_str(), S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IXGRP);
 #endif
                     last = s+1;
                 }
@@ -2862,14 +2862,14 @@
         }
         dest.appendPath(className);
         dest.append(".java");
-        FILE* fp = fopen(dest.string(), "w+");
+        FILE* fp = fopen(dest.c_str(), "w+");
         if (fp == NULL) {
             fprintf(stderr, "ERROR: Unable to open class file %s: %s\n",
-                    dest.string(), strerror(errno));
+                    dest.c_str(), strerror(errno));
             return UNKNOWN_ERROR;
         }
         if (bundle->getVerbose()) {
-            printf("  Writing symbols for class %s.\n", className.string());
+            printf("  Writing symbols for class %s.\n", className.c_str());
         }
 
         fprintf(fp,
@@ -2880,7 +2880,7 @@
             " * should not be modified by hand.\n"
             " */\n"
             "\n"
-            "package %s;\n\n", package.string());
+            "package %s;\n\n", package.c_str());
 
         status_t err = writeSymbolClass(fp, assets, includePrivate, symbols,
                 className, 0, bundle->getNonConstantId(), emitCallback);
@@ -2894,14 +2894,14 @@
             textDest.appendPath(className);
             textDest.append(".txt");
 
-            FILE* fp = fopen(textDest.string(), "w+");
+            FILE* fp = fopen(textDest.c_str(), "w+");
             if (fp == NULL) {
                 fprintf(stderr, "ERROR: Unable to open text symbol file %s: %s\n",
-                        textDest.string(), strerror(errno));
+                        textDest.c_str(), strerror(errno));
                 return UNKNOWN_ERROR;
             }
             if (bundle->getVerbose()) {
-                printf("  Writing text symbols for class %s.\n", className.string());
+                printf("  Writing text symbols for class %s.\n", className.c_str());
             }
 
             status_t err = writeTextSymbolClass(fp, assets, includePrivate, symbols,
@@ -2919,8 +2919,8 @@
             String8 dependencyFile(bundle->getRClassDir());
             dependencyFile.appendPath("R.java.d");
 
-            FILE *fp = fopen(dependencyFile.string(), "a");
-            fprintf(fp,"%s \\\n", dest.string());
+            FILE *fp = fopen(dependencyFile.c_str(), "a");
+            fprintf(fp,"%s \\\n", dest.c_str());
             fclose(fp);
         }
     }
@@ -2956,7 +2956,7 @@
         // asdf     --> package.asdf
         // .asdf  .a.b  --> package.asdf package.a.b
         // asdf.adsf --> asdf.asdf
-        const char* p = className.string();
+        const char* p = className.c_str();
         const char* q = strchr(p, '.');
         if (p == q) {
             className = pkg;
@@ -3023,7 +3023,7 @@
 
     if (assGroup->getFiles().size() != 1) {
         fprintf(stderr, "warning: Multiple AndroidManifest.xml files found, using %s\n",
-                assGroup->getFiles().valueAt(0)->getPrintableSource().string());
+                assGroup->getFiles().valueAt(0)->getPrintableSource().c_str());
     }
 
     assFile = assGroup->getFiles().valueAt(0);
@@ -3048,7 +3048,7 @@
         }
         depth++;
         String8 tag(tree.getElementName(&len));
-        // printf("Depth %d tag %s\n", depth, tag.string());
+        // printf("Depth %d tag %s\n", depth, tag.c_str());
         bool keepTag = false;
         if (depth == 1) {
             if (tag != "manifest") {
@@ -3065,7 +3065,7 @@
                         "http://schemas.android.com/apk/res/android",
                         "backupAgent", &error);
                 if (agent.length() > 0) {
-                    addProguardKeepRule(keep, agent, pkg.string(),
+                    addProguardKeepRule(keep, agent, pkg.c_str(),
                             assFile->getPrintableSource(), tree.getLineNumber());
                 }
 
@@ -3073,7 +3073,7 @@
                     defaultProcess = AaptXml::getAttribute(tree,
                             "http://schemas.android.com/apk/res/android", "process", &error);
                     if (error != "") {
-                        fprintf(stderr, "ERROR: %s\n", error.string());
+                        fprintf(stderr, "ERROR: %s\n", error.c_str());
                         return -1;
                     }
                 }
@@ -3089,7 +3089,7 @@
                     String8 componentProcess = AaptXml::getAttribute(tree,
                             "http://schemas.android.com/apk/res/android", "process", &error);
                     if (error != "") {
-                        fprintf(stderr, "ERROR: %s\n", error.string());
+                        fprintf(stderr, "ERROR: %s\n", error.c_str());
                         return -1;
                     }
 
@@ -3103,14 +3103,14 @@
             String8 name = AaptXml::getAttribute(tree,
                     "http://schemas.android.com/apk/res/android", "name", &error);
             if (error != "") {
-                fprintf(stderr, "ERROR: %s\n", error.string());
+                fprintf(stderr, "ERROR: %s\n", error.c_str());
                 return -1;
             }
 
             keepTag = name.length() > 0;
 
             if (keepTag) {
-                addProguardKeepRule(keep, name, pkg.string(),
+                addProguardKeepRule(keep, name, pkg.c_str(),
                         assFile->getPrintableSource(), tree.getLineNumber());
             }
         }
@@ -3170,7 +3170,7 @@
         String8 tag(tree.getElementName(&len));
 
         // If there is no '.', we'll assume that it's one of the built in names.
-        if (strchr(tag.string(), '.')) {
+        if (strchr(tag.c_str(), '.')) {
             addProguardKeepRule(keep, tag, NULL,
                     layoutFile->getPrintableSource(), tree.getLineNumber());
         } else if (tagAttrPairs != NULL) {
@@ -3183,8 +3183,8 @@
                     ssize_t attrIndex = tree.indexOfAttribute(nsAttr.ns, nsAttr.attr);
                     if (attrIndex < 0) {
                         // fprintf(stderr, "%s:%d: <%s> does not have attribute %s:%s.\n",
-                        //        layoutFile->getPrintableSource().string(), tree.getLineNumber(),
-                        //        tag.string(), nsAttr.ns, nsAttr.attr);
+                        //        layoutFile->getPrintableSource().c_str(), tree.getLineNumber(),
+                        //        tag.c_str(), nsAttr.ns, nsAttr.attr);
                     } else {
                         size_t len;
                         addProguardKeepRule(keep,
@@ -3242,7 +3242,7 @@
 
     // tag:attribute pairs that should be checked in transition files.
     KeyedVector<String8, Vector<NamespaceAttributePair> > kTransitionTagAttrPairs;
-    addTagAttrPair(&kTransitionTagAttrPairs, kTransition.string(), NULL, kClass);
+    addTagAttrPair(&kTransitionTagAttrPairs, kTransition.c_str(), NULL, kClass);
     addTagAttrPair(&kTransitionTagAttrPairs, "pathMotion", NULL, kClass);
 
     const Vector<sp<AaptDir> >& dirs = assets->resDirs();
@@ -3252,16 +3252,16 @@
         const String8& dirName = d->getLeaf();
         Vector<String8> startTags;
         const KeyedVector<String8, Vector<NamespaceAttributePair> >* tagAttrPairs = NULL;
-        if ((dirName == String8("layout")) || (strncmp(dirName.string(), "layout-", 7) == 0)) {
+        if ((dirName == String8("layout")) || (strncmp(dirName.c_str(), "layout-", 7) == 0)) {
             tagAttrPairs = &kLayoutTagAttrPairs;
-        } else if ((dirName == String8("xml")) || (strncmp(dirName.string(), "xml-", 4) == 0)) {
+        } else if ((dirName == String8("xml")) || (strncmp(dirName.c_str(), "xml-", 4) == 0)) {
             startTags.add(String8("PreferenceScreen"));
             startTags.add(String8("preference-headers"));
             tagAttrPairs = &kXmlTagAttrPairs;
-        } else if ((dirName == String8("menu")) || (strncmp(dirName.string(), "menu-", 5) == 0)) {
+        } else if ((dirName == String8("menu")) || (strncmp(dirName.c_str(), "menu-", 5) == 0)) {
             startTags.add(String8("menu"));
             tagAttrPairs = NULL;
-        } else if (dirName == kTransition || (strncmp(dirName.string(), kTransitionPrefix.string(),
+        } else if (dirName == kTransition || (strncmp(dirName.c_str(), kTransitionPrefix.c_str(),
                         kTransitionPrefix.size()) == 0)) {
             tagAttrPairs = &kTransitionTagAttrPairs;
         } else {
@@ -3307,9 +3307,9 @@
         const SortedVector<String8>& locations = rules.valueAt(i);
         const size_t M = locations.size();
         for (size_t j=0; j<M; j++) {
-            fprintf(fp, "# %s\n", locations.itemAt(j).string());
+            fprintf(fp, "# %s\n", locations.itemAt(j).c_str());
         }
-        fprintf(fp, "%s\n\n", rules.keyAt(i).string());
+        fprintf(fp, "%s\n\n", rules.keyAt(i).c_str());
     }
     fclose(fp);
 
@@ -3366,7 +3366,7 @@
     status_t deps = -1;
     for (size_t file_i = 0; file_i < files->size(); ++file_i) {
         // Add the full file path to the dependency file
-        fprintf(fp, "%s \\\n", files->itemAt(file_i).string());
+        fprintf(fp, "%s \\\n", files->itemAt(file_i).c_str());
         deps++;
     }
     return deps;
diff --git a/tools/aapt/ResourceFilter.cpp b/tools/aapt/ResourceFilter.cpp
index ed06f60..cc8dce7e 100644
--- a/tools/aapt/ResourceFilter.cpp
+++ b/tools/aapt/ResourceFilter.cpp
@@ -32,7 +32,7 @@
             // only specify locale in the standard 'en_US' format.
             val.writeTo(&entry.first);
         } else if (!AaptConfig::parse(part, &entry.first)) {
-            fprintf(stderr, "Invalid configuration: %s\n", part.string());
+            fprintf(stderr, "Invalid configuration: %s\n", part.c_str());
             return UNKNOWN_ERROR;
         }
 
@@ -43,7 +43,7 @@
 
         // Ignore any densities. Those are best handled in --preferred-density
         if ((entry.second & ResTable_config::CONFIG_DENSITY) != 0) {
-            fprintf(stderr, "warning: ignoring flag -c %s. Use --preferred-density instead.\n", entry.first.toString().string());
+            fprintf(stderr, "warning: ignoring flag -c %s. Use --preferred-density instead.\n", entry.first.toString().c_str());
             entry.first.density = 0;
             entry.second &= ~ResTable_config::CONFIG_DENSITY;
         }
@@ -148,7 +148,7 @@
     mConfigs.clear();
     for (size_t i = 0; i < configStrs.size(); i++) {
         if (!AaptConfig::parse(configStrs[i], &config)) {
-            fprintf(stderr, "Invalid configuration: %s\n", configStrs[i].string());
+            fprintf(stderr, "Invalid configuration: %s\n", configStrs[i].c_str());
             return UNKNOWN_ERROR;
         }
         mConfigs.insert(config);
diff --git a/tools/aapt/ResourceIdCache.cpp b/tools/aapt/ResourceIdCache.cpp
index 8835fb0..1c7788d 100644
--- a/tools/aapt/ResourceIdCache.cpp
+++ b/tools/aapt/ResourceIdCache.cpp
@@ -37,7 +37,7 @@
 
 static uint32_t hash(const android::String16& hashableString) {
     uint32_t hash = 5381;
-    const char16_t* str = hashableString.string();
+    const char16_t* str = hashableString.c_str();
     while (int c = *str++) hash = hashround(hash, c);
     return hash;
 }
diff --git a/tools/aapt/ResourceTable.cpp b/tools/aapt/ResourceTable.cpp
index 4e597fb..2344007 100644
--- a/tools/aapt/ResourceTable.cpp
+++ b/tools/aapt/ResourceTable.cpp
@@ -361,10 +361,10 @@
     ssize_t typeIdx = block.indexOfAttribute(NULL, "format");
     if (typeIdx >= 0) {
         String16 typeStr = String16(block.getAttributeStringValue(typeIdx, &len));
-        attr.type = parse_flags(typeStr.string(), typeStr.size(), gFormatFlags);
+        attr.type = parse_flags(typeStr.c_str(), typeStr.size(), gFormatFlags);
         if (attr.type == 0) {
             attr.sourcePos.error("Tag <attr> 'format' attribute value \"%s\" not valid\n",
-                    String8(typeStr).string());
+                    String8(typeStr).c_str());
             attr.hasErrors = true;
         }
         attr.createIfNeeded(outTable);
@@ -374,14 +374,14 @@
         attr.createIfNeeded(outTable);
     }
 
-    //printf("Attribute %s: type=0x%08x\n", String8(attr.ident).string(), attr.type);
+    //printf("Attribute %s: type=0x%08x\n", String8(attr.ident).c_str(), attr.type);
 
     ssize_t minIdx = block.indexOfAttribute(NULL, "min");
     if (minIdx >= 0) {
         String16 val = String16(block.getAttributeStringValue(minIdx, &len));
-        if (!ResTable::stringToInt(val.string(), val.size(), NULL)) {
+        if (!ResTable::stringToInt(val.c_str(), val.size(), NULL)) {
             attr.sourcePos.error("Tag <attr> 'min' attribute must be a number, not \"%s\"\n",
-                    String8(val).string());
+                    String8(val).c_str());
             attr.hasErrors = true;
         }
         attr.createIfNeeded(outTable);
@@ -397,9 +397,9 @@
     ssize_t maxIdx = block.indexOfAttribute(NULL, "max");
     if (maxIdx >= 0) {
         String16 val = String16(block.getAttributeStringValue(maxIdx, &len));
-        if (!ResTable::stringToInt(val.string(), val.size(), NULL)) {
+        if (!ResTable::stringToInt(val.c_str(), val.size(), NULL)) {
             attr.sourcePos.error("Tag <attr> 'max' attribute must be a number, not \"%s\"\n",
-                    String8(val).string());
+                    String8(val).c_str());
             attr.hasErrors = true;
         }
         attr.createIfNeeded(outTable);
@@ -422,7 +422,7 @@
         uint32_t l10n_required = parse_flags(str, len, l10nRequiredFlags, &error);
         if (error) {
             attr.sourcePos.error("Tag <attr> 'localization' attribute value \"%s\" not valid\n",
-                    String8(str).string());
+                    String8(str).c_str());
             attr.hasErrors = true;
         }
         attr.createIfNeeded(outTable);
@@ -442,14 +442,14 @@
     while ((code=block.next()) != ResXMLTree::END_DOCUMENT && code != ResXMLTree::BAD_DOCUMENT) {
         if (code == ResXMLTree::START_TAG) {
             uint32_t localType = 0;
-            if (strcmp16(block.getElementName(&len), enum16.string()) == 0) {
+            if (strcmp16(block.getElementName(&len), enum16.c_str()) == 0) {
                 localType = ResTable_map::TYPE_ENUM;
-            } else if (strcmp16(block.getElementName(&len), flag16.string()) == 0) {
+            } else if (strcmp16(block.getElementName(&len), flag16.c_str()) == 0) {
                 localType = ResTable_map::TYPE_FLAGS;
             } else {
                 SourcePos(in->getPrintableSource(), block.getLineNumber())
                         .error("Tag <%s> can not appear inside <attr>, only <enum> or <flag>\n",
-                        String8(block.getElementName(&len)).string());
+                        String8(block.getElementName(&len)).c_str());
                 return UNKNOWN_ERROR;
             }
 
@@ -505,11 +505,11 @@
                         .error("A 'value' attribute is required for <enum> or <flag>\n");
                 attr.hasErrors = true;
             }
-            if (!attr.hasErrors && !ResTable::stringToInt(value.string(), value.size(), NULL)) {
+            if (!attr.hasErrors && !ResTable::stringToInt(value.c_str(), value.size(), NULL)) {
                 SourcePos(in->getPrintableSource(), block.getLineNumber())
                         .error("Tag <enum> or <flag> 'value' attribute must be a number,"
                         " not \"%s\"\n",
-                        String8(value).string());
+                        String8(value).c_str());
                 attr.hasErrors = true;
             }
 
@@ -546,21 +546,21 @@
                 }
             }
         } else if (code == ResXMLTree::END_TAG) {
-            if (strcmp16(block.getElementName(&len), attr16.string()) == 0) {
+            if (strcmp16(block.getElementName(&len), attr16.c_str()) == 0) {
                 break;
             }
             if ((attr.type&ResTable_map::TYPE_ENUM) != 0) {
-                if (strcmp16(block.getElementName(&len), enum16.string()) != 0) {
+                if (strcmp16(block.getElementName(&len), enum16.c_str()) != 0) {
                     SourcePos(in->getPrintableSource(), block.getLineNumber())
                             .error("Found tag </%s> where </enum> is expected\n",
-                            String8(block.getElementName(&len)).string());
+                            String8(block.getElementName(&len)).c_str());
                     return UNKNOWN_ERROR;
                 }
             } else {
-                if (strcmp16(block.getElementName(&len), flag16.string()) != 0) {
+                if (strcmp16(block.getElementName(&len), flag16.c_str()) != 0) {
                     SourcePos(in->getPrintableSource(), block.getLineNumber())
                             .error("Found tag </%s> where </flag> is expected\n",
-                            String8(block.getElementName(&len)).string());
+                            String8(block.getElementName(&len)).c_str());
                     return UNKNOWN_ERROR;
                 }
             }
@@ -606,7 +606,7 @@
 
     String16 str;
     Vector<StringPool::entry_style_span> spans;
-    err = parseStyledString(bundle, in->getPrintableSource().string(),
+    err = parseStyledString(bundle, in->getPrintableSource().c_str(),
                             block, item16, &str, &spans, isFormatted,
                             pseudolocalize);
     if (err != NO_ERROR) {
@@ -619,10 +619,10 @@
                 config.language[0], config.language[1],
                 config.country[0], config.country[1],
                 config.orientation, config.density,
-                String8(parentIdent).string(),
-                String8(ident).string(),
-                String8(itemIdent).string(),
-                String8(str).string());
+                String8(parentIdent).c_str(),
+                String8(ident).c_str(),
+                String8(itemIdent).c_str(),
+                String8(str).c_str());
     }
 
     err = outTable->addBag(SourcePos(in->getPrintableSource(), block->getLineNumber()),
@@ -636,8 +636,8 @@
  * haystack, false otherwise.
  */
 bool isInProductList(const String16& needle, const String16& haystack) {
-    const char16_t *needle2 = needle.string();
-    const char16_t *haystack2 = haystack.string();
+    const char16_t *needle2 = needle.c_str();
+    const char16_t *haystack2 = haystack.c_str();
     size_t needlesize = needle.size();
 
     while (*haystack2 != '\0') {
@@ -703,7 +703,7 @@
 
     String16 str;
     Vector<StringPool::entry_style_span> spans;
-    err = parseStyledString(bundle, in->getPrintableSource().string(), block,
+    err = parseStyledString(bundle, in->getPrintableSource().c_str(), block,
                             curTag, &str, curIsStyled ? &spans : NULL,
                             isFormatted, pseudolocalize);
 
@@ -730,7 +730,7 @@
          */
 
         if (bundleProduct[0] == '\0') {
-            if (strcmp16(String16("default").string(), product.string()) != 0) {
+            if (strcmp16(String16("default").c_str(), product.c_str()) != 0) {
                 /*
                  * This string has a product other than 'default'. Do not add it,
                  * but record it so that if we do not see the same string with
@@ -750,7 +750,7 @@
 
             if (isInProductList(product, String16(bundleProduct))) {
                 ;
-            } else if (strcmp16(String16("default").string(), product.string()) == 0 &&
+            } else if (strcmp16(String16("default").c_str(), product.c_str()) == 0 &&
                        !outTable->hasBagOrEntry(myPackage, curType, ident, config)) {
                 ;
             } else {
@@ -764,7 +764,7 @@
                 config.language[0], config.language[1],
                 config.country[0], config.country[1],
                 config.orientation, config.density,
-                String8(ident).string(), String8(str).string());
+                String8(ident).c_str(), String8(str).c_str());
     }
 
     err = outTable->addEntry(SourcePos(in->getPrintableSource(), block->getLineNumber()),
@@ -847,7 +847,7 @@
     bool hasErrors = false;
 
     bool fileIsTranslatable = true;
-    if (strstr(in->getPrintableSource().string(), "donottranslate") != NULL) {
+    if (strstr(in->getPrintableSource().c_str(), "donottranslate") != NULL) {
         fileIsTranslatable = false;
     }
 
@@ -869,9 +869,9 @@
                 "No start tag found\n");
         return UNKNOWN_ERROR;
     }
-    if (strcmp16(block.getElementName(&len), resources16.string()) != 0) {
+    if (strcmp16(block.getElementName(&len), resources16.c_str()) != 0) {
         SourcePos(in->getPrintableSource(), block.getLineNumber()).error(
-                "Invalid start tag %s\n", String8(block.getElementName(&len)).string());
+                "Invalid start tag %s\n", String8(block.getElementName(&len)).c_str());
         return UNKNOWN_ERROR;
     }
 
@@ -900,7 +900,7 @@
         SourcePos(in->getPrintableSource(), 0).warning(
                 "Resource file %s is skipped as pseudolocalization"
                 " was done automatically.",
-                in->getPrintableSource().string());
+                in->getPrintableSource().c_str());
         return NO_ERROR;
     }
 
@@ -917,29 +917,29 @@
             bool curIsFormatted = fileIsTranslatable;
             bool localHasErrors = false;
 
-            if (strcmp16(block.getElementName(&len), skip16.string()) == 0) {
+            if (strcmp16(block.getElementName(&len), skip16.c_str()) == 0) {
                 while ((code=block.next()) != ResXMLTree::END_DOCUMENT
                         && code != ResXMLTree::BAD_DOCUMENT) {
                     if (code == ResXMLTree::END_TAG) {
-                        if (strcmp16(block.getElementName(&len), skip16.string()) == 0) {
+                        if (strcmp16(block.getElementName(&len), skip16.c_str()) == 0) {
                             break;
                         }
                     }
                 }
                 continue;
 
-            } else if (strcmp16(block.getElementName(&len), eat_comment16.string()) == 0) {
+            } else if (strcmp16(block.getElementName(&len), eat_comment16.c_str()) == 0) {
                 while ((code=block.next()) != ResXMLTree::END_DOCUMENT
                         && code != ResXMLTree::BAD_DOCUMENT) {
                     if (code == ResXMLTree::END_TAG) {
-                        if (strcmp16(block.getElementName(&len), eat_comment16.string()) == 0) {
+                        if (strcmp16(block.getElementName(&len), eat_comment16.c_str()) == 0) {
                             break;
                         }
                     }
                 }
                 continue;
 
-            } else if (strcmp16(block.getElementName(&len), public16.string()) == 0) {
+            } else if (strcmp16(block.getElementName(&len), public16.c_str()) == 0) {
                 SourcePos srcPos(in->getPrintableSource(), block.getLineNumber());
             
                 String16 type;
@@ -965,7 +965,7 @@
                     Res_value identValue;
                     if (!ResTable::stringToInt(identStr, len, &identValue)) {
                         srcPos.error("Given 'id' attribute is not an integer: %s\n",
-                                String8(block.getAttributeStringValue(identIdx, &len)).string());
+                                String8(block.getAttributeStringValue(identIdx, &len)).c_str());
                         hasErrors = localHasErrors = true;
                     } else {
                         ident = identValue.data;
@@ -1004,14 +1004,14 @@
 
                 while ((code=block.next()) != ResXMLTree::END_DOCUMENT && code != ResXMLTree::BAD_DOCUMENT) {
                     if (code == ResXMLTree::END_TAG) {
-                        if (strcmp16(block.getElementName(&len), public16.string()) == 0) {
+                        if (strcmp16(block.getElementName(&len), public16.c_str()) == 0) {
                             break;
                         }
                     }
                 }
                 continue;
 
-            } else if (strcmp16(block.getElementName(&len), public_padding16.string()) == 0) {
+            } else if (strcmp16(block.getElementName(&len), public_padding16.c_str()) == 0) {
                 SourcePos srcPos(in->getPrintableSource(), block.getLineNumber());
             
                 String16 type;
@@ -1037,7 +1037,7 @@
                     Res_value startValue;
                     if (!ResTable::stringToInt(startStr, len, &startValue)) {
                         srcPos.error("Given 'start' attribute is not an integer: %s\n",
-                                String8(block.getAttributeStringValue(startIdx, &len)).string());
+                                String8(block.getAttributeStringValue(startIdx, &len)).c_str());
                         hasErrors = localHasErrors = true;
                     } else {
                         start = startValue.data;
@@ -1057,7 +1057,7 @@
                     Res_value endValue;
                     if (!ResTable::stringToInt(endStr, len, &endValue)) {
                         srcPos.error("Given 'end' attribute is not an integer: %s\n",
-                                String8(block.getAttributeStringValue(endIdx, &len)).string());
+                                String8(block.getAttributeStringValue(endIdx, &len)).c_str());
                         hasErrors = localHasErrors = true;
                     } else {
                         end = endValue.data;
@@ -1114,14 +1114,14 @@
 
                 while ((code=block.next()) != ResXMLTree::END_DOCUMENT && code != ResXMLTree::BAD_DOCUMENT) {
                     if (code == ResXMLTree::END_TAG) {
-                        if (strcmp16(block.getElementName(&len), public_padding16.string()) == 0) {
+                        if (strcmp16(block.getElementName(&len), public_padding16.c_str()) == 0) {
                             break;
                         }
                     }
                 }
                 continue;
 
-            } else if (strcmp16(block.getElementName(&len), private_symbols16.string()) == 0) {
+            } else if (strcmp16(block.getElementName(&len), private_symbols16.c_str()) == 0) {
                 String16 pkg;
                 ssize_t pkgIdx = block.indexOfAttribute(NULL, "package");
                 if (pkgIdx < 0) {
@@ -1144,14 +1144,14 @@
 
                 while ((code=block.next()) != ResXMLTree::END_DOCUMENT && code != ResXMLTree::BAD_DOCUMENT) {
                     if (code == ResXMLTree::END_TAG) {
-                        if (strcmp16(block.getElementName(&len), private_symbols16.string()) == 0) {
+                        if (strcmp16(block.getElementName(&len), private_symbols16.c_str()) == 0) {
                             break;
                         }
                     }
                 }
                 continue;
 
-            } else if (strcmp16(block.getElementName(&len), java_symbol16.string()) == 0) {
+            } else if (strcmp16(block.getElementName(&len), java_symbol16.c_str()) == 0) {
                 SourcePos srcPos(in->getPrintableSource(), block.getLineNumber());
             
                 String16 type;
@@ -1186,7 +1186,7 @@
 
                 while ((code=block.next()) != ResXMLTree::END_DOCUMENT && code != ResXMLTree::BAD_DOCUMENT) {
                     if (code == ResXMLTree::END_TAG) {
-                        if (strcmp16(block.getElementName(&len), java_symbol16.string()) == 0) {
+                        if (strcmp16(block.getElementName(&len), java_symbol16.c_str()) == 0) {
                             break;
                         }
                     }
@@ -1194,7 +1194,7 @@
                 continue;
 
 
-            } else if (strcmp16(block.getElementName(&len), add_resource16.string()) == 0) {
+            } else if (strcmp16(block.getElementName(&len), add_resource16.c_str()) == 0) {
                 SourcePos srcPos(in->getPrintableSource(), block.getLineNumber());
             
                 String16 typeName;
@@ -1217,14 +1217,14 @@
 
                 while ((code=block.next()) != ResXMLTree::END_DOCUMENT && code != ResXMLTree::BAD_DOCUMENT) {
                     if (code == ResXMLTree::END_TAG) {
-                        if (strcmp16(block.getElementName(&len), add_resource16.string()) == 0) {
+                        if (strcmp16(block.getElementName(&len), add_resource16.c_str()) == 0) {
                             break;
                         }
                     }
                 }
                 continue;
                 
-            } else if (strcmp16(block.getElementName(&len), declare_styleable16.string()) == 0) {
+            } else if (strcmp16(block.getElementName(&len), declare_styleable16.c_str()) == 0) {
                 SourcePos srcPos(in->getPrintableSource(), block.getLineNumber());
                                 
                 String16 ident;
@@ -1258,30 +1258,30 @@
 
                 while ((code=block.next()) != ResXMLTree::END_DOCUMENT && code != ResXMLTree::BAD_DOCUMENT) {
                     if (code == ResXMLTree::START_TAG) {
-                        if (strcmp16(block.getElementName(&len), skip16.string()) == 0) {
+                        if (strcmp16(block.getElementName(&len), skip16.c_str()) == 0) {
                             while ((code=block.next()) != ResXMLTree::END_DOCUMENT
                                    && code != ResXMLTree::BAD_DOCUMENT) {
                                 if (code == ResXMLTree::END_TAG) {
-                                    if (strcmp16(block.getElementName(&len), skip16.string()) == 0) {
+                                    if (strcmp16(block.getElementName(&len), skip16.c_str()) == 0) {
                                         break;
                                     }
                                 }
                             }
                             continue;
-                        } else if (strcmp16(block.getElementName(&len), eat_comment16.string()) == 0) {
+                        } else if (strcmp16(block.getElementName(&len), eat_comment16.c_str()) == 0) {
                             while ((code=block.next()) != ResXMLTree::END_DOCUMENT
                                    && code != ResXMLTree::BAD_DOCUMENT) {
                                 if (code == ResXMLTree::END_TAG) {
-                                    if (strcmp16(block.getElementName(&len), eat_comment16.string()) == 0) {
+                                    if (strcmp16(block.getElementName(&len), eat_comment16.c_str()) == 0) {
                                         break;
                                     }
                                 }
                             }
                             continue;
-                        } else if (strcmp16(block.getElementName(&len), attr16.string()) != 0) {
+                        } else if (strcmp16(block.getElementName(&len), attr16.c_str()) != 0) {
                             SourcePos(in->getPrintableSource(), block.getLineNumber()).error(
                                     "Tag <%s> can not appear inside <declare-styleable>, only <attr>\n",
-                                    String8(block.getElementName(&len)).string());
+                                    String8(block.getElementName(&len)).c_str());
                             return UNKNOWN_ERROR;
                         }
 
@@ -1297,30 +1297,30 @@
                             SourcePos srcPos(String8(in->getPrintableSource()), block.getLineNumber());
                             symbols->addSymbol(String8(itemIdent), 0, srcPos);
                             symbols->appendComment(String8(itemIdent), comment, srcPos);
-                            //printf("Attribute %s comment: %s\n", String8(itemIdent).string(),
-                            //     String8(comment).string());
+                            //printf("Attribute %s comment: %s\n", String8(itemIdent).c_str(),
+                            //     String8(comment).c_str());
                         }
                     } else if (code == ResXMLTree::END_TAG) {
-                        if (strcmp16(block.getElementName(&len), declare_styleable16.string()) == 0) {
+                        if (strcmp16(block.getElementName(&len), declare_styleable16.c_str()) == 0) {
                             break;
                         }
 
                         SourcePos(in->getPrintableSource(), block.getLineNumber()).error(
                                 "Found tag </%s> where </attr> is expected\n",
-                                String8(block.getElementName(&len)).string());
+                                String8(block.getElementName(&len)).c_str());
                         return UNKNOWN_ERROR;
                     }
                 }
                 continue;
 
-            } else if (strcmp16(block.getElementName(&len), attr16.string()) == 0) {
+            } else if (strcmp16(block.getElementName(&len), attr16.c_str()) == 0) {
                 err = compileAttribute(in, block, myPackage, outTable, NULL);
                 if (err != NO_ERROR) {
                     hasErrors = true;
                 }
                 continue;
 
-            } else if (strcmp16(block.getElementName(&len), item16.string()) == 0) {
+            } else if (strcmp16(block.getElementName(&len), item16.c_str()) == 0) {
                 curTag = &item16;
                 ssize_t attri = block.indexOfAttribute(NULL, "type");
                 if (attri >= 0) {
@@ -1333,12 +1333,12 @@
                     if (formatIdx >= 0) {
                         String16 formatStr = String16(block.getAttributeStringValue(
                                 formatIdx, &len));
-                        curFormat = parse_flags(formatStr.string(), formatStr.size(),
+                        curFormat = parse_flags(formatStr.c_str(), formatStr.size(),
                                                 gFormatFlags);
                         if (curFormat == 0) {
                             SourcePos(in->getPrintableSource(), block.getLineNumber()).error(
                                     "Tag <item> 'format' attribute value \"%s\" not valid\n",
-                                    String8(formatStr).string());
+                                    String8(formatStr).c_str());
                             hasErrors = localHasErrors = true;
                         }
                     }
@@ -1348,7 +1348,7 @@
                     hasErrors = localHasErrors = true;
                 }
                 curIsStyled = true;
-            } else if (strcmp16(block.getElementName(&len), string16.string()) == 0) {
+            } else if (strcmp16(block.getElementName(&len), string16.c_str()) == 0) {
                 // Note the existence and locale of every string we process
                 char rawLocale[RESTABLE_MAX_LOCALE_LEN];
                 curParams.getBcp47Locale(rawLocale);
@@ -1361,11 +1361,11 @@
                 for (size_t i = 0; i < n; i++) {
                     size_t length;
                     const char16_t* attr = block.getAttributeName(i, &length);
-                    if (strcmp16(attr, name16.string()) == 0) {
+                    if (strcmp16(attr, name16.c_str()) == 0) {
                         name.setTo(block.getAttributeStringValue(i, &length));
-                    } else if (strcmp16(attr, translatable16.string()) == 0) {
+                    } else if (strcmp16(attr, translatable16.c_str()) == 0) {
                         translatable.setTo(block.getAttributeStringValue(i, &length));
-                    } else if (strcmp16(attr, formatted16.string()) == 0) {
+                    } else if (strcmp16(attr, formatted16.c_str()) == 0) {
                         formatted.setTo(block.getAttributeStringValue(i, &length));
                     }
                 }
@@ -1380,8 +1380,8 @@
                         if (locale.size() > 0) {
                             SourcePos(in->getPrintableSource(), block.getLineNumber()).warning(
                                     "string '%s' marked untranslatable but exists in locale '%s'\n",
-                                    String8(name).string(),
-                                    locale.string());
+                                    String8(name).c_str(),
+                                    locale.c_str());
                             // hasErrors = localHasErrors = true;
                         } else {
                             // Intentionally empty block:
@@ -1407,31 +1407,31 @@
                 curFormat = ResTable_map::TYPE_REFERENCE|ResTable_map::TYPE_STRING;
                 curIsStyled = true;
                 curIsPseudolocalizable = fileIsTranslatable && (translatable != false16);
-            } else if (strcmp16(block.getElementName(&len), drawable16.string()) == 0) {
+            } else if (strcmp16(block.getElementName(&len), drawable16.c_str()) == 0) {
                 curTag = &drawable16;
                 curType = drawable16;
                 curFormat = ResTable_map::TYPE_REFERENCE|ResTable_map::TYPE_COLOR;
-            } else if (strcmp16(block.getElementName(&len), color16.string()) == 0) {
+            } else if (strcmp16(block.getElementName(&len), color16.c_str()) == 0) {
                 curTag = &color16;
                 curType = color16;
                 curFormat = ResTable_map::TYPE_REFERENCE|ResTable_map::TYPE_COLOR;
-            } else if (strcmp16(block.getElementName(&len), bool16.string()) == 0) {
+            } else if (strcmp16(block.getElementName(&len), bool16.c_str()) == 0) {
                 curTag = &bool16;
                 curType = bool16;
                 curFormat = ResTable_map::TYPE_REFERENCE|ResTable_map::TYPE_BOOLEAN;
-            } else if (strcmp16(block.getElementName(&len), integer16.string()) == 0) {
+            } else if (strcmp16(block.getElementName(&len), integer16.c_str()) == 0) {
                 curTag = &integer16;
                 curType = integer16;
                 curFormat = ResTable_map::TYPE_REFERENCE|ResTable_map::TYPE_INTEGER;
-            } else if (strcmp16(block.getElementName(&len), dimen16.string()) == 0) {
+            } else if (strcmp16(block.getElementName(&len), dimen16.c_str()) == 0) {
                 curTag = &dimen16;
                 curType = dimen16;
                 curFormat = ResTable_map::TYPE_REFERENCE|ResTable_map::TYPE_DIMENSION;
-            } else if (strcmp16(block.getElementName(&len), fraction16.string()) == 0) {
+            } else if (strcmp16(block.getElementName(&len), fraction16.c_str()) == 0) {
                 curTag = &fraction16;
                 curType = fraction16;
                 curFormat = ResTable_map::TYPE_REFERENCE|ResTable_map::TYPE_FRACTION;
-            } else if (strcmp16(block.getElementName(&len), bag16.string()) == 0) {
+            } else if (strcmp16(block.getElementName(&len), bag16.c_str()) == 0) {
                 curTag = &bag16;
                 curIsBag = true;
                 ssize_t attri = block.indexOfAttribute(NULL, "type");
@@ -1442,16 +1442,16 @@
                             "A 'type' attribute is required for <bag>\n");
                     hasErrors = localHasErrors = true;
                 }
-            } else if (strcmp16(block.getElementName(&len), style16.string()) == 0) {
+            } else if (strcmp16(block.getElementName(&len), style16.c_str()) == 0) {
                 curTag = &style16;
                 curType = style16;
                 curIsBag = true;
-            } else if (strcmp16(block.getElementName(&len), plurals16.string()) == 0) {
+            } else if (strcmp16(block.getElementName(&len), plurals16.c_str()) == 0) {
                 curTag = &plurals16;
                 curType = plurals16;
                 curIsBag = true;
                 curIsPseudolocalizable = fileIsTranslatable;
-            } else if (strcmp16(block.getElementName(&len), array16.string()) == 0) {
+            } else if (strcmp16(block.getElementName(&len), array16.c_str()) == 0) {
                 curTag = &array16;
                 curType = array16;
                 curIsBag = true;
@@ -1460,16 +1460,16 @@
                 if (formatIdx >= 0) {
                     String16 formatStr = String16(block.getAttributeStringValue(
                             formatIdx, &len));
-                    curFormat = parse_flags(formatStr.string(), formatStr.size(),
+                    curFormat = parse_flags(formatStr.c_str(), formatStr.size(),
                                             gFormatFlags);
                     if (curFormat == 0) {
                         SourcePos(in->getPrintableSource(), block.getLineNumber()).error(
                                 "Tag <array> 'format' attribute value \"%s\" not valid\n",
-                                String8(formatStr).string());
+                                String8(formatStr).c_str());
                         hasErrors = localHasErrors = true;
                     }
                 }
-            } else if (strcmp16(block.getElementName(&len), string_array16.string()) == 0) {
+            } else if (strcmp16(block.getElementName(&len), string_array16.c_str()) == 0) {
                 // Check whether these strings need valid formats.
                 // (simplified form of what string16 does above)
                 bool isTranslatable = false;
@@ -1480,14 +1480,14 @@
                 for (size_t i = 0; i < n; i++) {
                     size_t length;
                     const char16_t* attr = block.getAttributeName(i, &length);
-                    if (strcmp16(attr, formatted16.string()) == 0) {
+                    if (strcmp16(attr, formatted16.c_str()) == 0) {
                         const char16_t* value = block.getAttributeStringValue(i, &length);
-                        if (strcmp16(value, false16.string()) == 0) {
+                        if (strcmp16(value, false16.c_str()) == 0) {
                             curIsFormatted = false;
                         }
-                    } else if (strcmp16(attr, translatable16.string()) == 0) {
+                    } else if (strcmp16(attr, translatable16.c_str()) == 0) {
                         const char16_t* value = block.getAttributeStringValue(i, &length);
-                        if (strcmp16(value, false16.string()) == 0) {
+                        if (strcmp16(value, false16.c_str()) == 0) {
                             isTranslatable = false;
                         }
                     }
@@ -1499,7 +1499,7 @@
                 curIsBag = true;
                 curIsBagReplaceOnOverwrite = true;
                 curIsPseudolocalizable = isTranslatable && fileIsTranslatable;
-            } else if (strcmp16(block.getElementName(&len), integer_array16.string()) == 0) {
+            } else if (strcmp16(block.getElementName(&len), integer_array16.c_str()) == 0) {
                 curTag = &integer_array16;
                 curType = array16;
                 curFormat = ResTable_map::TYPE_REFERENCE|ResTable_map::TYPE_INTEGER;
@@ -1508,7 +1508,7 @@
             } else {
                 SourcePos(in->getPrintableSource(), block.getLineNumber()).error(
                         "Found tag %s where item is expected\n",
-                        String8(block.getElementName(&len)).string());
+                        String8(block.getElementName(&len)).c_str());
                 return UNKNOWN_ERROR;
             }
 
@@ -1519,7 +1519,7 @@
             } else {
                 SourcePos(in->getPrintableSource(), block.getLineNumber()).error(
                         "A 'name' attribute is required for <%s>\n",
-                        String8(*curTag).string());
+                        String8(*curTag).c_str());
                 hasErrors = localHasErrors = true;
             }
 
@@ -1560,11 +1560,11 @@
                         && code != ResXMLTree::BAD_DOCUMENT) {
 
                     if (code == ResXMLTree::START_TAG) {
-                        if (strcmp16(block.getElementName(&len), item16.string()) != 0) {
+                        if (strcmp16(block.getElementName(&len), item16.c_str()) != 0) {
                             SourcePos(in->getPrintableSource(), block.getLineNumber()).error(
                                     "Tag <%s> can not appear inside <%s>, only <item>\n",
-                                    String8(block.getElementName(&len)).string(),
-                                    String8(*curTag).string());
+                                    String8(block.getElementName(&len)).c_str(),
+                                    String8(*curTag).c_str());
                             return UNKNOWN_ERROR;
                         }
 
@@ -1647,11 +1647,11 @@
                             hasErrors = localHasErrors = true;
                         }
                     } else if (code == ResXMLTree::END_TAG) {
-                        if (strcmp16(block.getElementName(&len), curTag->string()) != 0) {
+                        if (strcmp16(block.getElementName(&len), curTag->c_str()) != 0) {
                             SourcePos(in->getPrintableSource(), block.getLineNumber()).error(
                                     "Found tag </%s> where </%s> is expected\n",
-                                    String8(block.getElementName(&len)).string(),
-                                    String8(*curTag).string());
+                                    String8(block.getElementName(&len)).c_str(),
+                                    String8(*curTag).c_str());
                             return UNKNOWN_ERROR;
                         }
                         break;
@@ -1700,9 +1700,9 @@
 
 #if 0
             if (comment.size() > 0) {
-                printf("Comment for @%s:%s/%s: %s\n", String8(myPackage).string(),
-                       String8(curType).string(), String8(ident).string(),
-                       String8(comment).string());
+                printf("Comment for @%s:%s/%s: %s\n", String8(myPackage).c_str(),
+                       String8(curType).c_str(), String8(ident).c_str(),
+                       String8(comment).c_str());
             }
 #endif
             if (!localHasErrors) {
@@ -1710,9 +1710,9 @@
             }
         }
         else if (code == ResXMLTree::END_TAG) {
-            if (strcmp16(block.getElementName(&len), resources16.string()) != 0) {
+            if (strcmp16(block.getElementName(&len), resources16.c_str()) != 0) {
                 SourcePos(in->getPrintableSource(), block.getLineNumber()).error(
-                        "Unexpected end tag %s\n", String8(block.getElementName(&len)).string());
+                        "Unexpected end tag %s\n", String8(block.getElementName(&len)).c_str());
                 return UNKNOWN_ERROR;
             }
         }
@@ -1724,7 +1724,7 @@
             }
             SourcePos(in->getPrintableSource(), block.getLineNumber()).error(
                     "Found text \"%s\" where item tag is expected\n",
-                    String8(block.getText(&len)).string());
+                    String8(block.getText(&len)).c_str());
             return UNKNOWN_ERROR;
         }
     }
@@ -1740,13 +1740,13 @@
                 const char* bundleProduct =
                         (bundle->getProduct() == NULL) ? "" : bundle->getProduct();
                 fprintf(stderr, "In resource file %s: %s\n",
-                        in->getPrintableSource().string(),
-                        curParams.toString().string());
+                        in->getPrintableSource().c_str(),
+                        curParams.toString().c_str());
 
                 fprintf(stderr, "\t%s '%s' does not match product %s.\n"
                         "\tYou may have forgotten to include a 'default' product variant"
                         " of the resource.\n",
-                        String8(p.type).string(), String8(p.ident).string(),
+                        String8(p.type).c_str(), String8(p.ident).c_str(),
                         bundleProduct[0] == 0 ? "default" : bundleProduct);
                 return UNKNOWN_ERROR;
             }
@@ -1816,7 +1816,7 @@
         AssetManager featureAssetManager;
         if (!featureAssetManager.addAssetPath(featureAfter, NULL)) {
             fprintf(stderr, "ERROR: Feature package '%s' not found.\n",
-                    featureAfter.string());
+                    featureAfter.c_str());
             return UNKNOWN_ERROR;
         }
 
@@ -1835,13 +1835,13 @@
                                   const uint32_t ident)
 {
     uint32_t rid = mAssets->getIncludedResources()
-        .identifierForName(name.string(), name.size(),
-                           type.string(), type.size(),
-                           package.string(), package.size());
+        .identifierForName(name.c_str(), name.size(),
+                           type.c_str(), type.size(),
+                           package.c_str(), package.size());
     if (rid != 0) {
         sourcePos.error("Error declaring public resource %s/%s for included package %s\n",
-                String8(type).string(), String8(name).string(),
-                String8(package).string());
+                String8(type).c_str(), String8(name).c_str(),
+                String8(package).c_str());
         return UNKNOWN_ERROR;
     }
 
@@ -1864,12 +1864,12 @@
                                  const bool overwrite)
 {
     uint32_t rid = mAssets->getIncludedResources()
-        .identifierForName(name.string(), name.size(),
-                           type.string(), type.size(),
-                           package.string(), package.size());
+        .identifierForName(name.c_str(), name.size(),
+                           type.c_str(), type.size(),
+                           package.c_str(), package.size());
     if (rid != 0) {
         sourcePos.error("Resource entry %s/%s is already defined in package %s.",
-                String8(type).string(), String8(name).string(), String8(package).string());
+                String8(type).c_str(), String8(name).c_str(), String8(package).c_str());
         return UNKNOWN_ERROR;
     }
     
@@ -1899,12 +1899,12 @@
     // Check for adding entries in other packages...  for now we do
     // nothing.  We need to do the right thing here to support skinning.
     uint32_t rid = mAssets->getIncludedResources()
-    .identifierForName(name.string(), name.size(),
-                       type.string(), type.size(),
-                       package.string(), package.size());
+    .identifierForName(name.c_str(), name.size(),
+                       type.c_str(), type.size(),
+                       package.c_str(), package.size());
     if (rid != 0) {
         sourcePos.error("Resource entry %s/%s is already defined in package %s.",
-                String8(type).string(), String8(name).string(), String8(package).string());
+                String8(type).c_str(), String8(name).c_str(), String8(package).c_str());
         return UNKNOWN_ERROR;
     }
 
@@ -1921,7 +1921,7 @@
         }
         if (!canAdd) {
             sourcePos.error("Resource does not already exist in overlay at '%s'; use <add-resource> to add.\n",
-                            String8(name).string());
+                            String8(name).c_str());
             return UNKNOWN_ERROR;
         }
     }
@@ -1959,9 +1959,9 @@
     // Check for adding entries in other packages...  for now we do
     // nothing.  We need to do the right thing here to support skinning.
     uint32_t rid = mAssets->getIncludedResources()
-        .identifierForName(name.string(), name.size(),
-                           type.string(), type.size(),
-                           package.string(), package.size());
+        .identifierForName(name.c_str(), name.size(),
+                           type.c_str(), type.size(),
+                           package.c_str(), package.size());
     if (rid != 0) {
         return NO_ERROR;
     }
@@ -1969,7 +1969,7 @@
 #if 0
     if (name == String16("left")) {
         printf("Adding bag left: file=%s, line=%d, type=%s\n",
-               sourcePos.file.striing(), sourcePos.line, String8(type).string());
+               sourcePos.file.striing(), sourcePos.line, String8(type).c_str());
     }
 #endif
     sp<Entry> e = getEntry(package, type, name, sourcePos, replace, params);
@@ -1996,9 +1996,9 @@
 {
     // First look for this in the included resources...
     uint32_t rid = mAssets->getIncludedResources()
-        .identifierForName(name.string(), name.size(),
-                           type.string(), type.size(),
-                           package.string(), package.size());
+        .identifierForName(name.c_str(), name.size(),
+                           type.c_str(), type.size(),
+                           package.c_str(), package.size());
     if (rid != 0) {
         return true;
     }
@@ -2022,9 +2022,9 @@
 {
     // First look for this in the included resources...
     uint32_t rid = mAssets->getIncludedResources()
-        .identifierForName(name.string(), name.size(),
-                           type.string(), type.size(),
-                           package.string(), package.size());
+        .identifierForName(name.c_str(), name.size(),
+                           type.c_str(), type.size(),
+                           package.c_str(), package.size());
     if (rid != 0) {
         return true;
     }
@@ -2051,7 +2051,7 @@
                                   const String16* defPackage)
 {
     String16 package, type, name;
-    if (!ResTable::expandResourceRef(ref.string(), ref.size(), &package, &type, &name,
+    if (!ResTable::expandResourceRef(ref.c_str(), ref.size(), &package, &type, &name,
                 defType, defPackage ? defPackage:&mAssetsPackage, NULL)) {
         return false;
     }
@@ -2115,17 +2115,17 @@
 
     // First look for this in the included resources...
     uint32_t rid = mAssets->getIncludedResources()
-            .identifierForName(name.string(), name.size(),
-                               attr16.string(), attr16.size(),
-                               package.string(), package.size());
+            .identifierForName(name.c_str(), name.size(),
+                               attr16.c_str(), attr16.size(),
+                               package.c_str(), package.size());
     if (rid != 0) {
-        source.error("Attribute \"%s\" has already been defined", String8(name).string());
+        source.error("Attribute \"%s\" has already been defined", String8(name).c_str());
         return false;
     }
 
     sp<ResourceTable::Entry> entry = getEntry(package, attr16, name, source, false);
     if (entry == NULL) {
-        source.error("Failed to create entry attr/%s", String8(name).string());
+        source.error("Failed to create entry attr/%s", String8(name).c_str());
         return false;
     }
 
@@ -2146,7 +2146,7 @@
                 formatItem.value != formatValue16) {
             source.error("Attribute \"%s\" already defined with incompatible format.\n"
                          "%s:%d: Original attribute defined here.",
-                         String8(name).string(), formatItem.sourcePos.file.string(),
+                         String8(name).c_str(), formatItem.sourcePos.file.c_str(),
                          formatItem.sourcePos.line);
             return false;
         }
@@ -2207,9 +2207,9 @@
     // First look for this in the included resources...
     uint32_t specFlags = 0;
     uint32_t rid = mAssets->getIncludedResources()
-        .identifierForName(name.string(), name.size(),
-                           type.string(), type.size(),
-                           package.string(), package.size(),
+        .identifierForName(name.c_str(), name.size(),
+                           type.c_str(), type.size(),
+                           package.c_str(), package.size(),
                            &specFlags);
     if (rid != 0) {
         if (onlyPublic && (specFlags & ResTable_typeSpec::SPEC_PUBLIC) == 0) {
@@ -2253,27 +2253,27 @@
     String16 package, type, name;
     bool refOnlyPublic = true;
     if (!ResTable::expandResourceRef(
-        ref.string(), ref.size(), &package, &type, &name,
+        ref.c_str(), ref.size(), &package, &type, &name,
         defType, defPackage ? defPackage:&mAssetsPackage,
         outErrorMsg, &refOnlyPublic)) {
         if (kIsDebug) {
-            printf("Expanding resource: ref=%s\n", String8(ref).string());
+            printf("Expanding resource: ref=%s\n", String8(ref).c_str());
             printf("Expanding resource: defType=%s\n",
-                    defType ? String8(*defType).string() : "NULL");
+                    defType ? String8(*defType).c_str() : "NULL");
             printf("Expanding resource: defPackage=%s\n",
-                    defPackage ? String8(*defPackage).string() : "NULL");
-            printf("Expanding resource: ref=%s\n", String8(ref).string());
+                    defPackage ? String8(*defPackage).c_str() : "NULL");
+            printf("Expanding resource: ref=%s\n", String8(ref).c_str());
             printf("Expanded resource: p=%s, t=%s, n=%s, res=0\n",
-                    String8(package).string(), String8(type).string(),
-                    String8(name).string());
+                    String8(package).c_str(), String8(type).c_str(),
+                    String8(name).c_str());
         }
         return 0;
     }
     uint32_t res = getResId(package, type, name, onlyPublic && refOnlyPublic);
     if (kIsDebug) {
         printf("Expanded resource: p=%s, t=%s, n=%s, res=%d\n",
-                String8(package).string(), String8(type).string(),
-                String8(name).string(), res);
+                String8(package).c_str(), String8(type).c_str(),
+                String8(name).c_str(), res);
     }
     if (res == 0) {
         if (outErrorMsg)
@@ -2284,7 +2284,7 @@
 
 bool ResourceTable::isValidResourceName(const String16& s)
 {
-    const char16_t* p = s.string();
+    const char16_t* p = s.c_str();
     bool first = true;
     while (*p) {
         if ((*p >= 'a' && *p <= 'z')
@@ -2315,7 +2315,7 @@
     if (style == NULL || style->size() == 0) {
         // Text is not styled so it can be any type...  let's figure it out.
         res = mAssets->getIncludedResources()
-            .stringToValue(outValue, &finalStr, str.string(), str.size(), preserveSpaces,
+            .stringToValue(outValue, &finalStr, str.c_str(), str.size(), preserveSpaces,
                             coerceType, attrID, NULL, &mAssetsPackage, this,
                            accessorCookie, attrType);
     } else {
@@ -2344,7 +2344,7 @@
             if (kIsDebug) {
                 printf("Adding to pool string style #%zu config %s: %s\n",
                         style != NULL ? style->size() : 0U,
-                        configStr.string(), String8(finalStr).string());
+                        configStr.c_str(), String8(finalStr).c_str());
             }
             if (style != NULL && style->size() > 0) {
                 outValue->data = pool->add(finalStr, *style, configTypeName, config);
@@ -2368,8 +2368,8 @@
 uint32_t ResourceTable::getCustomResource(
     const String16& package, const String16& type, const String16& name) const
 {
-    //printf("getCustomResource: %s %s %s\n", String8(package).string(),
-    //       String8(type).string(), String8(name).string());
+    //printf("getCustomResource: %s %s %s\n", String8(package).c_str(),
+    //       String8(type).c_str(), String8(name).c_str());
     sp<Package> p = mPackages.valueFor(package);
     if (p == NULL) return 0;
     sp<Type> t = p->getTypes().valueFor(type);
@@ -2400,7 +2400,7 @@
 
     if (mAssetsPackage != package) {
         mCurrentXmlPos.error("creating resource for external package %s: %s/%s.",
-                String8(package).string(), String8(type).string(), String8(name).string());
+                String8(package).c_str(), String8(type).c_str(), String8(name).c_str());
         if (package == String16("android")) {
             mCurrentXmlPos.printf("did you mean to use @+id instead of @+android:id?");
         }
@@ -2427,7 +2427,7 @@
     Res_value value;
     if (getItemValue(attrID, ResTable_map::ATTR_TYPE, &value)) {
         //printf("getAttributeType #%08x (%s): #%08x\n", attrID,
-        //       String8(getEntry(attrID)->getName()).string(), value.data);
+        //       String8(getEntry(attrID)->getName()).c_str(), value.data);
         *outType = value.data;
         return true;
     }
@@ -2481,7 +2481,7 @@
         vsnprintf(buf, sizeof(buf), fmt, ap);
         va_end(ap);
         ac->sourcePos.error("Error: %s (at '%s' with value '%s').\n",
-                            buf, ac->attr.string(), ac->value.string());
+                            buf, ac->attr.c_str(), ac->value.c_str());
     }
 }
 
@@ -2493,7 +2493,7 @@
         const size_t N = e->getBag().size();
         for (size_t i=0; i<N; i++) {
             const String16& key = e->getBag().keyAt(i);
-            if (key.size() > 0 && key.string()[0] != '^') {
+            if (key.size() > 0 && key.c_str()[0] != '^') {
                 outKeys->add(key);
             }
         }
@@ -2506,14 +2506,14 @@
     uint32_t attrID, const char16_t* name, size_t nameLen,
     Res_value* outValue)
 {
-    //printf("getAttributeEnum #%08x %s\n", attrID, String8(name, nameLen).string());
+    //printf("getAttributeEnum #%08x %s\n", attrID, String8(name, nameLen).c_str());
     String16 nameStr(name, nameLen);
     sp<const Entry> e = getEntry(attrID);
     if (e != NULL) {
         const size_t N = e->getBag().size();
         for (size_t i=0; i<N; i++) {
-            //printf("Comparing %s to %s\n", String8(name, nameLen).string(),
-            //       String8(e->getBag().keyAt(i)).string());
+            //printf("Comparing %s to %s\n", String8(name, nameLen).c_str(),
+            //       String8(e->getBag().keyAt(i)).c_str());
             if (e->getBag().keyAt(i) == nameStr) {
                 return getItemValue(attrID, e->getBag().valueAt(i).bagKeyId, outValue);
             }
@@ -2529,7 +2529,7 @@
     outValue->dataType = Res_value::TYPE_INT_HEX;
     outValue->data = 0;
 
-    //printf("getAttributeFlags #%08x %s\n", attrID, String8(name, nameLen).string());
+    //printf("getAttributeFlags #%08x %s\n", attrID, String8(name, nameLen).c_str());
     String16 nameStr(name, nameLen);
     sp<const Entry> e = getEntry(attrID);
     if (e != NULL) {
@@ -2546,8 +2546,8 @@
             String16 nameStr(start, pos-start);
             size_t i;
             for (i=0; i<N; i++) {
-                //printf("Comparing \"%s\" to \"%s\"\n", String8(nameStr).string(),
-                //       String8(e->getBag().keyAt(i)).string());
+                //printf("Comparing \"%s\" to \"%s\"\n", String8(nameStr).c_str(),
+                //       String8(e->getBag().keyAt(i)).c_str());
                 if (e->getBag().keyAt(i) == nameStr) {
                     Res_value val;
                     bool got = getItemValue(attrID, e->getBag().valueAt(i).bagKeyId, &val);
@@ -2753,7 +2753,7 @@
                         if (mHasDefaultLocalization.find(c->getName())
                                 == mHasDefaultLocalization.end()) {
                             // printf("Skip symbol [%08x] %s\n", rid,
-                            //          String8(c->getName()).string());
+                            //          String8(c->getName()).c_str());
                             continue;
                         }
                     }
@@ -2763,7 +2763,7 @@
                     String16 comment(c->getComment());
                     typeSymbols->appendComment(String8(c->getName()), comment, c->getPos());
                     //printf("Type symbol [%08x] %s comment: %s\n", rid,
-                    //        String8(c->getName()).string(), String8(comment).string());
+                    //        String8(c->getName()).c_str(), String8(comment).c_str());
                     comment = c->getTypeComment();
                     typeSymbols->appendTypeComment(String8(c->getName()), comment);
                 }
@@ -2809,10 +2809,10 @@
         // Look for strings with no default localization
         if (configSrcMap.count(defaultLocale) == 0) {
             SourcePos().warning("string '%s' has no default translation.",
-                    String8(nameIter.first).string());
+                    String8(nameIter.first).c_str());
             if (mBundle->getVerbose()) {
                 for (const auto& locale : configSrcMap) {
-                    locale.second.printf("locale %s found", locale.first.string());
+                    locale.second.printf("locale %s found", locale.first.c_str());
                 }
             }
             // !!! TODO: throw an error here in some circumstances
@@ -2820,7 +2820,7 @@
 
         // Check that all requested localizations are present for this string
         if (mBundle->getConfigurations().size() > 0 && mBundle->getRequireLocalization()) {
-            const char* allConfigs = mBundle->getConfigurations().string();
+            const char* allConfigs = mBundle->getConfigurations().c_str();
             const char* start = allConfigs;
             const char* comma;
 
@@ -2847,7 +2847,7 @@
                         // requiring a specific regional localization [e.g. de_DE] but there is an
                         // available string in the generic language localization [e.g. de];
                         // consider that string to have fulfilled the localization requirement.
-                        String8 region(config.string(), 2);
+                        String8 region(config.c_str(), 2);
                         if (configSrcMap.find(region) == configSrcMap.end() &&
                                 configSrcMap.count(defaultLocale) == 0) {
                             missingConfigs.insert(config);
@@ -2859,12 +2859,12 @@
             if (!missingConfigs.empty()) {
                 String8 configStr;
                 for (const auto& iter : missingConfigs) {
-                    configStr.appendFormat(" %s", iter.string());
+                    configStr.appendFormat(" %s", iter.c_str());
                 }
                 SourcePos().warning("string '%s' is missing %u required localizations:%s",
-                        String8(nameIter.first).string(),
+                        String8(nameIter.first).c_str(),
                         (unsigned int)missingConfigs.size(),
-                        configStr.string());
+                        configStr.c_str());
             }
         }
     }
@@ -3021,7 +3021,7 @@
         header->header.type = htods(RES_TABLE_PACKAGE_TYPE);
         header->header.headerSize = htods(sizeof(*header));
         header->id = htodl(static_cast<uint32_t>(p->getAssignedId()));
-        strcpy16_htod(header->name, p->getName().string());
+        strcpy16_htod(header->name, p->getName().c_str());
 
         // Write the string blocks.
         const size_t typeStringsStart = data->getSize();
@@ -3061,7 +3061,7 @@
             sp<Type> t = p->getTypes().valueFor(typeName);
             LOG_ALWAYS_FATAL_IF(t == NULL && typeName != String16("<empty>"),
                                 "Type name %s not found",
-                                String8(typeName).string());
+                                String8(typeName).c_str());
             if (t == NULL) {
                 continue;
             }
@@ -3260,7 +3260,7 @@
                         sp<ConfigList> c = t->getOrderedConfigs().itemAt(i);
                         if (c != NULL) {
                             fprintf(stderr, "%s: no entries written for %s/%s (0x%08zx)\n", log_prefix,
-                                    String8(typeName).string(), String8(c->getName()).string(),
+                                    String8(typeName).c_str(), String8(c->getName()).c_str(),
                                     Res_MAKEID(p->getAssignedId() - 1, ti, i));
                         }
                         missing_entry = true;
@@ -3359,7 +3359,7 @@
             sp<Package> libPackage = libs[i];
             if (kIsDebug) {
                 fprintf(stderr, "  Entry %s -> 0x%02x\n",
-                        String8(libPackage->getName()).string(),
+                        String8(libPackage->getName()).c_str(),
                         (uint8_t)libPackage->getAssignedId());
             }
 
@@ -3367,7 +3367,7 @@
                     entryStart, sizeof(ResTable_lib_entry));
             memset(entry, 0, sizeof(*entry));
             entry->packageId = htodl(libPackage->getAssignedId());
-            strcpy16_htod(entry->packageName, libPackage->getName().string());
+            strcpy16_htod(entry->packageName, libPackage->getName().c_str());
         }
     }
     return NO_ERROR;
@@ -3435,13 +3435,13 @@
                         const SourcePos& pos = c->getEntries().valueAt(k)->getPos();
                         if (pos.file != "") {
                             fprintf(fp,"  <!-- Declared at %s:%d -->\n",
-                                    pos.file.string(), pos.line);
+                                    pos.file.c_str(), pos.line);
                         }
                     }
                 }
                 fprintf(fp, "  <public type=\"%s\" name=\"%s\" id=\"0x%08x\" />\n",
-                        String8(t->getName()).string(),
-                        String8(c->getName()).string(),
+                        String8(t->getName()).c_str(),
+                        String8(c->getName()).c_str(),
                         getResId(pkg, t, c->getEntryIndex()));
             }
         }
@@ -3501,8 +3501,8 @@
     }
     sourcePos.error("Resource entry %s is already defined as a single item.\n"
                     "%s:%d: Originally defined here.\n",
-                    String8(mName).string(),
-                    mItem.sourcePos.file.string(), mItem.sourcePos.line);
+                    String8(mName).c_str(),
+                    mItem.sourcePos.file.c_str(), mItem.sourcePos.line);
     return UNKNOWN_ERROR;
 }
 
@@ -3517,21 +3517,21 @@
     if (mType == TYPE_BAG) {
         if (mBag.size() == 0) {
             sourcePos.error("Resource entry %s is already defined as a bag.",
-                    String8(mName).string());
+                    String8(mName).c_str());
         } else {
             const Item& item(mBag.valueAt(0));
             sourcePos.error("Resource entry %s is already defined as a bag.\n"
                             "%s:%d: Originally defined here.\n",
-                            String8(mName).string(),
-                            item.sourcePos.file.string(), item.sourcePos.line);
+                            String8(mName).c_str(),
+                            item.sourcePos.file.c_str(), item.sourcePos.line);
         }
         return UNKNOWN_ERROR;
     }
     if ( (mType != TYPE_UNKNOWN) && (overwrite == false) ) {
         sourcePos.error("Resource entry %s is already defined.\n"
                         "%s:%d: Originally defined here.\n",
-                        String8(mName).string(),
-                        mItem.sourcePos.file.string(), mItem.sourcePos.line);
+                        String8(mName).c_str(),
+                        mItem.sourcePos.file.c_str(), mItem.sourcePos.line);
         return UNKNOWN_ERROR;
     }
 
@@ -3562,12 +3562,12 @@
             const Item& item(mBag.valueAt(origKey));
             sourcePos.error("Resource entry %s already has bag item %s.\n"
                     "%s:%d: Originally defined here.\n",
-                    String8(mName).string(), String8(key).string(),
-                    item.sourcePos.file.string(), item.sourcePos.line);
+                    String8(mName).c_str(), String8(key).c_str(),
+                    item.sourcePos.file.c_str(), item.sourcePos.line);
             return UNKNOWN_ERROR;
         }
         //printf("Replacing %s with %s\n",
-        //       String8(mBag.valueFor(key).value).string(), String8(value).string());
+        //       String8(mBag.valueFor(key).value).c_str(), String8(value).c_str());
         mBag.replaceValueFor(key, item);
     }
 
@@ -3611,8 +3611,8 @@
                 String16 value("false");
                 if (kIsDebug) {
                     fprintf(stderr, "Generating %s:id/%s\n",
-                            String8(package).string(),
-                            String8(key).string());
+                            String8(package).c_str(),
+                            String8(key).c_str());
                 }
                 status_t err = table->addEntry(SourcePos(String8("<generated>"), 0), package,
                                                id16, key, value);
@@ -3624,10 +3624,10 @@
 
 #if 1
 //             fprintf(stderr, "ERROR: Bag attribute '%s' has not been defined.\n",
-//                     String8(key).string());
+//                     String8(key).c_str());
 //             const Item& item(mBag.valueAt(i));
 //             fprintf(stderr, "Referenced from file %s line %d\n",
-//                     item.sourcePos.file.string(), item.sourcePos.line);
+//                     item.sourcePos.file.c_str(), item.sourcePos.line);
 //             return UNKNOWN_ERROR;
 #else
             char numberStr[16];
@@ -3660,7 +3660,7 @@
             mParentId = table->getResId(mParent, &style16, NULL, &errorMsg);
             if (mParentId == 0) {
                 mPos.error("Error retrieving parent for item: %s '%s'.\n",
-                        errorMsg, String8(mParent).string());
+                        errorMsg, String8(mParent).c_str());
                 hasErrors = true;
             }
         }
@@ -3670,11 +3670,11 @@
             Item& it = mBag.editValueAt(i);
             it.bagKeyId = table->getResId(key,
                     it.isId ? &id16 : &attr16, NULL, &errorMsg);
-            //printf("Bag key of %s: #%08x\n", String8(key).string(), it.bagKeyId);
+            //printf("Bag key of %s: #%08x\n", String8(key).c_str(), it.bagKeyId);
             if (it.bagKeyId == 0) {
                 it.sourcePos.error("Error: %s: %s '%s'.\n", errorMsg,
-                        String8(it.isId ? id16 : attr16).string(),
-                        String8(key).string());
+                        String8(it.isId ? id16 : attr16).c_str(),
+                        String8(key).c_str());
                 hasErrors = true;
             }
         }
@@ -3709,7 +3709,7 @@
         }
     } else {
         mPos.error("Error: entry %s is not a single item or a bag.\n",
-                   String8(mName).string());
+                   String8(mName).c_str());
         return UNKNOWN_ERROR;
     }
     return NO_ERROR;
@@ -3732,7 +3732,7 @@
         }
     } else {
         mPos.error("Error: entry %s is not a single item or a bag.\n",
-                   String8(mName).string());
+                   String8(mName).c_str());
         return UNKNOWN_ERROR;
     }
     return NO_ERROR;
@@ -3768,7 +3768,7 @@
         par.data = htodl(it.parsedValue.data);
         #if 0
         printf("Writing item (%s): type=%d, data=0x%x, res0=0x%x\n",
-               String8(mName).string(), it.parsedValue.dataType,
+               String8(mName).c_str(), it.parsedValue.dataType,
                it.parsedValue.data, par.res0);
         #endif
         err = data->writeData(&par, it.parsedValue.size);
@@ -3852,7 +3852,7 @@
     int32_t entryIdx = Res_GETENTRY(ident);
     if (entryIdx < 0) {
         sourcePos.error("Public resource %s/%s has an invalid 0 identifier (0x%08x).\n",
-                String8(mName).string(), String8(name).string(), ident);
+                String8(mName).c_str(), String8(name).c_str(), ident);
         return UNKNOWN_ERROR;
     }
     #endif
@@ -3863,7 +3863,7 @@
         if (mPublicIndex > 0 && mPublicIndex != typeIdx) {
             sourcePos.error("Public resource %s/%s has conflicting type codes for its"
                     " public identifiers (0x%x vs 0x%x).\n",
-                    String8(mName).string(), String8(name).string(),
+                    String8(mName).c_str(), String8(name).c_str(),
                     mPublicIndex, typeIdx);
             return UNKNOWN_ERROR;
         }
@@ -3882,8 +3882,8 @@
             sourcePos.error("Public resource %s/%s has conflicting public identifiers"
                     " (0x%08x vs 0x%08x).\n"
                     "%s:%d: Originally defined here.\n",
-                    String8(mName).string(), String8(name).string(), p.ident, ident,
-                    p.sourcePos.file.string(), p.sourcePos.line);
+                    String8(mName).c_str(), String8(name).c_str(), p.ident, ident,
+                    p.sourcePos.file.c_str(), p.sourcePos.line);
             return UNKNOWN_ERROR;
         }
     }
@@ -3909,7 +3909,7 @@
         if (overlay && !autoAddOverlay && mCanAddEntries.indexOf(entry) < 0) {
             sourcePos.error("Resource at %s appears in overlay but not"
                             " in the base package; use <add-resource> to add.\n",
-                            String8(entry).string());
+                            String8(entry).c_str());
             return NULL;
         }
         c = new ConfigList(entry, sourcePos);
@@ -3931,7 +3931,7 @@
                 printf("New entry at %s:%d: imsi:%d/%d lang:%c%c cnt:%c%c "
                     "orien:%d touch:%d density:%d key:%d inp:%d nav:%d sz:%dx%d "
                     "sw%ddp w%ddp h%ddp layout:%d\n",
-                      sourcePos.file.string(), sourcePos.line,
+                      sourcePos.file.c_str(), sourcePos.line,
                       config->mcc, config->mnc,
                       config->language[0] ? config->language[0] : '-',
                       config->language[1] ? config->language[1] : '-',
@@ -3951,7 +3951,7 @@
                       config->screenLayout);
             } else {
                 printf("New entry at %s:%d: NULL config\n",
-                        sourcePos.file.string(), sourcePos.line);
+                        sourcePos.file.c_str(), sourcePos.line);
             }
         }
         e = new Entry(entry, sourcePos);
@@ -4032,11 +4032,11 @@
         const Public& p = mPublic.valueAt(j);
         int32_t idx = Res_GETENTRY(p.ident);
         //printf("Looking for entry \"%s\"/\"%s\" (0x%08x) in %d...\n",
-        //       String8(mName).string(), String8(name).string(), p.ident, N);
+        //       String8(mName).c_str(), String8(name).c_str(), p.ident, N);
         bool found = false;
         for (i=0; i<N; i++) {
             sp<ConfigList> e = origOrder.itemAt(i);
-            //printf("#%d: \"%s\"\n", i, String8(e->getName()).string());
+            //printf("#%d: \"%s\"\n", i, String8(e->getName()).c_str());
             if (e->getName() == name) {
                 if (idx >= (int32_t)mOrderedConfigs.size()) {
                     mOrderedConfigs.resize(idx + 1);
@@ -4056,10 +4056,10 @@
                     p.sourcePos.error("Multiple entry names declared for public entry"
                             " identifier 0x%x in type %s (%s vs %s).\n"
                             "%s:%d: Originally defined here.",
-                            idx+1, String8(mName).string(),
-                            String8(oe->getName()).string(),
-                            String8(name).string(),
-                            oe->getPublicSourcePos().file.string(),
+                            idx+1, String8(mName).c_str(),
+                            String8(oe->getName()).c_str(),
+                            String8(name).c_str(),
+                            oe->getPublicSourcePos().file.c_str(),
                             oe->getPublicSourcePos().line);
                     hasError = true;
                 }
@@ -4068,7 +4068,7 @@
 
         if (!found) {
             p.sourcePos.error("Public symbol %s/%s declared here is not defined.",
-                    String8(mName).string(), String8(name).string());
+                    String8(mName).c_str(), String8(name).c_str());
             hasError = true;
         }
     }
@@ -4189,9 +4189,9 @@
                 t->getFirstPublicSourcePos().error("Multiple type names declared for public type"
                         " identifier 0x%x (%s vs %s).\n"
                         "%s:%d: Originally defined here.",
-                        idx, String8(ot->getName()).string(),
-                        String8(t->getName()).string(),
-                        ot->getFirstPublicSourcePos().file.string(),
+                        idx, String8(ot->getName()).c_str(),
+                        String8(t->getName()).c_str(),
+                        ot->getFirstPublicSourcePos().file.c_str(),
                         ot->getFirstPublicSourcePos().line);
                 return UNKNOWN_ERROR;
             }
@@ -4399,8 +4399,8 @@
         const Item& it = e->getBag().valueAt(i);
         if (it.bagKeyId == 0) {
             fprintf(stderr, "warning: ID not yet assigned to '%s' in bag '%s'\n",
-                    String8(e->getName()).string(),
-                    String8(e->getBag().keyAt(i)).string());
+                    String8(e->getName()).c_str(),
+                    String8(e->getBag().keyAt(i)).c_str());
         }
         if (it.bagKeyId == attrID) {
             return &it;
@@ -4427,8 +4427,8 @@
                 }
             }
             fprintf(stderr, "warning: Circular reference detected in key '%s' of bag '%s'\n",
-                    String8(e->getName()).string(),
-                    String8(e->getBag().keyAt(i)).string());
+                    String8(e->getName()).c_str(),
+                    String8(e->getBag().keyAt(i)).c_str());
             return false;
         }
         item->evaluating = true;
@@ -4436,7 +4436,7 @@
         if (kIsDebug) {
             if (res) {
                 printf("getItemValue of #%08x[#%08x] (%s): type=#%08x, data=#%08x\n",
-                       resID, attrID, String8(getEntry(resID)->getName()).string(),
+                       resID, attrID, String8(getEntry(resID)->getName()).c_str(),
                        outValue->dataType, outValue->data);
             } else {
                 printf("getItemValue of #%08x[#%08x]: failed\n",
@@ -4713,10 +4713,10 @@
                         entriesToAdd[i].value->getPos()
                                 .printf("using v%d attributes; synthesizing resource %s:%s/%s for configuration %s.",
                                         entriesToAdd[i].key.sdkVersion,
-                                        String8(p->getName()).string(),
-                                        String8(t->getName()).string(),
-                                        String8(entriesToAdd[i].value->getName()).string(),
-                                        entriesToAdd[i].key.toString().string());
+                                        String8(p->getName()).c_str(),
+                                        String8(t->getName()).c_str(),
+                                        String8(entriesToAdd[i].value->getName()).c_str(),
+                                        entriesToAdd[i].key.toString().c_str());
                     }
 
                     sp<Entry> newEntry = t->getEntry(c->getName(),
@@ -4801,8 +4801,8 @@
     sp<AaptFile> newFile = new AaptFile(target->getSourceFile(),
             AaptGroupEntry(newConfig), target->getResourceType());
     String8 resPath = String8::format("res/%s/%s.xml",
-            newFile->getGroupEntry().toDirName(target->getResourceType()).string(),
-            String8(resourceName).string());
+            newFile->getGroupEntry().toDirName(target->getResourceType()).c_str(),
+            String8(resourceName).c_str());
     resPath.convertToResPath();
 
     // Add a resource table entry.
@@ -4893,10 +4893,10 @@
                 if (bundle->getVerbose()) {
                     SourcePos(node->getFilename(), node->getStartLineNumber()).printf(
                             "removing attribute %s%s%s from <%s>",
-                            String8(attr.ns).string(),
+                            String8(attr.ns).c_str(),
                             (attr.ns.size() == 0 ? "" : ":"),
-                            String8(attr.name).string(),
-                            String8(node->getElementName()).string());
+                            String8(attr.name).c_str(),
+                            String8(node->getElementName()).c_str());
                 }
                 node->removeAttribute(i);
                 i--;
@@ -4925,8 +4925,8 @@
         sp<AaptFile> newFile = new AaptFile(target->getSourceFile(),
                 AaptGroupEntry(newConfig), target->getResourceType());
         String8 resPath = String8::format("res/%s/%s.xml",
-                newFile->getGroupEntry().toDirName(target->getResourceType()).string(),
-                String8(resourceName).string());
+                newFile->getGroupEntry().toDirName(target->getResourceType()).c_str(),
+                String8(resourceName).c_str());
         resPath.convertToResPath();
 
         // Add a resource table entry.
@@ -4934,10 +4934,10 @@
             SourcePos(target->getSourceFile(), -1).printf(
                     "using v%d attributes; synthesizing resource %s:%s/%s for configuration %s.",
                     newConfig.sdkVersion,
-                    mAssets->getPackage().string(),
-                    newFile->getResourceType().string(),
-                    String8(resourceName).string(),
-                    newConfig.toString().string());
+                    mAssets->getPackage().c_str(),
+                    newFile->getResourceType().c_str(),
+                    String8(resourceName).c_str(),
+                    newConfig.toString().c_str());
         }
 
         addEntry(SourcePos(),
@@ -5114,8 +5114,8 @@
         sp<XMLNode> nestedRoot = findOnlyChildElement(child);
         if (nestedRoot == NULL) {
             source.error("<%s:%s> must have exactly one child element",
-                         String8(child->getElementNamespace()).string(),
-                         String8(child->getElementName()).string());
+                         String8(child->getElementNamespace()).c_str(),
+                         String8(child->getElementName()).c_str());
             return UNKNOWN_ERROR;
         }
 
@@ -5130,7 +5130,7 @@
         // Parse the attribute name.
         const char* errorMsg = NULL;
         String16 attrPackage, attrType, attrName;
-        bool result = ResTable::expandResourceRef(attr->string.string(),
+        bool result = ResTable::expandResourceRef(attr->string.c_str(),
                                                   attr->string.size(),
                                                   &attrPackage, &attrType, &attrName,
                                                   &kAttr16, &kAssetPackage16,
@@ -5156,11 +5156,11 @@
             // This child element will be extracted into its own resource file.
             // Generate a name and path for it from its parent.
             nestedResourceName = String8::format("%s_%d",
-                        String8(resourceName).string(), suffix++);
+                        String8(resourceName).c_str(), suffix++);
             nestedResourcePath = String8::format("res/%s/%s.xml",
                         target->getGroupEntry().toDirName(target->getResourceType())
-                                               .string(),
-                        nestedResourceName.string());
+                                               .c_str(),
+                        nestedResourceName.c_str());
 
             // Lookup or create the entry for this name.
             sp<Entry> entry = getEntry(kAssetPackage16,
@@ -5187,20 +5187,20 @@
 
         if (bundle->getVerbose()) {
             source.printf("generating nested resource %s:%s/%s",
-                    mAssets->getPackage().string(), target->getResourceType().string(),
-                    nestedResourceName.string());
+                    mAssets->getPackage().c_str(), target->getResourceType().c_str(),
+                    nestedResourceName.c_str());
         }
 
         // Build the attribute reference and assign it to the parent.
         String16 nestedResourceRef = String16(String8::format("@%s:%s/%s",
-                    mAssets->getPackage().string(), target->getResourceType().string(),
-                    nestedResourceName.string()));
+                    mAssets->getPackage().c_str(), target->getResourceType().c_str(),
+                    nestedResourceName.c_str()));
 
         String16 attrNs = buildNamespace(attrPackage);
         if (parent->getAttribute(attrNs, attrName) != NULL) {
             SourcePos(parent->getFilename(), parent->getStartLineNumber())
                     .error("parent of nested resource already defines attribute '%s:%s'",
-                           String8(attrPackage).string(), String8(attrName).string());
+                           String8(attrPackage).c_str(), String8(attrName).c_str());
             return UNKNOWN_ERROR;
         }
 
diff --git a/tools/aapt/SourcePos.cpp b/tools/aapt/SourcePos.cpp
index 3864320..e130286 100644
--- a/tools/aapt/SourcePos.cpp
+++ b/tools/aapt/SourcePos.cpp
@@ -80,12 +80,12 @@
     
     if (!this->file.isEmpty()) {
         if (this->line >= 0) {
-            fprintf(to, "%s:%d: %s%s\n", this->file.string(), this->line, type, this->error.string());
+            fprintf(to, "%s:%d: %s%s\n", this->file.c_str(), this->line, type, this->error.c_str());
         } else {
-            fprintf(to, "%s: %s%s\n", this->file.string(), type, this->error.string());
+            fprintf(to, "%s: %s%s\n", this->file.c_str(), type, this->error.c_str());
         }
     } else {
-        fprintf(to, "%s%s\n", type, this->error.string());
+        fprintf(to, "%s%s\n", type, this->error.c_str());
     }
 }
 
diff --git a/tools/aapt/StringPool.cpp b/tools/aapt/StringPool.cpp
index 6cacd32..8d02683 100644
--- a/tools/aapt/StringPool.cpp
+++ b/tools/aapt/StringPool.cpp
@@ -67,7 +67,7 @@
     const size_t NS = pool->size();
     for (size_t s=0; s<NS; s++) {
         auto str = pool->string8ObjectAt(s);
-        printf("String #" ZD ": %s\n", (ZD_TYPE) s, (str.has_value() ? str->string() : ""));
+        printf("String #" ZD ": %s\n", (ZD_TYPE) s, (str.has_value() ? str->c_str() : ""));
     }
 }
 
@@ -139,7 +139,7 @@
     if (eidx < 0) {
         eidx = mEntries.add(entry(value));
         if (eidx < 0) {
-            fprintf(stderr, "Failure adding string %s\n", String8(value).string());
+            fprintf(stderr, "Failure adding string %s\n", String8(value).c_str());
             return eidx;
         }
     }
@@ -148,7 +148,7 @@
         entry& ent = mEntries.editItemAt(eidx);
         if (kIsDebug) {
             printf("*** adding config type name %s, was %s\n",
-                    configTypeName->string(), ent.configTypeName.string());
+                    configTypeName->c_str(), ent.configTypeName.c_str());
         }
         if (ent.configTypeName.size() <= 0) {
             ent.configTypeName = *configTypeName;
@@ -166,7 +166,7 @@
             if (cmp >= 0) {
                 if (cmp > 0) {
                     if (kIsDebug) {
-                        printf("*** inserting config: %s\n", config->toString().string());
+                        printf("*** inserting config: %s\n", config->toString().c_str());
                     }
                     ent.configs.insertAt(*config, addPos);
                 }
@@ -175,7 +175,7 @@
         }
         if (addPos >= ent.configs.size()) {
             if (kIsDebug) {
-                printf("*** adding config: %s\n", config->toString().string());
+                printf("*** adding config: %s\n", config->toString().c_str());
             }
             ent.configs.add(*config);
         }
@@ -195,7 +195,7 @@
 
     if (kIsDebug) {
         printf("Adding string %s to pool: pos=%zd eidx=%zd vidx=%zd\n",
-                String8(value).string(), pos, eidx, vidx);
+                String8(value).c_str(), pos, eidx, vidx);
     }
 
     return pos;
@@ -286,13 +286,13 @@
 
     for (size_t i=0; i<N; i++) {
         printf("#%d was %d: %s\n", i, newPosToOriginalPos[i],
-                mEntries[mEntryArray[newPosToOriginalPos[i]]].makeConfigsString().string());
+                mEntries[mEntryArray[newPosToOriginalPos[i]]].makeConfigsString().c_str());
         entries.add(mEntries[mEntryArray[i]]);
     }
 
     for (size_t i=0; i<entries.size(); i++) {
         printf("Sorted config #%d: %s\n", i,
-                entries[i].makeConfigsString().string());
+                entries[i].makeConfigsString().c_str());
     }
 #endif
 
@@ -363,8 +363,8 @@
     printf("FINAL SORTED STRING CONFIGS:\n");
     for (size_t i=0; i<mEntries.size(); i++) {
         const entry& ent = mEntries[i];
-        printf("#" ZD " %s: %s\n", (ZD_TYPE)i, ent.makeConfigsString().string(),
-                String8(ent.value).string());
+        printf("#" ZD " %s: %s\n", (ZD_TYPE)i, ent.makeConfigsString().c_str(),
+                String8(ent.value).c_str());
     }
 #endif
 }
@@ -415,7 +415,7 @@
             ssize_t idx = add(span.name, true);
             if (idx < 0) {
                 fprintf(stderr, "Error adding span for style tag '%s'\n",
-                        String8(span.name).string());
+                        String8(span.name).c_str());
                 return idx;
             }
             span.span.name.index = (uint32_t)idx;
@@ -571,7 +571,7 @@
         if (kIsDebug) {
             printf("Writing entry #%zu: \"%s\" ent=%zu off=%zu\n",
                     i,
-                    String8(ent.value).string(),
+                    String8(ent.value).c_str(),
                     mEntryArray[i],
                     ent.offset);
         }
@@ -591,8 +591,8 @@
     const Vector<size_t>* indices = offsetsForString(val);
     ssize_t res = indices != NULL && indices->size() > 0 ? indices->itemAt(0) : -1;
     if (kIsDebug) {
-        printf("Offset for string %s: %zd (%s)\n", String8(val).string(), res,
-                res >= 0 ? String8(mEntries[mEntryArray[res]].value).string() : String8());
+        printf("Offset for string %s: %zd (%s)\n", String8(val).c_str(), res,
+                res >= 0 ? String8(mEntries[mEntryArray[res]].value).c_str() : String8());
     }
     return res;
 }
diff --git a/tools/aapt/Symbol.h b/tools/aapt/Symbol.h
index e157541..de1d60c 100644
--- a/tools/aapt/Symbol.h
+++ b/tools/aapt/Symbol.h
@@ -68,9 +68,9 @@
 
 android::String8 Symbol::toString() const {
     return android::String8::format("%s:%s/%s (0x%08x)",
-            android::String8(package).string(),
-            android::String8(type).string(),
-            android::String8(name).string(),
+            android::String8(package).c_str(),
+            android::String8(type).c_str(),
+            android::String8(name).c_str(),
             (int) id);
 }
 
diff --git a/tools/aapt/XMLNode.cpp b/tools/aapt/XMLNode.cpp
index 69392d6..e270a73 100644
--- a/tools/aapt/XMLNode.cpp
+++ b/tools/aapt/XMLNode.cpp
@@ -66,14 +66,14 @@
 
 String16 getNamespaceResourcePackage(const String16& appPackage, const String16& namespaceUri, bool* outIsPublic)
 {
-    //printf("%s starts with %s?\n", String8(namespaceUri).string(),
-    //       String8(RESOURCES_PREFIX).string());
+    //printf("%s starts with %s?\n", String8(namespaceUri).c_str(),
+    //       String8(RESOURCES_PREFIX).c_str());
     size_t prefixSize;
     bool isPublic = true;
     if(namespaceUri.startsWith(RESOURCES_PREFIX_AUTO_PACKAGE)) {
         if (kIsDebug) {
-            printf("Using default application package: %s -> %s\n", String8(namespaceUri).string(),
-                   String8(appPackage).string());
+            printf("Using default application package: %s -> %s\n", String8(namespaceUri).c_str(),
+                   String8(appPackage).c_str());
         }
         isPublic = true;
         return appPackage;
@@ -88,7 +88,7 @@
     }
 
     //printf("YES!\n");
-    //printf("namespace: %s\n", String8(String16(namespaceUri, namespaceUri.size()-prefixSize, prefixSize)).string());
+    //printf("namespace: %s\n", String8(String16(namespaceUri, namespaceUri.size()-prefixSize, prefixSize)).c_str());
     if (outIsPublic) *outIsPublic = isPublic;
     return String16(namespaceUri, namespaceUri.size()-prefixSize, prefixSize);
 }
@@ -97,7 +97,7 @@
                                ResXMLTree* inXml,
                                const String16& str16)
 {
-    const char16_t* str = str16.string();
+    const char16_t* str = str16.c_str();
     const char16_t* p = str;
     const char16_t* end = str + str16.size();
 
@@ -223,7 +223,7 @@
             String16 text(inXml->getText(&len));
             if (firstTime && text.size() > 0) {
                 firstTime = false;
-                if (text.string()[0] == '@') {
+                if (text.c_str()[0] == '@') {
                     // If this is a resource reference, don't do the pseudoloc.
                     pseudolocalize = NO_PSEUDOLOCALIZATION;
                     pseudo.setMethod(pseudolocalize);
@@ -263,7 +263,7 @@
                 {
                     SourcePos(String8(fileName), inXml->getLineNumber()).error(
                             "Found unsupported XLIFF tag <%s>\n",
-                            element8.string());
+                            element8.c_str());
                     return UNKNOWN_ERROR;
                 }
 moveon:
@@ -272,14 +272,14 @@
 
             if (outSpans == NULL) {
                 SourcePos(String8(fileName), inXml->getLineNumber()).error(
-                        "Found style tag <%s> where styles are not allowed\n", element8.string());
+                        "Found style tag <%s> where styles are not allowed\n", element8.c_str());
                 return UNKNOWN_ERROR;
             }
 
-            if (!ResTable::collectString(outString, curString.string(),
+            if (!ResTable::collectString(outString, curString.c_str(),
                                          curString.size(), false, &errorMsg, true)) {
                 SourcePos(String8(fileName), inXml->getLineNumber()).error("%s (in %s)\n",
-                        errorMsg, String8(curString).string());
+                        errorMsg, String8(curString).c_str());
                 return UNKNOWN_ERROR;
             }
             rawString.append(curString);
@@ -295,7 +295,7 @@
                 str = inXml->getAttributeStringValue(ai, &len);
                 span.name.append(str, len);
             }
-            //printf("Span: %s\n", String8(span.name).string());
+            //printf("Span: %s\n", String8(span.name).c_str());
             span.span.firstChar = span.span.lastChar = outString->size();
             spanStack.push(span);
 
@@ -311,21 +311,21 @@
                 xliffDepth--;
                 continue;
             }
-            if (!ResTable::collectString(outString, curString.string(),
+            if (!ResTable::collectString(outString, curString.c_str(),
                                          curString.size(), false, &errorMsg, true)) {
                 SourcePos(String8(fileName), inXml->getLineNumber()).error("%s (in %s)\n",
-                        errorMsg, String8(curString).string());
+                        errorMsg, String8(curString).c_str());
                 return UNKNOWN_ERROR;
             }
             rawString.append(curString);
             curString = String16();
 
             if (spanStack.size() == 0) {
-                if (strcmp16(inXml->getElementName(&len), endTag.string()) != 0) {
+                if (strcmp16(inXml->getElementName(&len), endTag.c_str()) != 0) {
                     SourcePos(String8(fileName), inXml->getLineNumber()).error(
                             "Found tag %s where <%s> close is expected\n",
-                            String8(inXml->getElementName(&len)).string(),
-                            String8(endTag).string());
+                            String8(inXml->getElementName(&len)).c_str(),
+                            String8(endTag).c_str());
                     return UNKNOWN_ERROR;
                 }
                 break;
@@ -334,15 +334,15 @@
             String16 spanTag;
             ssize_t semi = span.name.findFirst(';');
             if (semi >= 0) {
-                spanTag.setTo(span.name.string(), semi);
+                spanTag.setTo(span.name.c_str(), semi);
             } else {
                 spanTag.setTo(span.name);
             }
-            if (strcmp16(inXml->getElementName(&len), spanTag.string()) != 0) {
+            if (strcmp16(inXml->getElementName(&len), spanTag.c_str()) != 0) {
                 SourcePos(String8(fileName), inXml->getLineNumber()).error(
                         "Found close tag %s where close tag %s is expected\n",
-                        String8(inXml->getElementName(&len)).string(),
-                        String8(spanTag).string());
+                        String8(inXml->getElementName(&len)).c_str(),
+                        String8(spanTag).c_str());
                 return UNKNOWN_ERROR;
             }
             bool empty = true;
@@ -363,7 +363,7 @@
             if (0 && empty) {
                 fprintf(stderr, "%s:%d: warning: empty '%s' span found in text '%s'\n",
                         fileName, inXml->getLineNumber(),
-                        String8(spanTag).string(), String8(*outString).string());
+                        String8(spanTag).c_str(), String8(*outString).c_str());
 
             }
         } else if (code == ResXMLTree::START_NAMESPACE) {
@@ -380,11 +380,11 @@
 
     if (outSpans != NULL && outSpans->size() > 0) {
         if (curString.size() > 0) {
-            if (!ResTable::collectString(outString, curString.string(),
+            if (!ResTable::collectString(outString, curString.c_str(),
                                          curString.size(), false, &errorMsg, true)) {
                 SourcePos(String8(fileName), inXml->getLineNumber()).error(
                         "%s (in %s)\n",
-                        errorMsg, String8(curString).string());
+                        errorMsg, String8(curString).c_str());
                 return UNKNOWN_ERROR;
             }
         }
@@ -450,10 +450,10 @@
             String8 elemNs = build_namespace(namespaces, ns16);
             const char16_t* com16 = block->getComment(&len);
             if (com16) {
-                printf("%s <!-- %s -->\n", prefix.string(), String8(com16).string());
+                printf("%s <!-- %s -->\n", prefix.c_str(), String8(com16).c_str());
             }
-            printf("%sE: %s%s (line=%d)\n", prefix.string(), elemNs.string(),
-                   String8(block->getElementName(&len)).string(),
+            printf("%sE: %s%s (line=%d)\n", prefix.c_str(), elemNs.c_str(),
+                   String8(block->getElementName(&len)).c_str(),
                    block->getLineNumber());
             int N = block->getAttributeCount();
             depth++;
@@ -463,11 +463,11 @@
                 ns16 = block->getAttributeNamespace(i, &len);
                 String8 ns = build_namespace(namespaces, ns16);
                 String8 name(block->getAttributeName(i, &len));
-                printf("%sA: ", prefix.string());
+                printf("%sA: ", prefix.c_str());
                 if (res) {
-                    printf("%s%s(0x%08x)", ns.string(), name.string(), res);
+                    printf("%s%s(0x%08x)", ns.c_str(), name.c_str(), res);
                 } else {
-                    printf("%s%s", ns.string(), name.string());
+                    printf("%s%s", ns.c_str(), name.c_str());
                 }
                 Res_value value;
                 block->getAttributeValue(i, &value);
@@ -480,14 +480,14 @@
                 } else if (value.dataType == Res_value::TYPE_STRING) {
                     printf("=\"%s\"",
                             ResTable::normalizeForOutput(String8(block->getAttributeStringValue(i,
-                                        &len)).string()).string());
+                                        &len)).c_str()).c_str());
                 } else {
                     printf("=(type 0x%x)0x%x", (int)value.dataType, (int)value.data);
                 }
                 const char16_t* val = block->getAttributeStringValue(i, &len);
                 if (val != NULL) {
-                    printf(" (Raw: \"%s\")", ResTable::normalizeForOutput(String8(val).string()).
-                            string());
+                    printf(" (Raw: \"%s\")", ResTable::normalizeForOutput(String8(val).c_str()).
+                            c_str());
                 }
                 printf("\n");
             }
@@ -509,8 +509,8 @@
             }
             ns.uri = String8(block->getNamespaceUri(&len));
             namespaces.push(ns);
-            printf("%sN: %s=%s\n", prefix.string(), ns.prefix.string(),
-                    ns.uri.string());
+            printf("%sN: %s=%s\n", prefix.c_str(), ns.prefix.c_str(),
+                    ns.uri.c_str());
             depth++;
         } else if (code == ResXMLTree::END_NAMESPACE) {
             if (--depth < 0) {
@@ -529,19 +529,19 @@
             if (ns.prefix != pr) {
                 prefix = make_prefix(depth);
                 printf("%s*** BAD END NS PREFIX: found=%s, expected=%s\n",
-                        prefix.string(), pr.string(), ns.prefix.string());
+                        prefix.c_str(), pr.c_str(), ns.prefix.c_str());
             }
             String8 uri = String8(block->getNamespaceUri(&len));
             if (ns.uri != uri) {
                 prefix = make_prefix(depth);
                 printf("%s *** BAD END NS URI: found=%s, expected=%s\n",
-                        prefix.string(), uri.string(), ns.uri.string());
+                        prefix.c_str(), uri.c_str(), ns.uri.c_str());
             }
             namespaces.pop();
         } else if (code == ResXMLTree::TEXT) {
             size_t len;
-            printf("%sC: \"%s\"\n", prefix.string(),
-                    ResTable::normalizeForOutput(String8(block->getText(&len)).string()).string());
+            printf("%sC: \"%s\"\n", prefix.c_str(),
+                    ResTable::normalizeForOutput(String8(block->getText(&len)).c_str()).c_str());
         }
     }
 
@@ -583,7 +583,7 @@
 sp<XMLNode> XMLNode::parse(const sp<AaptFile>& file)
 {
     char buf[16384];
-    int fd = open(file->getSourceFile().string(), O_RDONLY | O_BINARY);
+    int fd = open(file->getSourceFile().c_str(), O_RDONLY | O_BINARY);
     if (fd < 0) {
         SourcePos(file->getSourceFile(), -1).error("Unable to open file for read: %s",
                 strerror(errno));
@@ -875,9 +875,9 @@
     }
     if (kIsDebug) {
         printf("Elem %s %s=\"%s\": set res id = 0x%08x\n",
-                String8(getElementName()).string(),
-                String8(mAttributes.itemAt(attrIdx).name).string(),
-                String8(mAttributes.itemAt(attrIdx).string).string(),
+                String8(getElementName()).c_str(),
+                String8(mAttributes.itemAt(attrIdx).name).c_str(),
+                String8(mAttributes.itemAt(attrIdx).string).c_str(),
                 resId);
     }
     mAttributes.editItemAt(attrIdx).nameResId = resId;
@@ -915,7 +915,7 @@
 
 void XMLNode::removeWhitespace(bool stripAll, const char** cDataTags)
 {
-    //printf("Removing whitespace in %s\n", String8(mElementName).string());
+    //printf("Removing whitespace in %s\n", String8(mElementName).c_str());
     size_t N = mChildren.size();
     if (cDataTags) {
         String8 tag(mElementName);
@@ -931,13 +931,13 @@
         sp<XMLNode> node = mChildren.itemAt(i);
         if (node->getType() == TYPE_CDATA) {
             // This is a CDATA node...
-            const char16_t* p = node->mChars.string();
+            const char16_t* p = node->mChars.c_str();
             while (*p != 0 && *p < 128 && isspace(*p)) {
                 p++;
             }
             //printf("Space ends at %d in \"%s\"\n",
-            //       (int)(p-node->mChars.string()),
-            //       String8(node->mChars).string());
+            //       (int)(p-node->mChars.c_str()),
+            //       String8(node->mChars).c_str());
             if (*p == 0) {
                 if (stripAll) {
                     // Remove this node!
@@ -949,18 +949,18 @@
                 }
             } else {
                 // Compact leading/trailing whitespace.
-                const char16_t* e = node->mChars.string()+node->mChars.size()-1;
+                const char16_t* e = node->mChars.c_str()+node->mChars.size()-1;
                 while (e > p && *e < 128 && isspace(*e)) {
                     e--;
                 }
-                if (p > node->mChars.string()) {
+                if (p > node->mChars.c_str()) {
                     p--;
                 }
-                if (e < (node->mChars.string()+node->mChars.size()-1)) {
+                if (e < (node->mChars.c_str()+node->mChars.size()-1)) {
                     e++;
                 }
-                if (p > node->mChars.string() ||
-                    e < (node->mChars.string()+node->mChars.size()-1)) {
+                if (p > node->mChars.c_str() ||
+                    e < (node->mChars.c_str()+node->mChars.size()-1)) {
                     String16 tmp(p, e-p+1);
                     node->mChars = tmp;
                 }
@@ -986,14 +986,14 @@
             table->setCurrentXmlPos(SourcePos(mFilename, getStartLineNumber()));
             if (!assets->getIncludedResources()
                     .stringToValue(&e.value, &e.string,
-                                  e.string.string(), e.string.size(), true, true,
+                                  e.string.c_str(), e.string.size(), true, true,
                                   e.nameResId, NULL, &defPackage, table, &ac)) {
                 hasErrors = true;
             }
             if (kIsDebug) {
                 printf("Attr %s: type=0x%x, str=%s\n",
-                        String8(e.name).string(), e.value.dataType,
-                        String8(e.string).string());
+                        String8(e.name).c_str(), e.value.dataType,
+                        String8(e.string).c_str());
             }
         }
     }
@@ -1023,30 +1023,30 @@
             String16 pkg(getNamespaceResourcePackage(String16(assets->getPackage()), e.ns, &nsIsPublic));
             if (kIsDebug) {
                 printf("Elem %s %s=\"%s\": namespace(%s) %s ===> %s\n",
-                        String8(getElementName()).string(),
-                        String8(e.name).string(),
-                        String8(e.string).string(),
-                        String8(e.ns).string(),
+                        String8(getElementName()).c_str(),
+                        String8(e.name).c_str(),
+                        String8(e.string).c_str(),
+                        String8(e.ns).c_str(),
                         (nsIsPublic) ? "public" : "private",
-                        String8(pkg).string());
+                        String8(pkg).c_str());
             }
             if (pkg.size() <= 0) continue;
             uint32_t res = table != NULL
                 ? table->getResId(e.name, &attr, &pkg, &errorMsg, nsIsPublic)
                 : assets->getIncludedResources().
-                    identifierForName(e.name.string(), e.name.size(),
-                                      attr.string(), attr.size(),
-                                      pkg.string(), pkg.size());
+                    identifierForName(e.name.c_str(), e.name.size(),
+                                      attr.c_str(), attr.size(),
+                                      pkg.c_str(), pkg.size());
             if (res != 0) {
                 if (kIsDebug) {
                     printf("XML attribute name %s: resid=0x%08x\n",
-                            String8(e.name).string(), res);
+                            String8(e.name).c_str(), res);
                 }
                 setAttributeResID(i, res);
             } else {
                 SourcePos(mFilename, getStartLineNumber()).error(
                         "No resource identifier found for attribute '%s' in package '%s'\n",
-                        String8(e.name).string(), String8(pkg).string());
+                        String8(e.name).c_str(), String8(pkg).c_str());
                 hasErrors = true;
             }
         }
@@ -1137,7 +1137,7 @@
     if (kPrintStringMetrics) {
         fprintf(stderr, "**** total xml size: %zu / %zu%% strings (in %s)\n",
                 dest->getSize(), (stringPool->getSize()*100)/dest->getSize(),
-                dest->getPath().string());
+                dest->getPath().c_str());
     }
 
     return NO_ERROR;
@@ -1155,8 +1155,8 @@
         if (elemNs.size() > 0) {
             elemNs.append(":");
         }
-        printf("%s E: %s%s", prefix.string(),
-               elemNs.string(), String8(getElementName()).string());
+        printf("%s E: %s%s", prefix.c_str(),
+               elemNs.c_str(), String8(getElementName()).c_str());
         int N = mAttributes.size();
         for (i=0; i<N; i++) {
             ssize_t idx = mAttributeOrder.valueAt(i);
@@ -1171,21 +1171,21 @@
                 attrNs.append(":");
             }
             if (attr.nameResId) {
-                printf("%s%s(0x%08x)", attrNs.string(),
-                       String8(attr.name).string(), attr.nameResId);
+                printf("%s%s(0x%08x)", attrNs.c_str(),
+                       String8(attr.name).c_str(), attr.nameResId);
             } else {
-                printf("%s%s", attrNs.string(), String8(attr.name).string());
+                printf("%s%s", attrNs.c_str(), String8(attr.name).c_str());
             }
-            printf("=%s", String8(attr.string).string());
+            printf("=%s", String8(attr.string).c_str());
         }
         printf("\n");
     } else if (getType() == TYPE_NAMESPACE) {
-        printf("%s N: %s=%s\n", prefix.string(),
+        printf("%s N: %s=%s\n", prefix.c_str(),
                getNamespacePrefix().size() > 0
-                    ? String8(getNamespacePrefix()).string() : "<DEF>",
-               String8(getNamespaceUri()).string());
+                    ? String8(getNamespacePrefix()).c_str() : "<DEF>",
+               String8(getNamespaceUri()).c_str());
     } else {
-        printf("%s C: \"%s\"\n", prefix.string(), String8(getCData()).string());
+        printf("%s C: \"%s\"\n", prefix.c_str(), String8(getCData()).c_str());
     }
     int N = mChildren.size();
     for (i=0; i<N; i++) {
@@ -1258,7 +1258,7 @@
 XMLNode::characterData(void *userData, const XML_Char *s, int len)
 {
     if (kIsDebugParse) {
-        printf("CDATA: \"%s\"\n", String8(s, len).string());
+        printf("CDATA: \"%s\"\n", String8(s, len).c_str());
     }
     ParseState* st = (ParseState*)userData;
     sp<XMLNode> node = NULL;
@@ -1423,7 +1423,7 @@
                 idx = outPool->add(attr.name);
                 if (kIsDebug) {
                     printf("Adding attr %s (resid 0x%08x) to pool: idx=%zd\n",
-                            String8(attr.name).string(), id, idx);
+                            String8(attr.name).c_str(), id, idx);
                 }
                 if (id != 0) {
                     while ((ssize_t)outResIds->size() <= idx) {
@@ -1434,7 +1434,7 @@
             }
             attr.namePoolIdx = idx;
             if (kIsDebug) {
-                printf("String %s offset=0x%08zd\n", String8(attr.name).string(), idx);
+                printf("String %s offset=0x%08zd\n", String8(attr.name).c_str(), idx);
             }
         }
     }
@@ -1488,7 +1488,7 @@
         node.comment.index = htodl(
             mComment.size() > 0 ? strings.offsetForString(mComment) : -1);
         //if (mComment.size() > 0) {
-        //  printf("Flattening comment: %s\n", String8(mComment).string());
+        //  printf("Flattening comment: %s\n", String8(mComment).c_str());
         //}
     } else {
         node.comment.index = htodl((uint32_t)-1);
diff --git a/tools/aapt/pseudolocalize.cpp b/tools/aapt/pseudolocalize.cpp
index 4e8dcb1..fc2ed98 100644
--- a/tools/aapt/pseudolocalize.cpp
+++ b/tools/aapt/pseudolocalize.cpp
@@ -42,7 +42,7 @@
   size_t depth = mLastDepth;
   size_t lastpos, pos;
   const size_t length= text.size();
-  const char16_t* str = text.string();
+  const char16_t* str = text.c_str();
   bool escaped = false;
   for (lastpos = pos = 0; pos < length; pos++) {
     char16_t c = str[pos];
@@ -181,7 +181,7 @@
 
 static String16 pseudo_generate_expansion(const unsigned int length) {
     String16 result = k_expansion_string;
-    const char16_t* s = result.string();
+    const char16_t* s = result.c_str();
     if (result.size() < length) {
         result += String16(" ");
         result += pseudo_generate_expansion(length - result.size());
@@ -237,7 +237,7 @@
  */
 String16 PseudoMethodAccent::text(const String16& source)
 {
-    const char16_t* s = source.string();
+    const char16_t* s = source.c_str();
     String16 result;
     const size_t I = source.size();
     bool lastspace = true;
@@ -357,7 +357,7 @@
 
 String16 PseudoMethodBidi::text(const String16& source)
 {
-    const char16_t* s = source.string();
+    const char16_t* s = source.c_str();
     String16 result;
     bool lastspace = true;
     bool space = true;
diff --git a/tools/aapt2/Debug.cpp b/tools/aapt2/Debug.cpp
index df87889..9cfb85d 100644
--- a/tools/aapt2/Debug.cpp
+++ b/tools/aapt2/Debug.cpp
@@ -447,7 +447,7 @@
   const size_t NS = pool->size();
   for (size_t s=0; s<NS; s++) {
     auto str = pool->string8ObjectAt(s);
-    printer->Print(StringPrintf("String #%zd : %s\n", s, str.has_value() ? str->string() : ""));
+    printer->Print(StringPrintf("String #%zd : %s\n", s, str.has_value() ? str->c_str() : ""));
   }
 }
 
diff --git a/tools/aapt2/cmd/Util.cpp b/tools/aapt2/cmd/Util.cpp
index 1671e1e..a92f24b 100644
--- a/tools/aapt2/cmd/Util.cpp
+++ b/tools/aapt2/cmd/Util.cpp
@@ -215,7 +215,7 @@
   }
   std::vector<std::string> sanitized_config_names;
   for (const auto &config : constraints.configs) {
-    sanitized_config_names.push_back(MakePackageSafeName(config.toString().string()));
+    sanitized_config_names.push_back(MakePackageSafeName(config.toString().c_str()));
   }
   split_name << "config." << util::Joiner(sanitized_config_names, "_");
 
diff --git a/tools/aapt2/format/binary/BinaryResourceParser.cpp b/tools/aapt2/format/binary/BinaryResourceParser.cpp
index 75dcba5..2e20e81 100644
--- a/tools/aapt2/format/binary/BinaryResourceParser.cpp
+++ b/tools/aapt2/format/binary/BinaryResourceParser.cpp
@@ -453,7 +453,7 @@
   const size_t count = entries.size();
   for (size_t i = 0; i < count; i++) {
     table_->included_packages_[entries.valueAt(i)] =
-        android::util::Utf16ToUtf8(StringPiece16(entries.keyAt(i).string()));
+        android::util::Utf16ToUtf8(StringPiece16(entries.keyAt(i).c_str()));
   }
   return true;
 }
diff --git a/tools/split-select/Grouper_test.cpp b/tools/split-select/Grouper_test.cpp
index 7294a86..a8b78cd 100644
--- a/tools/split-select/Grouper_test.cpp
+++ b/tools/split-select/Grouper_test.cpp
@@ -179,7 +179,7 @@
             errorMessage.append("\n");
         }
     }
-    ADD_FAILURE() << errorMessage.string();
+    ADD_FAILURE() << errorMessage.c_str();
 }
 
 void GrouperTest::addSplit(Vector<SplitDescription>& splits, const char* str) {
diff --git a/tools/split-select/Main.cpp b/tools/split-select/Main.cpp
index e6966db..1e75117 100644
--- a/tools/split-select/Main.cpp
+++ b/tools/split-select/Main.cpp
@@ -99,8 +99,7 @@
         }
         masterRule = Rule::simplify(masterRule);
         fprintf(stdout, "  {\n    \"path\": \"%s\",\n    \"rules\": %s\n  }",
-                splits.keyAt(i).string(),
-                masterRule->toJson(2).string());
+                splits.keyAt(i).c_str(), masterRule->toJson(2).c_str());
     }
     fprintf(stdout, "\n]\n");
 }
@@ -158,25 +157,23 @@
         const char16_t* name = xml.getElementName(&len);
         String16 name16(name, len);
         if (name16 == kManifestTag) {
-            ssize_t idx = xml.indexOfAttribute(
-                    kAndroidNamespace.string(), kAndroidNamespace.size(),
-                    kVersionCodeAttr.string(), kVersionCodeAttr.size());
+            ssize_t idx = xml.indexOfAttribute(kAndroidNamespace.c_str(), kAndroidNamespace.size(),
+                                               kVersionCodeAttr.c_str(), kVersionCodeAttr.size());
             if (idx >= 0) {
                 outInfo.versionCode = xml.getAttributeData(idx);
             }
 
         } else if (name16 == kApplicationTag) {
-            ssize_t idx = xml.indexOfAttribute(
-                    kAndroidNamespace.string(), kAndroidNamespace.size(),
-                    kMultiArchAttr.string(), kMultiArchAttr.size());
+            ssize_t idx = xml.indexOfAttribute(kAndroidNamespace.c_str(), kAndroidNamespace.size(),
+                                               kMultiArchAttr.c_str(), kMultiArchAttr.size());
             if (idx >= 0) {
                 outInfo.multiArch = xml.getAttributeData(idx) != 0;
             }
 
         } else if (name16 == kUsesSdkTag) {
-            ssize_t idx = xml.indexOfAttribute(
-                    kAndroidNamespace.string(), kAndroidNamespace.size(),
-                    kMinSdkVersionAttr.string(), kMinSdkVersionAttr.size());
+            ssize_t idx =
+                    xml.indexOfAttribute(kAndroidNamespace.c_str(), kAndroidNamespace.size(),
+                                         kMinSdkVersionAttr.c_str(), kMinSdkVersionAttr.size());
             if (idx >= 0) {
                 uint16_t type = xml.getAttributeDataType(idx);
                 if (type >= Res_value::TYPE_FIRST_INT && type <= Res_value::TYPE_LAST_INT) {
@@ -187,10 +184,10 @@
                         fprintf(stderr, "warning: failed to retrieve android:minSdkVersion.\n");
                     } else {
                         char *endPtr;
-                        int minSdk = strtol(minSdk8->string(), &endPtr, 10);
-                        if (endPtr != minSdk8->string() + minSdk8->size()) {
+                        int minSdk = strtol(minSdk8->c_str(), &endPtr, 10);
+                        if (endPtr != minSdk8->c_str() + minSdk8->size()) {
                             fprintf(stderr, "warning: failed to parse android:minSdkVersion '%s'\n",
-                                    minSdk8->string());
+                                    minSdk8->c_str());
                         } else {
                             outInfo.minSdkVersion = minSdk;
                         }
@@ -232,7 +229,7 @@
             splits.add();
             Vector<String8> parts = AaptUtil::splitAndLowerCase(dir->getFileName(i), '-');
             if (parseAbi(parts, 0, &splits.editTop()) < 0) {
-                fprintf(stderr, "Malformed library %s\n", dir->getFileName(i).string());
+                fprintf(stderr, "Malformed library %s\n", dir->getFileName(i).c_str());
                 splits.pop();
             }
         }
@@ -291,7 +288,7 @@
             help();
             return 0;
         } else {
-            fprintf(stderr, "error: unknown argument '%s'.\n", arg.string());
+            fprintf(stderr, "error: unknown argument '%s'.\n", arg.c_str());
             usage();
             return 1;
         }
@@ -313,15 +310,14 @@
     // Find out some details about the base APK.
     AppInfo baseAppInfo;
     if (!getAppInfo(baseApkPath, baseAppInfo)) {
-        fprintf(stderr, "error: unable to read base APK: '%s'.\n", baseApkPath.string());
+        fprintf(stderr, "error: unable to read base APK: '%s'.\n", baseApkPath.c_str());
         return 1;
     }
 
     SplitDescription targetSplit;
     if (!generateFlag) {
         if (!SplitDescription::parse(targetConfigStr, &targetSplit)) {
-            fprintf(stderr, "error: invalid --target config: '%s'.\n",
-                    targetConfigStr.string());
+            fprintf(stderr, "error: invalid --target config: '%s'.\n", targetConfigStr.c_str());
             usage();
             return 1;
         }
@@ -341,7 +337,7 @@
         Vector<SplitDescription> splits = extractSplitDescriptionsFromApk(splitApkPaths[i]);
         if (splits.isEmpty()) {
             fprintf(stderr, "error: invalid --split path: '%s'. No splits found.\n",
-                    splitApkPaths[i].string());
+                    splitApkPaths[i].c_str());
             usage();
             return 1;
         }
@@ -364,7 +360,7 @@
         const size_t matchingSplitApkPathCount = matchingSplitPaths.size();
         for (size_t i = 0; i < matchingSplitApkPathCount; i++) {
             if (matchingSplitPaths[i] != baseApkPath) {
-                fprintf(stdout, "%s\n", matchingSplitPaths[i].string());
+                fprintf(stdout, "%s\n", matchingSplitPaths[i].c_str());
             }
         }
     } else {
diff --git a/tools/split-select/Rule_test.cpp b/tools/split-select/Rule_test.cpp
index c6cff0d..c78533f 100644
--- a/tools/split-select/Rule_test.cpp
+++ b/tools/split-select/Rule_test.cpp
@@ -68,7 +68,7 @@
     expected.erase(std::remove_if(expected.begin(), expected.end(), ::isspace), expected.end());
 
     // Result
-    std::string result(rule.toJson().string());
+    std::string result(rule.toJson().c_str());
     result.erase(std::remove_if(result.begin(), result.end(), ::isspace), result.end());
 
     ASSERT_EQ(expected, result);
diff --git a/tools/split-select/SplitDescription.cpp b/tools/split-select/SplitDescription.cpp
index 99bc23d..4e2b48e 100644
--- a/tools/split-select/SplitDescription.cpp
+++ b/tools/split-select/SplitDescription.cpp
@@ -134,8 +134,8 @@
     String8 configStr;
     String8 extensionStr;
     if (index >= 0) {
-        configStr.setTo(str.string(), index);
-        extensionStr.setTo(str.string() + index + 1);
+        configStr.setTo(str.c_str(), index);
+        extensionStr.setTo(str.c_str() + index + 1);
     } else {
         configStr.setTo(str);
     }
diff --git a/tools/split-select/TestRules.cpp b/tools/split-select/TestRules.cpp
index 86ccd6a..ca3c56f 100644
--- a/tools/split-select/TestRules.cpp
+++ b/tools/split-select/TestRules.cpp
@@ -78,9 +78,8 @@
     const String8 actualStr(actual != NULL ? actual->toJson() : String8());
 
     if (expectedStr != actualStr) {
-        return ::testing::AssertionFailure()
-                << "Expected: " << expectedStr.string() << "\n"
-                << "  Actual: " << actualStr.string();
+        return ::testing::AssertionFailure() << "Expected: " << expectedStr.c_str() << "\n"
+                                             << "  Actual: " << actualStr.c_str();
     }
     return ::testing::AssertionSuccess();
 }