Merge changes from topic "bridged_AP_callback"

* changes:
  wifi: Add callback onConnectedClientsOrInfoChanged handling
  wifi: Add new callback to support use case in bridged mode
diff --git a/Android.bp b/Android.bp
index 598f4fc..62ac6e7 100644
--- a/Android.bp
+++ b/Android.bp
@@ -349,6 +349,7 @@
         ":framework-telecomm-sources",
         ":framework-telephony-common-sources",
         ":framework-telephony-sources",
+        ":framework-vcn-util-sources",
         ":framework-wifi-annotations",
         ":framework-wifi-non-updatable-sources",
         ":PacProcessor-aidl-sources",
@@ -627,7 +628,6 @@
         // in favor of an API stubs dependency in java_library "framework" below.
         "mimemap",
         "av-types-aidl-java",
-        "mediatranscoding_aidl_interface-java",
         "soundtrigger_middleware-aidl-java",
         "modules-utils-os",
     ],
@@ -1373,7 +1373,6 @@
 
 // TODO(b/145644363): move this to under StubLibraries.bp or ApiDocs.bp
 metalava_framework_docs_args = "--manifest $(location core/res/AndroidManifest.xml) " +
-    "--ignore-classes-on-classpath " +
     "--hide-package com.android.server " +
     "--hide-package android.audio.policy.configuration.V7_0 " +
     "--error UnhiddenSystemApi " +
diff --git a/ApiDocs.bp b/ApiDocs.bp
index 3d6bdbf..5f4f3c2 100644
--- a/ApiDocs.bp
+++ b/ApiDocs.bp
@@ -96,7 +96,9 @@
     arg_files: [
         "core/res/AndroidManifest.xml",
     ],
-    args: metalava_framework_docs_args,
+    args: metalava_framework_docs_args +
+        // Needed for hidden libcore annotations for now.
+        " --ignore-classes-on-classpath ",
     write_sdk_values: true,
 }
 
@@ -106,7 +108,10 @@
     arg_files: [
         "core/res/AndroidManifest.xml",
     ],
-    args: metalava_framework_docs_args + " --show-annotation android.annotation.SystemApi\\(client=android.annotation.SystemApi.Client.PRIVILEGED_APPS\\) ",
+    args: metalava_framework_docs_args +
+        // Needed for hidden libcore annotations for now.
+        " --ignore-classes-on-classpath " +
+        " --show-annotation android.annotation.SystemApi\\(client=android.annotation.SystemApi.Client.PRIVILEGED_APPS\\) ",
     write_sdk_values: true,
 }
 
diff --git a/StubLibraries.bp b/StubLibraries.bp
index 12ee889..0596755 100644
--- a/StubLibraries.bp
+++ b/StubLibraries.bp
@@ -50,7 +50,9 @@
         ":art.module.public.api{.public.stubs.source}",
         "**/package.html",
     ],
-    sdk_version: "core_platform",
+    sdk_version: "none",
+    system_modules: "none",
+    java_version: "1.8",
     arg_files: ["core/res/AndroidManifest.xml"],
     // TODO(b/147699819, b/169090544): remove below aidl includes.
     aidl: {
@@ -80,6 +82,7 @@
         "android.hardware.usb.gadget-V1.0-java",
         "android.hardware.vibrator-V1.3-java",
         "framework-protos",
+        "stable.core.platform.api.stubs",
         // There are a few classes from modules used as type arguments that
         // need to be resolved by metalava. For now, we can use a previously
         // finalized stub library to resolve them. If a new class gets added,
diff --git a/apex/jobscheduler/framework/java/android/app/job/JobInfo.java b/apex/jobscheduler/framework/java/android/app/job/JobInfo.java
index 31f05ba..6eb44a7 100644
--- a/apex/jobscheduler/framework/java/android/app/job/JobInfo.java
+++ b/apex/jobscheduler/framework/java/android/app/job/JobInfo.java
@@ -1472,6 +1472,7 @@
          *     <li>Run as soon as possible</li>
          *     <li>Be exempted from Doze and battery saver restrictions</li>
          *     <li>Have network access</li>
+         *     <li>Less likely to be killed than regular jobs</li>
          * </ol>
          *
          * Since these jobs have stronger guarantees than regular jobs, they will be subject to
@@ -1483,10 +1484,11 @@
          * will immediately return {@link JobScheduler#RESULT_FAILURE} if the app does not have
          * available quota (and the job will not be successfully scheduled).
          *
-         * Expedited jobs may only set network constraints. No other constraints are allowed.
+         * Expedited jobs may only set network, storage-not-low, and persistence constraints.
+         * No other constraints are allowed.
          *
          * Note: Even though expedited jobs are meant to run as soon as possible, they may be
-         * deferred if the system is under heavy load or the network constraint is satisfied
+         * deferred if the system is under heavy load or requested constraints are not satisfied.
          *
          * @see JobInfo#isExpedited()
          */
@@ -1666,9 +1668,10 @@
             if (isPeriodic) {
                 throw new IllegalArgumentException("An expedited job cannot be periodic");
             }
-            if (constraintFlags != 0 || (flags & ~FLAG_EXPEDITED) != 0) {
+            if ((constraintFlags & ~CONSTRAINT_FLAG_STORAGE_NOT_LOW) != 0
+                    || (flags & ~FLAG_EXPEDITED) != 0) {
                 throw new IllegalArgumentException(
-                        "An expedited job can only have network constraints");
+                        "An expedited job can only have network and storage-not-low constraints");
             }
             if (triggerContentUris != null && triggerContentUris.length > 0) {
                 throw new IllegalArgumentException(
diff --git a/apex/jobscheduler/framework/java/android/app/job/JobParameters.java b/apex/jobscheduler/framework/java/android/app/job/JobParameters.java
index d4c78a0..0d3e001 100644
--- a/apex/jobscheduler/framework/java/android/app/job/JobParameters.java
+++ b/apex/jobscheduler/framework/java/android/app/job/JobParameters.java
@@ -202,6 +202,8 @@
      * {@code true}. This will return {@code false} if the job that wasn't requested to run as a
      * expedited job, or if it was requested to run as an expedited job but the app didn't have
      * any remaining expedited job quota at the time of execution.
+     *
+     * @see JobInfo.Builder#setExpedited(boolean)
      */
     public boolean isExpeditedJob() {
         return mIsExpedited;
diff --git a/apex/media/framework/Android.bp b/apex/media/framework/Android.bp
index 811a700..60dea07 100644
--- a/apex/media/framework/Android.bp
+++ b/apex/media/framework/Android.bp
@@ -36,7 +36,8 @@
         "framework_media_annotation",
     ],
     static_libs: [
-        "exoplayer2-extractor"
+        "exoplayer2-extractor",
+        "mediatranscoding_aidl_interface-java",
     ],
     jarjar_rules: "jarjar_rules.txt",
 
@@ -57,10 +58,12 @@
 filegroup {
     name: "updatable-media-srcs",
     srcs: [
+        "java/android/media/MediaFrameworkInitializer.java",
         ":media-aidl-srcs",
         ":mediaparceledlistslice-java-srcs",
         ":mediaparser-srcs",
         ":mediasession2-java-srcs",
+        ":mediatranscoding-srcs",
     ],
     visibility: ["//frameworks/base"],
 }
@@ -98,6 +101,17 @@
     path: "java",
 }
 
+filegroup {
+    name: "mediatranscoding-srcs",
+    srcs: [
+        "java/android/media/ApplicationMediaCapabilities.java",
+        "java/android/media/MediaFeature.java",
+        "java/android/media/MediaTranscodeManager.java",
+        "java/android/media/MediaTranscodingException.java",
+    ],
+    path: "java",
+}
+
 java_sdk_library {
     name: "framework-media",
     defaults: ["framework-module-defaults"],
diff --git a/apex/media/framework/api/current.txt b/apex/media/framework/api/current.txt
index 0cc8e52..ce3bcbe 100644
--- a/apex/media/framework/api/current.txt
+++ b/apex/media/framework/api/current.txt
@@ -1,6 +1,26 @@
 // Signature format: 2.0
 package android.media {
 
+  public final class ApplicationMediaCapabilities implements android.os.Parcelable {
+    method @NonNull public static android.media.ApplicationMediaCapabilities createFromXml(@NonNull org.xmlpull.v1.XmlPullParser);
+    method public int describeContents();
+    method @NonNull public java.util.List<java.lang.String> getSupportedHdrTypes();
+    method @NonNull public java.util.List<java.lang.String> getSupportedVideoMimeTypes();
+    method public boolean isHdrTypeSupported(@NonNull String);
+    method public boolean isSlowMotionSupported();
+    method public boolean isVideoMimeTypeSupported(@NonNull String);
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.media.ApplicationMediaCapabilities> CREATOR;
+  }
+
+  public static final class ApplicationMediaCapabilities.Builder {
+    ctor public ApplicationMediaCapabilities.Builder();
+    method @NonNull public android.media.ApplicationMediaCapabilities.Builder addSupportedHdrType(@NonNull String);
+    method @NonNull public android.media.ApplicationMediaCapabilities.Builder addSupportedVideoMimeType(@NonNull String);
+    method @NonNull public android.media.ApplicationMediaCapabilities build();
+    method @NonNull public android.media.ApplicationMediaCapabilities.Builder setSlowMotionSupported(boolean);
+  }
+
   public class MediaController2 implements java.lang.AutoCloseable {
     method public void cancelSessionCommand(@NonNull Object);
     method public void close();
@@ -25,6 +45,17 @@
     method @Nullable public android.media.Session2Command.Result onSessionCommand(@NonNull android.media.MediaController2, @NonNull android.media.Session2Command, @Nullable android.os.Bundle);
   }
 
+  public final class MediaFeature {
+    ctor public MediaFeature();
+  }
+
+  public static final class MediaFeature.HdrType {
+    field public static final String DOLBY_VISION = "android.media.feature.hdr.dolby_vision";
+    field public static final String HDR10 = "android.media.feature.hdr.hdr10";
+    field public static final String HDR10_PLUS = "android.media.feature.hdr.hdr10_plus";
+    field public static final String HLG = "android.media.feature.hdr.hlg";
+  }
+
   public final class MediaParser {
     method public boolean advance(@NonNull android.media.MediaParser.SeekableInputReader) throws java.io.IOException;
     method @NonNull public static android.media.MediaParser create(@NonNull android.media.MediaParser.OutputConsumer, @NonNull java.lang.String...);
@@ -170,6 +201,12 @@
     method public int getNotificationId();
   }
 
+  public class MediaTranscodingException extends java.lang.Exception {
+  }
+
+  public static final class MediaTranscodingException.ServiceNotAvailableException extends android.media.MediaTranscodingException {
+  }
+
   public final class Session2Command implements android.os.Parcelable {
     ctor public Session2Command(int);
     ctor public Session2Command(@NonNull String, @Nullable android.os.Bundle);
diff --git a/apex/media/framework/api/module-lib-current.txt b/apex/media/framework/api/module-lib-current.txt
index 2b69863..ad9114f 100644
--- a/apex/media/framework/api/module-lib-current.txt
+++ b/apex/media/framework/api/module-lib-current.txt
@@ -1,6 +1,11 @@
 // Signature format: 2.0
 package android.media {
 
+  public class MediaFrameworkInitializer {
+    method public static void registerServiceWrappers();
+    method public static void setMediaServiceManager(@NonNull android.media.MediaServiceManager);
+  }
+
   @Deprecated public final class MediaParceledListSlice<T extends android.os.Parcelable> implements android.os.Parcelable {
     ctor @Deprecated public MediaParceledListSlice(@NonNull java.util.List<T>);
     method @Deprecated public int describeContents();
diff --git a/apex/media/framework/api/system-current.txt b/apex/media/framework/api/system-current.txt
index d802177..89cf77c 100644
--- a/apex/media/framework/api/system-current.txt
+++ b/apex/media/framework/api/system-current.txt
@@ -1 +1,67 @@
 // Signature format: 2.0
+package android.media {
+
+  public final class MediaTranscodeManager {
+    method @NonNull public android.media.MediaTranscodeManager.TranscodingSession enqueueRequest(@NonNull android.media.MediaTranscodeManager.TranscodingRequest, @NonNull java.util.concurrent.Executor, @NonNull android.media.MediaTranscodeManager.OnTranscodingFinishedListener) throws java.io.FileNotFoundException, android.media.MediaTranscodingException.ServiceNotAvailableException;
+    field public static final int PRIORITY_REALTIME = 1; // 0x1
+    field public static final int TRANSCODING_TYPE_VIDEO = 1; // 0x1
+  }
+
+  @java.lang.FunctionalInterface public static interface MediaTranscodeManager.OnTranscodingFinishedListener {
+    method public void onTranscodingFinished(@NonNull android.media.MediaTranscodeManager.TranscodingSession);
+  }
+
+  public static final class MediaTranscodeManager.TranscodingRequest {
+    method public int getClientPid();
+    method public int getClientUid();
+    method @NonNull public android.net.Uri getDestinationUri();
+    method public int getPriority();
+    method @NonNull public android.net.Uri getSourceUri();
+    method public int getType();
+    method @Nullable public android.media.MediaFormat getVideoTrackFormat();
+  }
+
+  public static final class MediaTranscodeManager.TranscodingRequest.Builder {
+    ctor public MediaTranscodeManager.TranscodingRequest.Builder();
+    method @NonNull public android.media.MediaTranscodeManager.TranscodingRequest build();
+    method @NonNull public android.media.MediaTranscodeManager.TranscodingRequest.Builder setClientPid(int);
+    method @NonNull public android.media.MediaTranscodeManager.TranscodingRequest.Builder setClientUid(int);
+    method @NonNull public android.media.MediaTranscodeManager.TranscodingRequest.Builder setDestinationUri(@NonNull android.net.Uri);
+    method @NonNull public android.media.MediaTranscodeManager.TranscodingRequest.Builder setPriority(int);
+    method @NonNull public android.media.MediaTranscodeManager.TranscodingRequest.Builder setSourceUri(@NonNull android.net.Uri);
+    method @NonNull public android.media.MediaTranscodeManager.TranscodingRequest.Builder setType(int);
+    method @NonNull public android.media.MediaTranscodeManager.TranscodingRequest.Builder setVideoTrackFormat(@NonNull android.media.MediaFormat);
+  }
+
+  public static class MediaTranscodeManager.TranscodingRequest.MediaFormatResolver {
+    ctor public MediaTranscodeManager.TranscodingRequest.MediaFormatResolver();
+    method @Nullable public android.media.MediaFormat resolveVideoFormat();
+    method @NonNull public android.media.MediaTranscodeManager.TranscodingRequest.MediaFormatResolver setClientCapabilities(@NonNull android.media.ApplicationMediaCapabilities);
+    method @NonNull public android.media.MediaTranscodeManager.TranscodingRequest.MediaFormatResolver setSourceVideoFormatHint(@NonNull android.media.MediaFormat);
+    method public boolean shouldTranscode();
+  }
+
+  public static final class MediaTranscodeManager.TranscodingSession {
+    method public void cancel();
+    method @IntRange(from=0, to=100) public int getProgress();
+    method public int getResult();
+    method public int getSessionId();
+    method public int getStatus();
+    method public void setOnProgressUpdateListener(@NonNull java.util.concurrent.Executor, @Nullable android.media.MediaTranscodeManager.TranscodingSession.OnProgressUpdateListener);
+    method public void setOnProgressUpdateListener(int, @NonNull java.util.concurrent.Executor, @Nullable android.media.MediaTranscodeManager.TranscodingSession.OnProgressUpdateListener);
+    field public static final int RESULT_CANCELED = 4; // 0x4
+    field public static final int RESULT_ERROR = 3; // 0x3
+    field public static final int RESULT_NONE = 1; // 0x1
+    field public static final int RESULT_SUCCESS = 2; // 0x2
+    field public static final int STATUS_FINISHED = 3; // 0x3
+    field public static final int STATUS_PAUSED = 4; // 0x4
+    field public static final int STATUS_PENDING = 1; // 0x1
+    field public static final int STATUS_RUNNING = 2; // 0x2
+  }
+
+  @java.lang.FunctionalInterface public static interface MediaTranscodeManager.TranscodingSession.OnProgressUpdateListener {
+    method public void onProgressUpdate(@NonNull android.media.MediaTranscodeManager.TranscodingSession, @IntRange(from=0, to=100) int);
+  }
+
+}
+
diff --git a/media/java/android/media/ApplicationMediaCapabilities.java b/apex/media/framework/java/android/media/ApplicationMediaCapabilities.java
similarity index 100%
rename from media/java/android/media/ApplicationMediaCapabilities.java
rename to apex/media/framework/java/android/media/ApplicationMediaCapabilities.java
diff --git a/media/java/android/media/MediaFeature.java b/apex/media/framework/java/android/media/MediaFeature.java
similarity index 100%
rename from media/java/android/media/MediaFeature.java
rename to apex/media/framework/java/android/media/MediaFeature.java
diff --git a/media/java/android/media/MediaFrameworkInitializer.java b/apex/media/framework/java/android/media/MediaFrameworkInitializer.java
similarity index 73%
copy from media/java/android/media/MediaFrameworkInitializer.java
copy to apex/media/framework/java/android/media/MediaFrameworkInitializer.java
index 577442e..813ad7b 100644
--- a/media/java/android/media/MediaFrameworkInitializer.java
+++ b/apex/media/framework/java/android/media/MediaFrameworkInitializer.java
@@ -17,20 +17,18 @@
 package android.media;
 
 import android.annotation.NonNull;
+import android.annotation.SystemApi;
+import android.annotation.SystemApi.Client;
+import android.media.MediaTranscodeManager;
 import android.app.SystemServiceRegistry;
 import android.content.Context;
-import android.media.session.MediaSessionManager;
-
-import com.android.internal.util.Preconditions;
-
-import java.util.Objects;
 
 /**
- * Class for performing registration for all media services
+ * Class for performing registration for all media services on com.android.media apex.
  *
- * TODO (b/160513103): Move this class when moving media service code to APEX
  * @hide
  */
+@SystemApi(client = Client.MODULE_LIBRARIES)
 public class MediaFrameworkInitializer {
     private MediaFrameworkInitializer() {
     }
@@ -47,9 +45,15 @@
      */
     public static void setMediaServiceManager(
             @NonNull MediaServiceManager mediaServiceManager) {
-        Preconditions.checkState(sMediaServiceManager == null,
-                "setMediaServiceManager called twice!");
-        sMediaServiceManager = Objects.requireNonNull(mediaServiceManager);
+        if (sMediaServiceManager != null) {
+            throw new IllegalStateException("setMediaServiceManager called twice!");
+        }
+
+        if (mediaServiceManager == null) {
+            throw new NullPointerException("mediaServiceManager is null!");
+        }
+
+        sMediaServiceManager = mediaServiceManager;
     }
 
     /** @hide */
@@ -66,9 +70,9 @@
      */
     public static void registerServiceWrappers() {
         SystemServiceRegistry.registerContextAwareService(
-                Context.MEDIA_SESSION_SERVICE,
-                MediaSessionManager.class,
-                context -> new MediaSessionManager(context)
+                Context.MEDIA_TRANSCODING_SERVICE,
+                MediaTranscodeManager.class,
+                context -> new MediaTranscodeManager(context)
         );
     }
 }
diff --git a/media/java/android/media/MediaTranscodeManager.java b/apex/media/framework/java/android/media/MediaTranscodeManager.java
similarity index 99%
rename from media/java/android/media/MediaTranscodeManager.java
rename to apex/media/framework/java/android/media/MediaTranscodeManager.java
index 705da19..d449289 100644
--- a/media/java/android/media/MediaTranscodeManager.java
+++ b/apex/media/framework/java/android/media/MediaTranscodeManager.java
@@ -28,7 +28,6 @@
 import android.net.Uri;
 import android.os.ParcelFileDescriptor;
 import android.os.RemoteException;
-import android.os.ServiceManager;
 import android.os.ServiceSpecificException;
 import android.system.Os;
 import android.util.Log;
@@ -104,8 +103,6 @@
 public final class MediaTranscodeManager {
     private static final String TAG = "MediaTranscodeManager";
 
-    private static final String MEDIA_TRANSCODING_SERVICE = "media.transcoding";
-
     /** Maximum number of retry to connect to the service. */
     private static final int CONNECT_SERVICE_RETRY_COUNT = 100;
 
@@ -281,7 +278,10 @@
         for (int count = 1;  count <= retryCount; count++) {
             Log.d(TAG, "Trying to connect to service. Try count: " + count);
             IMediaTranscodingService service = IMediaTranscodingService.Stub.asInterface(
-                    ServiceManager.getService(MEDIA_TRANSCODING_SERVICE));
+                    MediaFrameworkInitializer
+                    .getMediaServiceManager()
+                    .getMediaTranscodingServiceRegisterer()
+                    .get());
             if (service != null) {
                 return service;
             }
diff --git a/media/java/android/media/MediaTranscodingException.java b/apex/media/framework/java/android/media/MediaTranscodingException.java
similarity index 100%
rename from media/java/android/media/MediaTranscodingException.java
rename to apex/media/framework/java/android/media/MediaTranscodingException.java
diff --git a/cmds/idmap2/idmap2/Lookup.cpp b/cmds/idmap2/idmap2/Lookup.cpp
index 8323d0b..437180d 100644
--- a/cmds/idmap2/idmap2/Lookup.cpp
+++ b/cmds/idmap2/idmap2/Lookup.cpp
@@ -71,7 +71,7 @@
   }
 
   // next, try to parse as a package:type/name string
-  if (auto resid = am.GetResourceId(res, "", fallback_package)) {
+  if (auto resid = am.GetResourceId(res, "", fallback_package); resid.ok()) {
     return *resid;
   }
 
@@ -94,7 +94,7 @@
     case Res_value::TYPE_STRING: {
       const ResStringPool* pool = am->GetStringPoolForCookie(value.cookie);
       out->append("\"");
-      if (auto str = pool->string8ObjectAt(value.data)) {
+      if (auto str = pool->string8ObjectAt(value.data); str.ok()) {
         out->append(*str);
       }
     } break;
diff --git a/cmds/idmap2/libidmap2/XmlParser.cpp b/cmds/idmap2/libidmap2/XmlParser.cpp
index 7c55b64..4030b83 100644
--- a/cmds/idmap2/libidmap2/XmlParser.cpp
+++ b/cmds/idmap2/libidmap2/XmlParser.cpp
@@ -98,7 +98,7 @@
 
   switch ((*value).dataType) {
     case Res_value::TYPE_STRING: {
-      if (auto str = parser_.getStrings().string8ObjectAt((*value).data)) {
+      if (auto str = parser_.getStrings().string8ObjectAt((*value).data); str.ok()) {
         return std::string(str->string());
       }
       break;
diff --git a/core/api/current.txt b/core/api/current.txt
index c2f88d7..c11d2bc 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -10134,6 +10134,7 @@
     method public abstract android.content.Context createDisplayContext(@NonNull android.view.Display);
     method public abstract android.content.Context createPackageContext(String, int) throws android.content.pm.PackageManager.NameNotFoundException;
     method @NonNull public android.content.Context createWindowContext(int, @Nullable android.os.Bundle);
+    method @NonNull public android.content.Context createWindowContext(@NonNull android.view.Display, int, @Nullable android.os.Bundle);
     method public abstract String[] databaseList();
     method public abstract boolean deleteDatabase(String);
     method public abstract boolean deleteFile(String);
@@ -19069,6 +19070,20 @@
     field public static final int STATE_UNKNOWN = 0; // 0x0
   }
 
+  public final class GnssMeasurementRequest implements android.os.Parcelable {
+    method public int describeContents();
+    method public boolean isFullTracking();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.location.GnssMeasurementRequest> CREATOR;
+  }
+
+  public static final class GnssMeasurementRequest.Builder {
+    ctor public GnssMeasurementRequest.Builder();
+    ctor public GnssMeasurementRequest.Builder(@NonNull android.location.GnssMeasurementRequest);
+    method @NonNull public android.location.GnssMeasurementRequest build();
+    method @NonNull public android.location.GnssMeasurementRequest.Builder setFullTracking(boolean);
+  }
+
   public final class GnssMeasurementsEvent implements android.os.Parcelable {
     method public int describeContents();
     method @NonNull public android.location.GnssClock getClock();
@@ -19295,6 +19310,7 @@
     method @Deprecated @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public boolean registerGnssMeasurementsCallback(@NonNull android.location.GnssMeasurementsEvent.Callback);
     method @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public boolean registerGnssMeasurementsCallback(@NonNull android.location.GnssMeasurementsEvent.Callback, @Nullable android.os.Handler);
     method @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public boolean registerGnssMeasurementsCallback(@NonNull java.util.concurrent.Executor, @NonNull android.location.GnssMeasurementsEvent.Callback);
+    method @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public boolean registerGnssMeasurementsCallback(@NonNull android.location.GnssMeasurementRequest, @NonNull java.util.concurrent.Executor, @NonNull android.location.GnssMeasurementsEvent.Callback);
     method @Deprecated public boolean registerGnssNavigationMessageCallback(@NonNull android.location.GnssNavigationMessage.Callback);
     method @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public boolean registerGnssNavigationMessageCallback(@NonNull android.location.GnssNavigationMessage.Callback, @Nullable android.os.Handler);
     method @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public boolean registerGnssNavigationMessageCallback(@NonNull java.util.concurrent.Executor, @NonNull android.location.GnssNavigationMessage.Callback);
@@ -19430,26 +19446,6 @@
 
 package android.media {
 
-  public final class ApplicationMediaCapabilities implements android.os.Parcelable {
-    method @NonNull public static android.media.ApplicationMediaCapabilities createFromXml(@NonNull org.xmlpull.v1.XmlPullParser);
-    method public int describeContents();
-    method @NonNull public java.util.List<java.lang.String> getSupportedHdrTypes();
-    method @NonNull public java.util.List<java.lang.String> getSupportedVideoMimeTypes();
-    method public boolean isHdrTypeSupported(@NonNull String);
-    method public boolean isSlowMotionSupported();
-    method public boolean isVideoMimeTypeSupported(@NonNull String);
-    method public void writeToParcel(@NonNull android.os.Parcel, int);
-    field @NonNull public static final android.os.Parcelable.Creator<android.media.ApplicationMediaCapabilities> CREATOR;
-  }
-
-  public static final class ApplicationMediaCapabilities.Builder {
-    ctor public ApplicationMediaCapabilities.Builder();
-    method @NonNull public android.media.ApplicationMediaCapabilities.Builder addSupportedHdrType(@NonNull String);
-    method @NonNull public android.media.ApplicationMediaCapabilities.Builder addSupportedVideoMimeType(@NonNull String);
-    method @NonNull public android.media.ApplicationMediaCapabilities build();
-    method @NonNull public android.media.ApplicationMediaCapabilities.Builder setSlowMotionSupported(boolean);
-  }
-
   public class AsyncPlayer {
     ctor public AsyncPlayer(String);
     method @Deprecated public void play(android.content.Context, android.net.Uri, boolean, int);
@@ -19670,15 +19666,18 @@
   public class AudioManager {
     method @Deprecated public int abandonAudioFocus(android.media.AudioManager.OnAudioFocusChangeListener);
     method public int abandonAudioFocusRequest(@NonNull android.media.AudioFocusRequest);
+    method public void addOnCommunicationDeviceChangedListener(@NonNull java.util.concurrent.Executor, @NonNull android.media.AudioManager.OnCommunicationDeviceChangedListener);
     method public void adjustStreamVolume(int, int, int);
     method public void adjustSuggestedStreamVolume(int, int, int);
     method public void adjustVolume(int, int);
+    method public void clearDeviceForCommunication();
     method public void dispatchMediaKeyEvent(android.view.KeyEvent);
     method public int generateAudioSessionId();
     method @NonNull public java.util.List<android.media.AudioPlaybackConfiguration> getActivePlaybackConfigurations();
     method @NonNull public java.util.List<android.media.AudioRecordingConfiguration> getActiveRecordingConfigurations();
     method public int getAllowedCapturePolicy();
     method public int getAudioHwSyncForSession(int);
+    method @Nullable public android.media.AudioDeviceInfo getDeviceForCommunication();
     method public android.media.AudioDeviceInfo[] getDevices(int);
     method public java.util.List<android.media.MicrophoneInfo> getMicrophones() throws java.io.IOException;
     method public int getMode();
@@ -19714,11 +19713,13 @@
     method @Deprecated public void registerMediaButtonEventReceiver(android.app.PendingIntent);
     method @Deprecated public void registerRemoteControlClient(android.media.RemoteControlClient);
     method @Deprecated public boolean registerRemoteController(android.media.RemoteController);
+    method public void removeOnCommunicationDeviceChangedListener(@NonNull android.media.AudioManager.OnCommunicationDeviceChangedListener);
     method @Deprecated public int requestAudioFocus(android.media.AudioManager.OnAudioFocusChangeListener, int, int);
     method public int requestAudioFocus(@NonNull android.media.AudioFocusRequest);
     method public void setAllowedCapturePolicy(int);
     method @Deprecated public void setBluetoothA2dpOn(boolean);
     method public void setBluetoothScoOn(boolean);
+    method public boolean setDeviceForCommunication(@NonNull android.media.AudioDeviceInfo);
     method public void setMicrophoneMute(boolean);
     method public void setMode(int);
     method public void setParameters(String);
@@ -19856,6 +19857,10 @@
     method public void onAudioFocusChange(int);
   }
 
+  public static interface AudioManager.OnCommunicationDeviceChangedListener {
+    method public void onCommunicationDeviceChanged(@Nullable android.media.AudioDeviceInfo);
+  }
+
   public final class AudioMetadata {
     method @NonNull public static android.media.AudioMetadataMap createMap();
   }
@@ -19907,7 +19912,6 @@
   public final class AudioPlaybackConfiguration implements android.os.Parcelable {
     method public int describeContents();
     method public android.media.AudioAttributes getAudioAttributes();
-    method @Nullable public android.media.AudioDeviceInfo getAudioDevice();
     method public void writeToParcel(android.os.Parcel, int);
     field @NonNull public static final android.os.Parcelable.Creator<android.media.AudioPlaybackConfiguration> CREATOR;
   }
@@ -21561,17 +21565,6 @@
     field public static final String TRACKS = "android.media.mediaextractor.ntrk";
   }
 
-  public final class MediaFeature {
-    ctor public MediaFeature();
-  }
-
-  public static final class MediaFeature.HdrType {
-    field public static final String DOLBY_VISION = "android.media.feature.hdr.dolby_vision";
-    field public static final String HDR10 = "android.media.feature.hdr.hdr10";
-    field public static final String HDR10_PLUS = "android.media.feature.hdr.hdr10_plus";
-    field public static final String HLG = "android.media.feature.hdr.hlg";
-  }
-
   public final class MediaFormat {
     ctor public MediaFormat();
     ctor public MediaFormat(@NonNull android.media.MediaFormat);
@@ -22592,12 +22585,6 @@
     field public static final android.media.MediaTimestamp TIMESTAMP_UNKNOWN;
   }
 
-  public class MediaTranscodingException extends java.lang.Exception {
-  }
-
-  public static final class MediaTranscodingException.ServiceNotAvailableException extends android.media.MediaTranscodingException {
-  }
-
   public interface MicrophoneDirection {
     method public boolean setPreferredMicrophoneDirection(int);
     method public boolean setPreferredMicrophoneFieldDimension(@FloatRange(from=-1.0, to=1.0) float);
@@ -33611,8 +33598,8 @@
   }
 
   protected static interface ContactsContract.DataColumns {
-    field public static final String CARRIER_PRESENCE = "carrier_presence";
-    field public static final int CARRIER_PRESENCE_VT_CAPABLE = 1; // 0x1
+    field @Deprecated public static final String CARRIER_PRESENCE = "carrier_presence";
+    field @Deprecated public static final int CARRIER_PRESENCE_VT_CAPABLE = 1; // 0x1
     field public static final String DATA1 = "data1";
     field public static final String DATA10 = "data10";
     field public static final String DATA11 = "data11";
@@ -40665,7 +40652,7 @@
     field public static final String KEY_USE_ACS_FOR_RCS_BOOL = "use_acs_for_rcs_bool";
     field public static final String KEY_USE_HFA_FOR_PROVISIONING_BOOL = "use_hfa_for_provisioning_bool";
     field public static final String KEY_USE_OTASP_FOR_PROVISIONING_BOOL = "use_otasp_for_provisioning_bool";
-    field public static final String KEY_USE_RCS_PRESENCE_BOOL = "use_rcs_presence_bool";
+    field @Deprecated public static final String KEY_USE_RCS_PRESENCE_BOOL = "use_rcs_presence_bool";
     field public static final String KEY_USE_RCS_SIP_OPTIONS_BOOL = "use_rcs_sip_options_bool";
     field public static final String KEY_USE_WFC_HOME_NETWORK_MODE_IN_ROAMING_NETWORK_BOOL = "use_wfc_home_network_mode_in_roaming_network_bool";
     field public static final String KEY_VOICEMAIL_NOTIFICATION_PERSISTENT_BOOL = "voicemail_notification_persistent_bool";
@@ -40705,9 +40692,12 @@
   }
 
   public static final class CarrierConfigManager.Ims {
+    field public static final String KEY_ENABLE_PRESENCE_CAPABILITY_EXCHANGE_BOOL = "ims.enable_presence_capability_exchange_bool";
+    field public static final String KEY_ENABLE_PRESENCE_GROUP_SUBSCRIBE_BOOL = "ims.enable_presence_group_subscribe_bool";
     field public static final String KEY_ENABLE_PRESENCE_PUBLISH_BOOL = "ims.enable_presence_publish_bool";
     field public static final String KEY_IMS_SINGLE_REGISTRATION_REQUIRED_BOOL = "ims.ims_single_registration_required_bool";
     field public static final String KEY_PREFIX = "ims.";
+    field public static final String KEY_RCS_BULK_CAPABILITY_EXCHANGE_BOOL = "ims.rcs_bulk_capability_exchange_bool";
     field public static final String KEY_WIFI_OFF_DEFERRING_TIME_MILLIS_INT = "ims.wifi_off_deferring_time_millis_int";
   }
 
@@ -41363,6 +41353,7 @@
     field public static final int SERVICE_OPTION_OUT_OF_ORDER = 34; // 0x22
     field public static final int SIGNAL_LOST = -3; // 0xfffffffd
     field public static final int SIM_CARD_CHANGED = 2043; // 0x7fb
+    field public static final int SLICE_REJECTED = 2252; // 0x8cc
     field public static final int SYNCHRONIZATION_FAILURE = 2184; // 0x888
     field public static final int TEST_LOOPBACK_REGULAR_DEACTIVATION = 2196; // 0x894
     field public static final int TETHERED_CALL_ACTIVE = -6; // 0xfffffffa
@@ -42272,6 +42263,7 @@
     method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public boolean doesSwitchMultiSimConfigTriggerReboot();
     method public int getActiveModemCount();
     method @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public java.util.List<android.telephony.CellInfo> getAllCellInfo();
+    method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public int getCallComposerStatus();
     method public int getCallState();
     method public int getCardIdForDefaultEuicc();
     method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) @WorkerThread public android.os.PersistableBundle getCarrierConfig();
@@ -42368,6 +42360,7 @@
     method @Deprecated public String sendEnvelopeWithStatus(String);
     method @RequiresPermission(android.Manifest.permission.CALL_PHONE) public void sendUssdRequest(String, android.telephony.TelephonyManager.UssdResponseCallback, android.os.Handler);
     method public void sendVisualVoicemailSms(String, int, String, android.app.PendingIntent);
+    method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setCallComposerStatus(int);
     method @Deprecated @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setDataEnabled(boolean);
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setDataEnabledForReason(int, boolean);
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public int setForbiddenPlmns(@NonNull java.util.List<java.lang.String>);
@@ -42408,6 +42401,8 @@
     field public static final int APPTYPE_USIM = 2; // 0x2
     field public static final int AUTHTYPE_EAP_AKA = 129; // 0x81
     field public static final int AUTHTYPE_EAP_SIM = 128; // 0x80
+    field public static final int CALL_COMPOSER_STATUS_OFF = 0; // 0x0
+    field public static final int CALL_COMPOSER_STATUS_ON = 1; // 0x1
     field public static final int CALL_STATE_IDLE = 0; // 0x0
     field public static final int CALL_STATE_OFFHOOK = 2; // 0x2
     field public static final int CALL_STATE_RINGING = 1; // 0x1
@@ -46680,6 +46675,7 @@
     method public java.util.List<android.view.InputDevice.MotionRange> getMotionRanges();
     method public String getName();
     method public int getProductId();
+    method @NonNull public android.hardware.SensorManager getSensorManager();
     method public int getSources();
     method public int getVendorId();
     method public android.os.Vibrator getVibrator();
@@ -52150,6 +52146,7 @@
     method public void setCookieAndSequence(int, int);
     method public void writeToParcel(android.os.Parcel, int);
     field @NonNull public static final android.os.Parcelable.Creator<android.view.textservice.SuggestionsInfo> CREATOR;
+    field public static final int RESULT_ATTR_DONT_SHOW_UI_FOR_SUGGESTIONS = 16; // 0x10
     field public static final int RESULT_ATTR_HAS_RECOMMENDED_SUGGESTIONS = 4; // 0x4
     field public static final int RESULT_ATTR_IN_THE_DICTIONARY = 1; // 0x1
     field public static final int RESULT_ATTR_LOOKS_LIKE_GRAMMAR_ERROR = 8; // 0x8
diff --git a/core/api/module-lib-current.txt b/core/api/module-lib-current.txt
index cbb3bea..94a6576 100644
--- a/core/api/module-lib-current.txt
+++ b/core/api/module-lib-current.txt
@@ -80,6 +80,17 @@
 
   public class MediaMetadataRetriever implements java.lang.AutoCloseable {
     field public static final int METADATA_KEY_VIDEO_CODEC_MIME_TYPE = 40; // 0x28
+    field public static final int METADATA_KEY_XMP_LENGTH = 42; // 0x2a
+    field public static final int METADATA_KEY_XMP_OFFSET = 41; // 0x29
+  }
+
+  public class MediaServiceManager {
+    method @NonNull public android.media.MediaServiceManager.ServiceRegisterer getMediaSessionServiceRegisterer();
+    method @NonNull public android.media.MediaServiceManager.ServiceRegisterer getMediaTranscodingServiceRegisterer();
+  }
+
+  public static final class MediaServiceManager.ServiceRegisterer {
+    method @Nullable public android.os.IBinder get();
   }
 
 }
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index 0f1adc0..8fd48a5 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -4316,7 +4316,7 @@
     method @Deprecated @RequiresPermission(android.Manifest.permission.READ_DEVICE_CONFIG) public boolean isProviderPackage(@NonNull String);
     method @RequiresPermission(android.Manifest.permission.READ_DEVICE_CONFIG) public boolean isProviderPackage(@Nullable String, @NonNull String);
     method @Deprecated @RequiresPermission(allOf={android.Manifest.permission.LOCATION_HARDWARE, android.Manifest.permission.UPDATE_APP_OPS_STATS}) public boolean registerGnssBatchedLocationCallback(long, boolean, @NonNull android.location.BatchedLocationCallback, @Nullable android.os.Handler);
-    method @RequiresPermission(allOf={android.Manifest.permission.ACCESS_FINE_LOCATION, android.Manifest.permission.LOCATION_HARDWARE}) public boolean registerGnssMeasurementsCallback(@NonNull android.location.GnssRequest, @NonNull java.util.concurrent.Executor, @NonNull android.location.GnssMeasurementsEvent.Callback);
+    method @Deprecated @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public boolean registerGnssMeasurementsCallback(@NonNull android.location.GnssRequest, @NonNull java.util.concurrent.Executor, @NonNull android.location.GnssMeasurementsEvent.Callback);
     method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(@Nullable android.location.LocationRequest, @NonNull android.location.LocationListener, @Nullable android.os.Looper);
     method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(@Nullable android.location.LocationRequest, @NonNull java.util.concurrent.Executor, @NonNull android.location.LocationListener);
     method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(@Nullable android.location.LocationRequest, @NonNull android.app.PendingIntent);
@@ -4593,68 +4593,6 @@
     field @RequiresPermission(android.Manifest.permission.CAPTURE_AUDIO_OUTPUT) public static final int RADIO_TUNER = 1998; // 0x7ce
   }
 
-  public final class MediaTranscodeManager {
-    method @NonNull public android.media.MediaTranscodeManager.TranscodingSession enqueueRequest(@NonNull android.media.MediaTranscodeManager.TranscodingRequest, @NonNull java.util.concurrent.Executor, @NonNull android.media.MediaTranscodeManager.OnTranscodingFinishedListener) throws java.io.FileNotFoundException, android.media.MediaTranscodingException.ServiceNotAvailableException;
-    field public static final int PRIORITY_REALTIME = 1; // 0x1
-    field public static final int TRANSCODING_TYPE_VIDEO = 1; // 0x1
-  }
-
-  @java.lang.FunctionalInterface public static interface MediaTranscodeManager.OnTranscodingFinishedListener {
-    method public void onTranscodingFinished(@NonNull android.media.MediaTranscodeManager.TranscodingSession);
-  }
-
-  public static final class MediaTranscodeManager.TranscodingRequest {
-    method public int getClientPid();
-    method public int getClientUid();
-    method @NonNull public android.net.Uri getDestinationUri();
-    method public int getPriority();
-    method @NonNull public android.net.Uri getSourceUri();
-    method public int getType();
-    method @Nullable public android.media.MediaFormat getVideoTrackFormat();
-  }
-
-  public static final class MediaTranscodeManager.TranscodingRequest.Builder {
-    ctor public MediaTranscodeManager.TranscodingRequest.Builder();
-    method @NonNull public android.media.MediaTranscodeManager.TranscodingRequest build();
-    method @NonNull public android.media.MediaTranscodeManager.TranscodingRequest.Builder setClientPid(int);
-    method @NonNull public android.media.MediaTranscodeManager.TranscodingRequest.Builder setClientUid(int);
-    method @NonNull public android.media.MediaTranscodeManager.TranscodingRequest.Builder setDestinationUri(@NonNull android.net.Uri);
-    method @NonNull public android.media.MediaTranscodeManager.TranscodingRequest.Builder setPriority(int);
-    method @NonNull public android.media.MediaTranscodeManager.TranscodingRequest.Builder setSourceUri(@NonNull android.net.Uri);
-    method @NonNull public android.media.MediaTranscodeManager.TranscodingRequest.Builder setType(int);
-    method @NonNull public android.media.MediaTranscodeManager.TranscodingRequest.Builder setVideoTrackFormat(@NonNull android.media.MediaFormat);
-  }
-
-  public static class MediaTranscodeManager.TranscodingRequest.MediaFormatResolver {
-    ctor public MediaTranscodeManager.TranscodingRequest.MediaFormatResolver();
-    method @Nullable public android.media.MediaFormat resolveVideoFormat();
-    method @NonNull public android.media.MediaTranscodeManager.TranscodingRequest.MediaFormatResolver setClientCapabilities(@NonNull android.media.ApplicationMediaCapabilities);
-    method @NonNull public android.media.MediaTranscodeManager.TranscodingRequest.MediaFormatResolver setSourceVideoFormatHint(@NonNull android.media.MediaFormat);
-    method public boolean shouldTranscode();
-  }
-
-  public static final class MediaTranscodeManager.TranscodingSession {
-    method public void cancel();
-    method @IntRange(from=0, to=100) public int getProgress();
-    method public int getResult();
-    method public int getSessionId();
-    method public int getStatus();
-    method public void setOnProgressUpdateListener(@NonNull java.util.concurrent.Executor, @Nullable android.media.MediaTranscodeManager.TranscodingSession.OnProgressUpdateListener);
-    method public void setOnProgressUpdateListener(int, @NonNull java.util.concurrent.Executor, @Nullable android.media.MediaTranscodeManager.TranscodingSession.OnProgressUpdateListener);
-    field public static final int RESULT_CANCELED = 4; // 0x4
-    field public static final int RESULT_ERROR = 3; // 0x3
-    field public static final int RESULT_NONE = 1; // 0x1
-    field public static final int RESULT_SUCCESS = 2; // 0x2
-    field public static final int STATUS_FINISHED = 3; // 0x3
-    field public static final int STATUS_PAUSED = 4; // 0x4
-    field public static final int STATUS_PENDING = 1; // 0x1
-    field public static final int STATUS_RUNNING = 2; // 0x2
-  }
-
-  @java.lang.FunctionalInterface public static interface MediaTranscodeManager.TranscodingSession.OnProgressUpdateListener {
-    method public void onProgressUpdate(@NonNull android.media.MediaTranscodeManager.TranscodingSession, @IntRange(from=0, to=100) int);
-  }
-
   public class PlayerProxy {
     method public void pause();
     method public void setPan(float);
@@ -7670,12 +7608,14 @@
     method @NonNull @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public android.os.connectivity.WifiBatteryStats getWifiBatteryStats();
     method @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public void reportFullWifiLockAcquiredFromSource(@NonNull android.os.WorkSource);
     method @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public void reportFullWifiLockReleasedFromSource(@NonNull android.os.WorkSource);
+    method @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public void reportMobileRadioPowerState(boolean, int) throws java.lang.RuntimeException;
     method @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public void reportWifiBatchedScanStartedFromSource(@NonNull android.os.WorkSource, @IntRange(from=0) int);
     method @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public void reportWifiBatchedScanStoppedFromSource(@NonNull android.os.WorkSource);
     method @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public void reportWifiMulticastDisabled(@NonNull android.os.WorkSource);
     method @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public void reportWifiMulticastEnabled(@NonNull android.os.WorkSource);
     method @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public void reportWifiOff();
     method @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public void reportWifiOn();
+    method @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public void reportWifiRadioPowerState(boolean, int) throws java.lang.RuntimeException;
     method @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public void reportWifiRssiChanged(@IntRange(from=0xffffff81, to=0) int);
     method @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public void reportWifiScanStartedFromSource(@NonNull android.os.WorkSource);
     method @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public void reportWifiScanStoppedFromSource(@NonNull android.os.WorkSource);
@@ -8062,7 +8002,7 @@
     method @RequiresPermission(anyOf={android.Manifest.permission.RECOVERY, android.Manifest.permission.REBOOT}) public static void prepareForUnattendedUpdate(@NonNull android.content.Context, @NonNull String, @Nullable android.content.IntentSender) throws java.io.IOException;
     method @RequiresPermission(android.Manifest.permission.RECOVERY) public static void processPackage(android.content.Context, java.io.File, android.os.RecoverySystem.ProgressListener, android.os.Handler) throws java.io.IOException;
     method @RequiresPermission(android.Manifest.permission.RECOVERY) public static void processPackage(android.content.Context, java.io.File, android.os.RecoverySystem.ProgressListener) throws java.io.IOException;
-    method @RequiresPermission(anyOf={android.Manifest.permission.RECOVERY, android.Manifest.permission.REBOOT}) public static void rebootAndApply(@NonNull android.content.Context, @NonNull String, @NonNull String) throws java.io.IOException;
+    method @Deprecated @RequiresPermission(android.Manifest.permission.RECOVERY) public static void rebootAndApply(@NonNull android.content.Context, @NonNull String, @NonNull String) throws java.io.IOException;
     method @RequiresPermission(anyOf={android.Manifest.permission.RECOVERY, android.Manifest.permission.REBOOT}) public static void rebootAndApply(@NonNull android.content.Context, @NonNull String, boolean) throws java.io.IOException;
     method @RequiresPermission(allOf={android.Manifest.permission.RECOVERY, android.Manifest.permission.REBOOT}) public static void rebootWipeAb(android.content.Context, java.io.File, String) throws java.io.IOException;
     method @RequiresPermission(android.Manifest.permission.RECOVERY) public static void scheduleUpdateOnBoot(android.content.Context, java.io.File) throws java.io.IOException;
@@ -11527,6 +11467,7 @@
     method public int getPduSessionId();
     method public int getProtocolType();
     method public long getRetryDurationMillis();
+    method @Nullable public android.telephony.data.SliceInfo getSliceInfo();
     method @Deprecated public int getSuggestedRetryTime();
     method public void writeToParcel(android.os.Parcel, int);
     field @NonNull public static final android.os.Parcelable.Creator<android.telephony.data.DataCallResponse> CREATOR;
@@ -11561,6 +11502,7 @@
     method @NonNull public android.telephony.data.DataCallResponse.Builder setPduSessionId(int);
     method @NonNull public android.telephony.data.DataCallResponse.Builder setProtocolType(int);
     method @NonNull public android.telephony.data.DataCallResponse.Builder setRetryDurationMillis(long);
+    method @NonNull public android.telephony.data.DataCallResponse.Builder setSliceInfo(@Nullable android.telephony.data.SliceInfo);
     method @Deprecated @NonNull public android.telephony.data.DataCallResponse.Builder setSuggestedRetryTime(int);
   }
 
@@ -11633,7 +11575,7 @@
     method public void setDataProfile(@NonNull java.util.List<android.telephony.data.DataProfile>, boolean, @NonNull android.telephony.data.DataServiceCallback);
     method public void setInitialAttachApn(@NonNull android.telephony.data.DataProfile, boolean, @NonNull android.telephony.data.DataServiceCallback);
     method public void setupDataCall(int, @NonNull android.telephony.data.DataProfile, boolean, boolean, int, @Nullable android.net.LinkProperties, @NonNull android.telephony.data.DataServiceCallback);
-    method public void setupDataCall(int, @NonNull android.telephony.data.DataProfile, boolean, boolean, int, @Nullable android.net.LinkProperties, @IntRange(from=0, to=15) int, @NonNull android.telephony.data.DataServiceCallback);
+    method public void setupDataCall(int, @NonNull android.telephony.data.DataProfile, boolean, boolean, int, @Nullable android.net.LinkProperties, @IntRange(from=0, to=15) int, @Nullable android.telephony.data.SliceInfo, @NonNull android.telephony.data.DataServiceCallback);
     method public void startHandover(int, @NonNull android.telephony.data.DataServiceCallback);
   }
 
@@ -11668,6 +11610,32 @@
     method public final void updateQualifiedNetworkTypes(int, @NonNull java.util.List<java.lang.Integer>);
   }
 
+  public final class SliceInfo implements android.os.Parcelable {
+    method public int describeContents();
+    method @IntRange(from=android.telephony.data.SliceInfo.MIN_SLICE_DIFFERENTIATOR, to=android.telephony.data.SliceInfo.MAX_SLICE_DIFFERENTIATOR) public int getMappedHplmnSliceDifferentiator();
+    method public int getMappedHplmnSliceServiceType();
+    method @IntRange(from=android.telephony.data.SliceInfo.MIN_SLICE_DIFFERENTIATOR, to=android.telephony.data.SliceInfo.MAX_SLICE_DIFFERENTIATOR) public int getSliceDifferentiator();
+    method public int getSliceServiceType();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.telephony.data.SliceInfo> CREATOR;
+    field public static final int MAX_SLICE_DIFFERENTIATOR = 16777214; // 0xfffffe
+    field public static final int MIN_SLICE_DIFFERENTIATOR = -1; // 0xffffffff
+    field public static final int SLICE_DIFFERENTIATOR_NO_SLICE = -1; // 0xffffffff
+    field public static final int SLICE_SERVICE_TYPE_EMBB = 1; // 0x1
+    field public static final int SLICE_SERVICE_TYPE_MIOT = 3; // 0x3
+    field public static final int SLICE_SERVICE_TYPE_NONE = 0; // 0x0
+    field public static final int SLICE_SERVICE_TYPE_URLLC = 2; // 0x2
+  }
+
+  public static final class SliceInfo.Builder {
+    ctor public SliceInfo.Builder();
+    method @NonNull public android.telephony.data.SliceInfo build();
+    method @NonNull public android.telephony.data.SliceInfo.Builder setMappedHplmnSliceDifferentiator(@IntRange(from=android.telephony.data.SliceInfo.MIN_SLICE_DIFFERENTIATOR, to=android.telephony.data.SliceInfo.MAX_SLICE_DIFFERENTIATOR) int);
+    method @NonNull public android.telephony.data.SliceInfo.Builder setMappedHplmnSliceServiceType(int);
+    method @NonNull public android.telephony.data.SliceInfo.Builder setSliceDifferentiator(@IntRange(from=android.telephony.data.SliceInfo.MIN_SLICE_DIFFERENTIATOR, to=android.telephony.data.SliceInfo.MAX_SLICE_DIFFERENTIATOR) int);
+    method @NonNull public android.telephony.data.SliceInfo.Builder setSliceServiceType(int);
+  }
+
 }
 
 package android.telephony.euicc {
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index f51bb95..5b86e8d 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -381,11 +381,14 @@
     field public static final String ACTION_DATA_SHARING_RESTRICTION_APPLIED = "android.app.action.DATA_SHARING_RESTRICTION_APPLIED";
     field public static final int OPERATION_CREATE_AND_MANAGE_USER = 5; // 0x5
     field public static final int OPERATION_LOCK_NOW = 1; // 0x1
+    field public static final int OPERATION_LOGOUT_USER = 9; // 0x9
     field public static final int OPERATION_REBOOT = 7; // 0x7
     field public static final int OPERATION_REMOVE_USER = 6; // 0x6
+    field public static final int OPERATION_SET_USER_RESTRICTION = 10; // 0xa
     field public static final int OPERATION_START_USER_IN_BACKGROUND = 3; // 0x3
     field public static final int OPERATION_STOP_USER = 4; // 0x4
     field public static final int OPERATION_SWITCH_USER = 2; // 0x2
+    field public static final int OPERATION_WIPE_DATA = 8; // 0x8
   }
 
   public static final class SecurityLog.SecurityEvent implements android.os.Parcelable {
@@ -985,6 +988,7 @@
   }
 
   public class AudioManager {
+    method @Nullable public static android.media.AudioDeviceInfo getDeviceInfoFromType(int);
     method public boolean hasRegisteredDynamicPolicy();
   }
 
@@ -2457,6 +2461,13 @@
     field public static final int FEATURE_WINDOW_TOKENS = 2; // 0x2
   }
 
+  public final class StartingWindowInfo implements android.os.Parcelable {
+    ctor public StartingWindowInfo();
+    method public int describeContents();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.window.StartingWindowInfo> CREATOR;
+  }
+
   public final class TaskAppearedInfo implements android.os.Parcelable {
     ctor public TaskAppearedInfo(@NonNull android.app.ActivityManager.RunningTaskInfo, @NonNull android.view.SurfaceControl);
     method public int describeContents();
@@ -2468,7 +2479,7 @@
 
   public class TaskOrganizer extends android.window.WindowOrganizer {
     ctor public TaskOrganizer();
-    method @BinderThread public void addStartingWindow(@NonNull android.app.ActivityManager.RunningTaskInfo, @NonNull android.os.IBinder);
+    method @BinderThread public void addStartingWindow(@NonNull android.window.StartingWindowInfo, @NonNull android.os.IBinder);
     method @Nullable @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS) public void createRootTask(int, int, @Nullable android.os.IBinder);
     method @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS) public boolean deleteRootTask(@NonNull android.window.WindowContainerToken);
     method @Nullable @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS) public java.util.List<android.app.ActivityManager.RunningTaskInfo> getChildTasks(@NonNull android.window.WindowContainerToken, @NonNull int[]);
@@ -2479,7 +2490,7 @@
     method @BinderThread public void onTaskInfoChanged(@NonNull android.app.ActivityManager.RunningTaskInfo);
     method @BinderThread public void onTaskVanished(@NonNull android.app.ActivityManager.RunningTaskInfo);
     method @CallSuper @NonNull @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS) public java.util.List<android.window.TaskAppearedInfo> registerOrganizer();
-    method @BinderThread public void removeStartingWindow(@NonNull android.app.ActivityManager.RunningTaskInfo);
+    method @BinderThread public void removeStartingWindow(int);
     method @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS) public void setInterceptBackPressedOnTaskRoot(@NonNull android.window.WindowContainerToken, boolean);
     method @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS) public void setLaunchRoot(int, @NonNull android.window.WindowContainerToken);
     method @CallSuper @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS) public void unregisterOrganizer();
diff --git a/core/java/android/accessibilityservice/AccessibilityService.java b/core/java/android/accessibilityservice/AccessibilityService.java
index 8e50184..1fa7fa2 100644
--- a/core/java/android/accessibilityservice/AccessibilityService.java
+++ b/core/java/android/accessibilityservice/AccessibilityService.java
@@ -2120,6 +2120,10 @@
 
     /**
      * Sets the strokeWidth and color of the accessibility focus rectangle.
+     * <p>
+     * <strong>Note:</strong> This setting persists until this or another active
+     * AccessibilityService changes it or the device reboots.
+     * </p>
      *
      * @param strokeWidth The stroke width of the rectangle in pixels.
      *                    Setting this value to zero results in no focus rectangle being drawn.
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 6d564a3..69482bc 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -90,6 +90,7 @@
 import android.hardware.display.DisplayManagerGlobal;
 import android.inputmethodservice.InputMethodService;
 import android.media.MediaFrameworkInitializer;
+import android.media.MediaFrameworkPlatformInitializer;
 import android.media.MediaServiceManager;
 import android.net.ConnectivityManager;
 import android.net.IConnectivityManager;
@@ -492,6 +493,11 @@
 
     Bundle mCoreSettings = null;
 
+    /**
+     * The lock word for the {@link #mCoreSettings}.
+     */
+    private final Object mCoreSettingsLock = new Object();
+
     boolean mHasImeComponent = false;
 
     /** Activity client record, used for bookkeeping for the real {@link Activity} instance. */
@@ -4955,7 +4961,7 @@
     }
 
     private void handleSetCoreSettings(Bundle coreSettings) {
-        synchronized (mResourcesManager) {
+        synchronized (mCoreSettingsLock) {
             mCoreSettings = coreSettings;
         }
         onCoreSettingsChange();
@@ -4971,6 +4977,8 @@
     private boolean updateDebugViewAttributeState() {
         boolean previousState = View.sDebugViewAttributes;
 
+        // mCoreSettings is only updated from the main thread, while this function is only called
+        // from main thread as well, so no need to lock here.
         View.sDebugViewAttributesApplicationPackage = mCoreSettings.getString(
                 Settings.Global.DEBUG_VIEW_ATTRIBUTES_APPLICATION_PACKAGE, "");
         String currentPackage = (mBoundApplication != null && mBoundApplication.appInfo != null)
@@ -6267,6 +6275,8 @@
             }
         }
 
+        // mCoreSettings is only updated from the main thread, while this function is only called
+        // from main thread as well, so no need to lock here.
         GraphicsEnvironment.getInstance().setup(context, mCoreSettings);
         Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
     }
@@ -6448,6 +6458,8 @@
         }
         updateDefaultDensity();
 
+        // mCoreSettings is only updated from the main thread, while this function is only called
+        // from main thread as well, so no need to lock here.
         final String use24HourSetting = mCoreSettings.getString(Settings.System.TIME_12_24);
         Boolean is24Hr = null;
         if (use24HourSetting != null) {
@@ -7468,12 +7480,17 @@
         }
     }
 
-    public Bundle getCoreSettings() {
-        return mCoreSettings;
+    /**
+     * Caller should NEVER mutate the Bundle returned from here
+     */
+    Bundle getCoreSettings() {
+        synchronized (mCoreSettingsLock) {
+            return mCoreSettings;
+        }
     }
 
     public int getIntCoreSetting(String key, int defaultValue) {
-        synchronized (mResourcesManager) {
+        synchronized (mCoreSettingsLock) {
             if (mCoreSettings != null) {
                 return mCoreSettings.getInt(key, defaultValue);
             }
@@ -7485,7 +7502,7 @@
      * Get the string value of the given key from core settings.
      */
     public String getStringCoreSetting(String key, String defaultValue) {
-        synchronized (mResourcesManager) {
+        synchronized (mCoreSettingsLock) {
             if (mCoreSettings != null) {
                 return mCoreSettings.getString(key, defaultValue);
             }
@@ -7494,7 +7511,7 @@
     }
 
     float getFloatCoreSetting(String key, float defaultValue) {
-        synchronized (mResourcesManager) {
+        synchronized (mCoreSettingsLock) {
             if (mCoreSettings != null) {
                 return mCoreSettings.getFloat(key, defaultValue);
             }
@@ -7701,6 +7718,7 @@
     public static void initializeMainlineModules() {
         TelephonyFrameworkInitializer.setTelephonyServiceManager(new TelephonyServiceManager());
         StatsFrameworkInitializer.setStatsServiceManager(new StatsServiceManager());
+        MediaFrameworkPlatformInitializer.setMediaServiceManager(new MediaServiceManager());
         MediaFrameworkInitializer.setMediaServiceManager(new MediaServiceManager());
     }
 
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index 124cf71..700d8ff 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -2468,8 +2468,9 @@
         return context;
     }
 
+    @NonNull
     @Override
-    public @NonNull WindowContext createWindowContext(int type, Bundle options) {
+    public WindowContext createWindowContext(int type, @NonNull Bundle options) {
         if (getDisplay() == null) {
             throw new UnsupportedOperationException("WindowContext can only be created from "
                     + "other visual contexts, such as Activity or one created with "
@@ -2478,13 +2479,26 @@
         return new WindowContext(this, type, options);
     }
 
-    ContextImpl createBaseWindowContext(IBinder token) {
+    @NonNull
+    @Override
+    public WindowContext createWindowContext(@NonNull Display display, int type,
+            @NonNull Bundle options) {
+        if (display == null) {
+            throw new IllegalArgumentException("Display must not be null");
+        }
+        return new WindowContext(this, display, type, options);
+    }
+
+    ContextImpl createBaseWindowContext(IBinder token, Display display) {
         ContextImpl context = new ContextImpl(this, mMainThread, mPackageInfo, mAttributionTag,
                 mSplitName, token, mUser, mFlags, mClassLoader, null);
         // Window contexts receive configurations directly from the server and as such do not
         // need to override their display in ResourcesManager.
         context.mForceDisplayOverrideInResources = false;
         context.mContextType = CONTEXT_TYPE_WINDOW_CONTEXT;
+        if (display != null) {
+            context.mDisplay = display;
+        }
         return context;
     }
 
diff --git a/core/java/android/app/IActivityTaskManager.aidl b/core/java/android/app/IActivityTaskManager.aidl
index 1ac0a65..523c155 100644
--- a/core/java/android/app/IActivityTaskManager.aidl
+++ b/core/java/android/app/IActivityTaskManager.aidl
@@ -191,7 +191,7 @@
      */
     IBinder requestStartActivityPermissionToken(in IBinder delegatorToken);
 
-    void releaseSomeActivities(in IApplicationThread app);
+    oneway void releaseSomeActivities(in IApplicationThread app);
     Bitmap getTaskDescriptionIcon(in String filename, int userId);
     void registerTaskStackListener(in ITaskStackListener listener);
     void unregisterTaskStackListener(in ITaskStackListener listener);
diff --git a/core/java/android/app/LoadedApk.java b/core/java/android/app/LoadedApk.java
index 99785e1..50853a3 100644
--- a/core/java/android/app/LoadedApk.java
+++ b/core/java/android/app/LoadedApk.java
@@ -729,6 +729,23 @@
         }
     }
 
+    private StrictMode.VmPolicy allowVmViolations() {
+        if (mActivityThread == null) {
+            // When LoadedApk is used without an ActivityThread (usually in a
+            // zygote context), don't call into StrictMode, as it initializes
+            // the binder subsystem, which we don't want.
+            return null;
+        }
+
+        return StrictMode.allowVmViolations();
+    }
+
+    private void setVmPolicy(StrictMode.VmPolicy policy) {
+        if (mActivityThread != null && policy != null) {
+            StrictMode.setVmPolicy(policy);
+        }
+    }
+
     private void createOrUpdateClassLoaderLocked(List<String> addedPaths) {
         if (mPackageName.equals("android")) {
             // Note: This branch is taken for system server and we don't need to setup
@@ -984,13 +1001,20 @@
 
         // Temporarily disable logging of disk reads on the Looper thread as this is necessary -
         // and the loader will access the directory anyway if we don't check it.
-        StrictMode.ThreadPolicy oldPolicy = allowThreadDiskReads();
+        StrictMode.ThreadPolicy oldThreadPolicy = allowThreadDiskReads();
+
+        // Also disable logging of access to /data/user before CE storage is unlocked. The check
+        // below will return false (because the directory name we pass will not match the
+        // encrypted one), but that's correct.
+        StrictMode.VmPolicy oldVmPolicy = allowVmViolations();
+
         try {
             // We are constructing a classloader for a different package. It is likely,
             // but not certain, that we can't acccess its app data dir - so check.
             return new File(mDataDir).canExecute();
         } finally {
-            setThreadPolicy(oldPolicy);
+            setThreadPolicy(oldThreadPolicy);
+            setVmPolicy(oldVmPolicy);
         }
     }
 
diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
index 4afbfbf..48d2dfe 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -104,8 +104,8 @@
 import android.location.LocationManager;
 import android.media.AudioManager;
 import android.media.MediaFrameworkInitializer;
+import android.media.MediaFrameworkPlatformInitializer;
 import android.media.MediaRouter;
-import android.media.MediaTranscodeManager;
 import android.media.midi.IMidiManager;
 import android.media.midi.MidiManager;
 import android.media.musicrecognition.IMusicRecognitionManager;
@@ -312,15 +312,6 @@
                 return new AudioManager(ctx);
             }});
 
-        registerService(Context.MEDIA_TRANSCODING_SERVICE, MediaTranscodeManager.class,
-                new CachedServiceFetcher<MediaTranscodeManager>() {
-                    @Override
-                    public MediaTranscodeManager createService(ContextImpl ctx)
-                            throws ServiceNotFoundException {
-                        return new MediaTranscodeManager(ctx);
-                    }
-                });
-
         registerService(Context.MEDIA_ROUTER_SERVICE, MediaRouter.class,
                 new CachedServiceFetcher<MediaRouter>() {
             @Override
@@ -1401,6 +1392,7 @@
             WifiFrameworkInitializer.registerServiceWrappers();
             StatsFrameworkInitializer.registerServiceWrappers();
             RollbackManagerFrameworkInitializer.initialize();
+            MediaFrameworkPlatformInitializer.registerServiceWrappers();
             MediaFrameworkInitializer.registerServiceWrappers();
         } finally {
             // If any of the above code throws, we're in a pretty bad shape and the process
diff --git a/core/java/android/app/WindowContext.java b/core/java/android/app/WindowContext.java
index 5f72bac..14ed414 100644
--- a/core/java/android/app/WindowContext.java
+++ b/core/java/android/app/WindowContext.java
@@ -26,6 +26,7 @@
 import android.os.Bundle;
 import android.os.IBinder;
 import android.os.RemoteException;
+import android.view.Display;
 import android.view.IWindowManager;
 import android.view.WindowManagerGlobal;
 import android.view.WindowManagerImpl;
@@ -59,13 +60,27 @@
      * @hide
      */
     public WindowContext(@NonNull Context base, int type, @Nullable Bundle options) {
+        this(base, null /* display */, type, options);
+    }
+
+    /**
+     * Default constructor. Will generate a {@link WindowTokenClient} and attach this context to
+     * the token.
+     *
+     * @param base Base {@link Context} for this new instance.
+     * @param display the {@link Display} to override.
+     * @param type Window type to be used with this context.
+     * @hide
+     */
+    public WindowContext(@NonNull Context base, @Nullable Display display, int type,
+            @Nullable Bundle options) {
         // Correct base context will be built once the token is resolved, so passing 'null' here.
         super(null /* base */);
 
         mWms = WindowManagerGlobal.getWindowManagerService();
         mToken = new WindowTokenClient();
 
-        final ContextImpl contextImpl = createBaseWindowContext(base, mToken);
+        final ContextImpl contextImpl = createBaseWindowContext(base, mToken, display);
         attachBaseContext(contextImpl);
         contextImpl.setOuterContext(this);
 
@@ -93,9 +108,10 @@
         Reference.reachabilityFence(this);
     }
 
-    private static ContextImpl createBaseWindowContext(Context outer, IBinder token) {
+    private static ContextImpl createBaseWindowContext(Context outer, IBinder token,
+            Display display) {
         final ContextImpl contextImpl = ContextImpl.getImpl(outer);
-        return contextImpl.createBaseWindowContext(token);
+        return contextImpl.createBaseWindowContext(token, display);
     }
 
     @Override
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 2a79c72..a154396 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -54,7 +54,6 @@
 import android.content.pm.ParceledListSlice;
 import android.content.pm.UserInfo;
 import android.graphics.Bitmap;
-import android.net.NetworkUtils;
 import android.net.PrivateDnsConnectivityChecker;
 import android.net.ProxyInfo;
 import android.net.Uri;
@@ -92,6 +91,7 @@
 import android.util.Log;
 
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.net.NetworkUtilsInternal;
 import com.android.internal.os.BackgroundThread;
 import com.android.internal.util.Preconditions;
 import com.android.org.conscrypt.TrustedCertificateStore;
@@ -2615,6 +2615,15 @@
     /** @hide */
     @TestApi
     public static final int OPERATION_REBOOT = 7;
+    /** @hide */
+    @TestApi
+    public static final int OPERATION_WIPE_DATA = 8;
+    /** @hide */
+    @TestApi
+    public static final int OPERATION_LOGOUT_USER = 9;
+    /** @hide */
+    @TestApi
+    public static final int OPERATION_SET_USER_RESTRICTION = 10;
 
     private static final String PREFIX_OPERATION = "OPERATION_";
 
@@ -2626,7 +2635,10 @@
             OPERATION_STOP_USER,
             OPERATION_CREATE_AND_MANAGE_USER,
             OPERATION_REMOVE_USER,
-            OPERATION_REBOOT
+            OPERATION_REBOOT,
+            OPERATION_WIPE_DATA,
+            OPERATION_LOGOUT_USER,
+            OPERATION_SET_USER_RESTRICTION
     })
     @Retention(RetentionPolicy.SOURCE)
     public static @interface DevicePolicyOperation {
@@ -11973,7 +11985,7 @@
             return PRIVATE_DNS_SET_ERROR_FAILURE_SETTING;
         }
 
-        if (NetworkUtils.isWeaklyValidatedHostname(privateDnsHost)) {
+        if (NetworkUtilsInternal.isWeaklyValidatedHostname(privateDnsHost)) {
             if (!PrivateDnsConnectivityChecker.canConnectToPrivateDnsServer(privateDnsHost)) {
                 return PRIVATE_DNS_SET_ERROR_HOST_NOT_SERVING;
             }
@@ -12677,21 +12689,4 @@
             }
         }
     }
-
-    // TODO(b/175392542): remove if not needed by ManagedProvisioning app anymore
-    /**
-     * Used by ManagedProvisioning app to factory reset the device when DO cannto be provisioned.
-     *
-     * @hide
-     */
-    @RequiresPermission(android.Manifest.permission.MASTER_CLEAR)
-    public void factoryReset(String reason) {
-        if (mService != null) {
-            try {
-                mService.factoryReset(reason);
-            } catch (RemoteException re) {
-                throw re.rethrowFromSystemServer();
-            }
-        }
-    }
 }
diff --git a/core/java/android/app/admin/DevicePolicyManagerInternal.java b/core/java/android/app/admin/DevicePolicyManagerInternal.java
index a0d2977..ce2fd4f 100644
--- a/core/java/android/app/admin/DevicePolicyManagerInternal.java
+++ b/core/java/android/app/admin/DevicePolicyManagerInternal.java
@@ -231,13 +231,7 @@
      * Returns the profile owner component for the given user, or {@code null} if there is not one.
      */
     @Nullable
-    public abstract ComponentName getProfileOwnerAsUser(@UserIdInt int userId);
-
-    /**
-     * Returns the user id of the device owner, or {@link UserHandle#USER_NULL} if there is not one.
-     */
-    @UserIdInt
-    public abstract int getDeviceOwnerUserId();
+    public abstract ComponentName getProfileOwnerAsUser(int userHandle);
 
     /**
      * Returns whether the given package is a device owner or a profile owner in the calling user.
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index a81b506..bcc90f7 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -488,6 +488,4 @@
     boolean canProfileOwnerResetPasswordWhenLocked(int userId);
 
     void setNextOperationSafety(int operation, boolean safe);
-    // TODO(b/175392542): remove if not needed by ManagedProvisioning app anymore
-    void factoryReset(String reason);
 }
diff --git a/core/java/android/app/people/PeopleSpaceTile.java b/core/java/android/app/people/PeopleSpaceTile.java
index f60e42f..95739f3 100644
--- a/core/java/android/app/people/PeopleSpaceTile.java
+++ b/core/java/android/app/people/PeopleSpaceTile.java
@@ -17,6 +17,7 @@
 package android.app.people;
 
 import android.annotation.NonNull;
+import android.app.Person;
 import android.content.Intent;
 import android.content.pm.LauncherApps;
 import android.content.pm.ShortcutInfo;
@@ -44,6 +45,7 @@
     private int mUid;
     private Uri mContactUri;
     private String mPackageName;
+    private String mStatusText;
     private long mLastInteractionTimestamp;
     private boolean mIsImportantConversation;
     private boolean mIsHiddenConversation;
@@ -61,6 +63,7 @@
         mContactUri = b.mContactUri;
         mUid = b.mUid;
         mPackageName = b.mPackageName;
+        mStatusText = b.mStatusText;
         mLastInteractionTimestamp = b.mLastInteractionTimestamp;
         mIsImportantConversation = b.mIsImportantConversation;
         mIsHiddenConversation = b.mIsHiddenConversation;
@@ -95,6 +98,10 @@
         return mPackageName;
     }
 
+    public String getStatusText() {
+        return mStatusText;
+    }
+
     /** Returns the timestamp of the last interaction. */
     public long getLastInteractionTimestamp() {
         return mLastInteractionTimestamp;
@@ -148,6 +155,7 @@
         builder.setContactUri(mContactUri);
         builder.setUid(mUid);
         builder.setPackageName(mPackageName);
+        builder.setStatusText(mStatusText);
         builder.setLastInteractionTimestamp(mLastInteractionTimestamp);
         builder.setIsImportantConversation(mIsImportantConversation);
         builder.setIsHiddenConversation(mIsHiddenConversation);
@@ -165,6 +173,7 @@
         private Uri mContactUri;
         private int mUid;
         private String mPackageName;
+        private String mStatusText;
         private long mLastInteractionTimestamp;
         private boolean mIsImportantConversation;
         private boolean mIsHiddenConversation;
@@ -188,6 +197,16 @@
             mUserIcon = convertDrawableToIcon(launcherApps.getShortcutIconDrawable(info, 0));
             mUid = info.getUserId();
             mPackageName = info.getPackage();
+            mContactUri = getContactUri(info);
+        }
+
+        private Uri getContactUri(ShortcutInfo info) {
+            if (info.getPersons() == null || info.getPersons().length != 1) {
+                return null;
+            }
+            // TODO(b/175584929): Update to use the Uri from PeopleService directly
+            Person person = info.getPersons()[0];
+            return person.getUri() == null ? null : Uri.parse(person.getUri());
         }
 
         /** Sets the ID for the tile. */
@@ -226,6 +245,12 @@
             return this;
         }
 
+        /** Sets the status text. */
+        public Builder setStatusText(String statusText) {
+            mStatusText = statusText;
+            return this;
+        }
+
         /** Sets the last interaction timestamp. */
         public Builder setLastInteractionTimestamp(long lastInteractionTimestamp) {
             mLastInteractionTimestamp = lastInteractionTimestamp;
@@ -279,8 +304,10 @@
         mId = in.readString();
         mUserName = in.readCharSequence();
         mUserIcon = in.readParcelable(Icon.class.getClassLoader());
+        mContactUri = in.readParcelable(Uri.class.getClassLoader());
         mUid = in.readInt();
         mPackageName = in.readString();
+        mStatusText = in.readString();
         mLastInteractionTimestamp = in.readLong();
         mIsImportantConversation = in.readBoolean();
         mIsHiddenConversation = in.readBoolean();
@@ -300,8 +327,10 @@
         dest.writeString(mId);
         dest.writeCharSequence(mUserName);
         dest.writeParcelable(mUserIcon, flags);
+        dest.writeParcelable(mContactUri, flags);
         dest.writeInt(mUid);
         dest.writeString(mPackageName);
+        dest.writeString(mStatusText);
         dest.writeLong(mLastInteractionTimestamp);
         dest.writeBoolean(mIsImportantConversation);
         dest.writeBoolean(mIsHiddenConversation);
diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java
index 1713a0c..406fe8d 100644
--- a/core/java/android/bluetooth/BluetoothAdapter.java
+++ b/core/java/android/bluetooth/BluetoothAdapter.java
@@ -2967,6 +2967,16 @@
                             }
                         });
                     }
+                    synchronized (mBluetoothConnectionCallbackExecutorMap) {
+                        if (!mBluetoothConnectionCallbackExecutorMap.isEmpty()) {
+                            try {
+                                mService.registerBluetoothConnectionCallback(mConnectionCallback);
+                            } catch (RemoteException e) {
+                                Log.e(TAG, "onBluetoothServiceUp: Failed to register bluetooth"
+                                        + "connection callback", e);
+                            }
+                        }
+                    }
                 }
 
                 public void onBluetoothServiceDown() {
@@ -3616,25 +3626,25 @@
             return false;
         }
 
-        // If the callback map is empty, we register the service-to-app callback
-        if (mBluetoothConnectionCallbackExecutorMap.isEmpty()) {
-            try {
-                mServiceLock.readLock().lock();
-                if (mService != null) {
-                    if (!mService.registerBluetoothConnectionCallback(mConnectionCallback)) {
-                        return false;
-                    }
-                }
-            } catch (RemoteException e) {
-                Log.e(TAG, "", e);
-                mBluetoothConnectionCallbackExecutorMap.remove(callback);
-            } finally {
-                mServiceLock.readLock().unlock();
-            }
-        }
-
-        // Adds the passed in callback to our map of callbacks to executors
         synchronized (mBluetoothConnectionCallbackExecutorMap) {
+            // If the callback map is empty, we register the service-to-app callback
+            if (mBluetoothConnectionCallbackExecutorMap.isEmpty()) {
+                try {
+                    mServiceLock.readLock().lock();
+                    if (mService != null) {
+                        if (!mService.registerBluetoothConnectionCallback(mConnectionCallback)) {
+                            return false;
+                        }
+                    }
+                } catch (RemoteException e) {
+                    Log.e(TAG, "", e);
+                    mBluetoothConnectionCallbackExecutorMap.remove(callback);
+                } finally {
+                    mServiceLock.readLock().unlock();
+                }
+            }
+
+            // Adds the passed in callback to our map of callbacks to executors
             if (mBluetoothConnectionCallbackExecutorMap.containsKey(callback)) {
                 throw new IllegalArgumentException("This callback has already been registered");
             }
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index ac576a8..abe7fda 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -5989,22 +5989,22 @@
      * Creating a window context is an expensive operation. Misuse of this API may lead to a huge
      * performance drop. The best practice is to use the same window context when possible.
      * An approach is to create one window context with specific window type and display and
-     * use it everywhere it's needed..
+     * use it everywhere it's needed.
      * </p>
      *
      * @param type Window type in {@link WindowManager.LayoutParams}
-     * @param options Bundle used to pass window-related options.
-     * @return A {@link Context} that can be used to create windows.
-     * @throws UnsupportedOperationException if this is called on a non-UI context, such as
-     *         {@link android.app.Application Application} or {@link android.app.Service Service}.
+     * @param options A bundle used to pass window-related options
+     * @return A {@link Context} that can be used to create
+     *         non-{@link android.app.Activity activity} windows.
      *
      * @see #getSystemService(String)
      * @see #getSystemService(Class)
      * @see #WINDOW_SERVICE
      * @see #LAYOUT_INFLATER_SERVICE
      * @see #WALLPAPER_SERVICE
-     * @throws UnsupportedOperationException if this {@link Context} does not attach to a display or
-     * the current number of window contexts without adding any view by
+     * @throws UnsupportedOperationException if this {@link Context} does not attach to a display,
+     * such as {@link android.app.Application Application} or {@link android.app.Service Service},
+     * or the current number of window contexts without adding any view by
      * {@link WindowManager#addView} <b>exceeds five</b>.
      */
     @UiContext
@@ -6014,6 +6014,32 @@
     }
 
     /**
+     * A special version of {@link #createWindowContext(int, Bundle)} which also takes
+     * {@link Display}. The only difference between this API and
+     * {@link #createWindowContext(int, Bundle)} is that this API can create window context from
+     * any context even if the context which is not associated to a {@link Display} instance.
+     *
+     * @param display The {@link Display} to associate with
+     * @param type Window type in {@link WindowManager.LayoutParams}
+     * @param options A bundle used to pass window-related options.
+     * @return A {@link Context} that can be used to create
+     *         non-{@link android.app.Activity activity} windows.
+     * @throws IllegalArgumentException if the {@link Display} is {@code null}.
+     *
+     * @see #getSystemService(String)
+     * @see #getSystemService(Class)
+     * @see #WINDOW_SERVICE
+     * @see #LAYOUT_INFLATER_SERVICE
+     * @see #WALLPAPER_SERVICE
+     */
+    @UiContext
+    @NonNull
+    public Context createWindowContext(@NonNull Display display, @WindowType int type,
+            @Nullable Bundle options) {
+        throw new RuntimeException("Not implemented. Must override in a subclass.");
+    }
+
+    /**
      * Return a new Context object for the current Context but attribute to a different tag.
      * In complex apps attribution tagging can be used to distinguish between separate logical
      * parts.
diff --git a/core/java/android/content/ContextWrapper.java b/core/java/android/content/ContextWrapper.java
index 56da3cb..e450c08 100644
--- a/core/java/android/content/ContextWrapper.java
+++ b/core/java/android/content/ContextWrapper.java
@@ -988,6 +988,13 @@
     }
 
     @Override
+    @NonNull
+    public Context createWindowContext(@NonNull Display display, @WindowType int type,
+            @Nullable Bundle options) {
+        return mBase.createWindowContext(display, type, options);
+    }
+
+    @Override
     public @NonNull Context createAttributionContext(@Nullable String attributionTag) {
         return mBase.createAttributionContext(attributionTag);
     }
diff --git a/core/java/android/content/res/ApkAssets.java b/core/java/android/content/res/ApkAssets.java
index f5e1719..2d381eb 100644
--- a/core/java/android/content/res/ApkAssets.java
+++ b/core/java/android/content/res/ApkAssets.java
@@ -25,6 +25,8 @@
 
 import com.android.internal.annotations.GuardedBy;
 
+import libcore.util.NativeAllocationRegistry;
+
 import java.io.FileDescriptor;
 import java.io.IOException;
 import java.lang.annotation.Retention;
@@ -101,11 +103,11 @@
     public @interface FormatType {}
 
     @GuardedBy("this")
-    private long mNativePtr;  // final, except cleared in finalizer.
+    private final long mNativePtr;
 
     @Nullable
     @GuardedBy("this")
-    private final StringBlock mStringBlock;  // null or closed if mNativePtr = 0.
+    private final StringBlock mStringBlock;
 
     @PropertyFlags
     private final int mFlags;
@@ -113,6 +115,19 @@
     @Nullable
     private final AssetsProvider mAssets;
 
+    @GuardedBy("this")
+    @Nullable
+    private final Runnable mRunNativeCleanup;
+
+    // Use a Holder to allow static initialization of ApkAssets in the boot image, and
+    // possibly to avoid some initialization ordering issues.
+    private static class NoImagePreloadHolder {
+        // TODO(175425996): Make size estimate more accurate
+        public static final NativeAllocationRegistry REGISTRY =
+                NativeAllocationRegistry.createMalloced(ApkAssets.class.getClassLoader(),
+                                                        nativeGetFinalizer());
+    }
+
     /**
      * Creates a new ApkAssets instance from the given path on disk.
      *
@@ -287,6 +302,8 @@
         mFlags = flags;
         mNativePtr = nativeLoad(format, path, flags, assets);
         mStringBlock = new StringBlock(nativeGetStringBlock(mNativePtr), true /*useSparse*/);
+        mRunNativeCleanup = NoImagePreloadHolder.REGISTRY.registerNativeAllocation(
+                this, mNativePtr);
         mAssets = assets;
     }
 
@@ -298,6 +315,8 @@
         mFlags = flags;
         mNativePtr = nativeLoadFd(format, fd, friendlyName, flags, assets);
         mStringBlock = new StringBlock(nativeGetStringBlock(mNativePtr), true /*useSparse*/);
+        mRunNativeCleanup = NoImagePreloadHolder.REGISTRY.registerNativeAllocation(
+                this, mNativePtr);
         mAssets = assets;
     }
 
@@ -309,6 +328,8 @@
         mFlags = flags;
         mNativePtr = nativeLoadFdOffsets(format, fd, friendlyName, offset, length, flags, assets);
         mStringBlock = new StringBlock(nativeGetStringBlock(mNativePtr), true /*useSparse*/);
+        mRunNativeCleanup = NoImagePreloadHolder.REGISTRY.registerNativeAllocation(
+                this, mNativePtr);
         mAssets = assets;
     }
 
@@ -316,6 +337,7 @@
         mFlags = flags;
         mNativePtr = nativeLoadEmpty(flags, assets);
         mStringBlock = null;
+        mRunNativeCleanup = null;
         mAssets = assets;
     }
 
@@ -403,22 +425,16 @@
         return "ApkAssets{path=" + getAssetPath() + "}";
     }
 
-    @Override
-    protected void finalize() throws Throwable {
-        close();
-    }
-
     /**
      * Closes this class and the contained {@link #mStringBlock}.
      */
     public void close() {
         synchronized (this) {
-            if (mNativePtr != 0) {
-                if (mStringBlock != null) {
-                    mStringBlock.close();
-                }
-                nativeDestroy(mNativePtr);
-                mNativePtr = 0;
+            if (mStringBlock != null) {
+                mStringBlock.close();
+            }
+            if (mRunNativeCleanup != null) {
+                mRunNativeCleanup.run();
             }
         }
     }
@@ -433,7 +449,6 @@
     private static native long nativeLoadFdOffsets(@FormatType int format,
             @NonNull FileDescriptor fd, @NonNull String friendlyName, long offset, long length,
             @PropertyFlags int flags, @Nullable AssetsProvider asset) throws IOException;
-    private static native void nativeDestroy(long ptr);
     private static native @NonNull String nativeGetAssetPath(long ptr);
     private static native long nativeGetStringBlock(long ptr);
     private static native boolean nativeIsUpToDate(long ptr);
@@ -441,4 +456,5 @@
     private static native @Nullable OverlayableInfo nativeGetOverlayableInfo(long ptr,
             String overlayableName) throws IOException;
     private static native boolean nativeDefinesOverlayable(long ptr) throws IOException;
+    private static native final long nativeGetFinalizer();
 }
diff --git a/core/java/android/hardware/Sensor.java b/core/java/android/hardware/Sensor.java
index e913986..f7c4c2c 100644
--- a/core/java/android/hardware/Sensor.java
+++ b/core/java/android/hardware/Sensor.java
@@ -19,6 +19,7 @@
 
 import android.annotation.SystemApi;
 import android.compat.annotation.UnsupportedAppUsage;
+import android.hardware.input.InputSensorInfo;
 import android.os.Build;
 
 /**
@@ -923,6 +924,30 @@
     }
 
     /**
+     * Construct a sensor object from SensorInfo of an input device.
+     * This is only used for constructing an input device sensor object.
+     * @hide
+     */
+    public Sensor(InputSensorInfo sensorInfo) {
+        this.mName = sensorInfo.getName();
+        this.mVendor = sensorInfo.getVendor();
+        this.mVersion = sensorInfo.getVersion();
+        this.mHandle = sensorInfo.getHandle();
+        this.mType = sensorInfo.getType();
+        this.mMaxRange = sensorInfo.getMaxRange();
+        this.mResolution = sensorInfo.getResolution();
+        this.mPower = sensorInfo.getPower();
+        this.mMinDelay = sensorInfo.getMinDelay();
+        this.mFifoReservedEventCount = sensorInfo.getFifoReservedEventCount();
+        this.mFifoMaxEventCount = sensorInfo.getFifoMaxEventCount();
+        this.mStringType = sensorInfo.getStringType();
+        this.mRequiredPermission = sensorInfo.getRequiredPermission();
+        this.mMaxDelay = sensorInfo.getMaxDelay();
+        this.mFlags = sensorInfo.getFlags();
+        this.mId = sensorInfo.getId();
+    }
+
+    /**
      * @return name string of the sensor.
      */
     public String getName() {
diff --git a/core/java/android/hardware/SensorEvent.java b/core/java/android/hardware/SensorEvent.java
index 236fab0..232f234 100644
--- a/core/java/android/hardware/SensorEvent.java
+++ b/core/java/android/hardware/SensorEvent.java
@@ -16,6 +16,7 @@
 
 package android.hardware;
 
+import android.annotation.NonNull;
 import android.compat.annotation.UnsupportedAppUsage;
 
 /**
@@ -667,4 +668,16 @@
     SensorEvent(int valueSize) {
         values = new float[valueSize];
     }
+
+    /**
+     * Construct a sensor event object by sensor object, accuracy, timestamp and values.
+     * This is only used for constructing an input device sensor event object.
+     * @hide
+     */
+    public SensorEvent(@NonNull Sensor sensor, int accuracy, long timestamp, float[] values) {
+        this.sensor = sensor;
+        this.accuracy = accuracy;
+        this.timestamp = timestamp;
+        this.values = values;
+    }
 }
diff --git a/core/java/android/hardware/hdmi/HdmiControlManager.java b/core/java/android/hardware/hdmi/HdmiControlManager.java
index 3a73de6..43f04cd 100644
--- a/core/java/android/hardware/hdmi/HdmiControlManager.java
+++ b/core/java/android/hardware/hdmi/HdmiControlManager.java
@@ -848,6 +848,20 @@
     }
 
     /**
+     * Determines whether the HDMI CEC stack should handle KEYCODE_TV_POWER.
+     *
+     * @hide
+     */
+    @RequiresPermission(android.Manifest.permission.HDMI_CEC)
+    public boolean shouldHandleTvPowerKey() {
+        try {
+            return mService.shouldHandleTvPowerKey();
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
      * Controls whether volume control commands via HDMI CEC are enabled.
      *
      * <p>When disabled:
diff --git a/core/java/android/hardware/hdmi/HdmiControlServiceWrapper.java b/core/java/android/hardware/hdmi/HdmiControlServiceWrapper.java
index 202e090..3b61911f 100644
--- a/core/java/android/hardware/hdmi/HdmiControlServiceWrapper.java
+++ b/core/java/android/hardware/hdmi/HdmiControlServiceWrapper.java
@@ -72,6 +72,11 @@
         }
 
         @Override
+        public boolean shouldHandleTvPowerKey() {
+            return HdmiControlServiceWrapper.this.shouldHandleTvPowerKey();
+        }
+
+        @Override
         public void queryDisplayStatus(IHdmiControlCallback callback) {
             HdmiControlServiceWrapper.this.queryDisplayStatus(callback);
         }
@@ -368,6 +373,11 @@
     public void toggleAndFollowTvPower() {}
 
     /** @hide */
+    public boolean shouldHandleTvPowerKey() {
+        return true;
+    }
+
+    /** @hide */
     public void queryDisplayStatus(IHdmiControlCallback callback) {}
 
     /** @hide */
diff --git a/core/java/android/hardware/hdmi/IHdmiControlService.aidl b/core/java/android/hardware/hdmi/IHdmiControlService.aidl
index 6d0c688..65bd856 100644
--- a/core/java/android/hardware/hdmi/IHdmiControlService.aidl
+++ b/core/java/android/hardware/hdmi/IHdmiControlService.aidl
@@ -43,6 +43,7 @@
     HdmiDeviceInfo getActiveSource();
     void oneTouchPlay(IHdmiControlCallback callback);
     void toggleAndFollowTvPower();
+    boolean shouldHandleTvPowerKey();
     void queryDisplayStatus(IHdmiControlCallback callback);
     void addHdmiControlStatusChangeListener(IHdmiControlStatusChangeListener listener);
     void removeHdmiControlStatusChangeListener(IHdmiControlStatusChangeListener listener);
diff --git a/core/java/android/hardware/input/IInputManager.aidl b/core/java/android/hardware/input/IInputManager.aidl
index 3f3c3bf..b39df4d 100644
--- a/core/java/android/hardware/input/IInputManager.aidl
+++ b/core/java/android/hardware/input/IInputManager.aidl
@@ -23,6 +23,8 @@
 import android.hardware.input.ITabletModeChangedListener;
 import android.hardware.input.TouchCalibration;
 import android.os.CombinedVibrationEffect;
+import android.hardware.input.IInputSensorEventListener;
+import android.hardware.input.InputSensorInfo;
 import android.os.IBinder;
 import android.os.VibrationEffect;
 import android.view.InputDevice;
@@ -105,4 +107,17 @@
     // Remove the runtime association between the input port and the display port. Any existing
     // static association for the cleared input port will be restored.
     void removePortAssociation(in String inputPort);
+
+    InputSensorInfo[] getSensorList(int deviceId);
+
+    boolean registerSensorListener(IInputSensorEventListener listener);
+
+    void unregisterSensorListener(IInputSensorEventListener listener);
+
+    boolean enableSensor(int deviceId, int sensorType, int samplingPeriodUs,
+                int maxBatchReportLatencyUs);
+
+    void disableSensor(int deviceId, int sensorType);
+
+    boolean flushSensor(int deviceId, int sensorType);
 }
diff --git a/core/java/android/hardware/input/IInputSensorEventListener.aidl b/core/java/android/hardware/input/IInputSensorEventListener.aidl
new file mode 100644
index 0000000..508f590
--- /dev/null
+++ b/core/java/android/hardware/input/IInputSensorEventListener.aidl
@@ -0,0 +1,27 @@
+/*
+ * 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 android.hardware.input;
+
+/** @hide */
+interface IInputSensorEventListener {
+    /* Called when there is a new sensor event. */
+    oneway void onInputSensorChanged(int deviceId, int sensorId, int accuracy, long timestamp,
+            in float[] values);
+
+    /* Called when the accuracy of the registered sensor has changed. */
+    oneway void onInputSensorAccuracyChanged(int deviceId, int sensorId, int accuracy);
+}
diff --git a/core/java/android/hardware/input/InputDeviceSensorManager.java b/core/java/android/hardware/input/InputDeviceSensorManager.java
new file mode 100644
index 0000000..56c2cdd
--- /dev/null
+++ b/core/java/android/hardware/input/InputDeviceSensorManager.java
@@ -0,0 +1,661 @@
+/*
+ * 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 android.hardware.input;
+
+import android.annotation.NonNull;
+import android.hardware.HardwareBuffer;
+import android.hardware.Sensor;
+import android.hardware.SensorAdditionalInfo;
+import android.hardware.SensorDirectChannel;
+import android.hardware.SensorEvent;
+import android.hardware.SensorEventListener;
+import android.hardware.SensorManager;
+import android.hardware.TriggerEventListener;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.Looper;
+import android.os.MemoryFile;
+import android.os.Message;
+import android.os.RemoteException;
+import android.util.Slog;
+import android.view.InputDevice;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.os.SomeArgs;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Sensor manager implementation that communicates with the input device
+ * sensors.
+ * @hide
+ */
+public class InputDeviceSensorManager implements InputManager.InputDeviceListener {
+    private static final String TAG = "InputDeviceSensorManager";
+    private static final boolean DEBUG = false;
+
+    private static final int MSG_SENSOR_ACCURACY_CHANGED = 1;
+    private static final int MSG_SENSOR_CHANGED = 2;
+
+    private InputManager mInputManager;
+
+    // sensor map from device id to sensor list
+    @GuardedBy("mInputSensorLock")
+    private final Map<Integer, List<Sensor>> mSensors = new HashMap<>();
+
+    private final Object mInputSensorLock = new Object();
+    private InputSensorEventListener mInputServiceSensorListener;
+    @GuardedBy("mInputSensorLock")
+    private final ArrayList<InputSensorEventListenerDelegate> mInputSensorEventListeners =
+            new ArrayList<InputSensorEventListenerDelegate>();
+    private HandlerThread mSensorThread = null;
+    private Handler mSensorHandler = null;
+
+    public InputDeviceSensorManager(InputManager inputManager) {
+        mInputManager = inputManager;
+
+        mSensorThread = new HandlerThread("SensorThread");
+        mSensorThread.start();
+        mSensorHandler = new Handler(mSensorThread.getLooper());
+
+        // Register the input device listener
+        mInputManager.registerInputDeviceListener(this, mSensorHandler);
+        // Initialize the sensor list
+        initializeSensors();
+    }
+
+    /*
+     * Get SensorManager object for specific input device
+     *
+     * @param deviceId Input device ID
+     * @return SensorManager object for input device
+     */
+    SensorManager getSensorManager(int deviceId) {
+        return new InputSensorManager(deviceId);
+    }
+
+    /*
+     * Update input device sensor info for specified input device ID.
+     */
+    private void updateInputDeviceSensorInfoLocked(int deviceId) {
+        final InputDevice inputDevice = InputDevice.getDevice(deviceId);
+        if (inputDevice.hasSensor()) {
+            final InputSensorInfo[] sensorInfos =
+                    mInputManager.getSensorList(deviceId);
+            populateSensorsForInputDeviceLocked(deviceId, sensorInfos);
+        }
+    }
+
+    @Override
+    public void onInputDeviceAdded(int deviceId) {
+        synchronized (mInputSensorLock) {
+            if (!mSensors.containsKey(deviceId)) {
+                updateInputDeviceSensorInfoLocked(deviceId);
+            } else {
+                Slog.e(TAG, "Received 'device added' notification for device " + deviceId
+                        + ", but it is already in the list");
+            }
+        }
+    }
+
+    @Override
+    public void onInputDeviceRemoved(int deviceId) {
+        synchronized (mInputSensorLock) {
+            mSensors.remove(deviceId);
+        }
+    }
+
+    @Override
+    public void onInputDeviceChanged(int deviceId) {
+        synchronized (mInputSensorLock) {
+            if (mSensors.containsKey(deviceId)) {
+                mSensors.remove(deviceId);
+            }
+            updateInputDeviceSensorInfoLocked(deviceId);
+        }
+    }
+
+    private static boolean sensorEquals(@NonNull Sensor lhs, @NonNull Sensor rhs) {
+        if (lhs.getType() == rhs.getType() && lhs.getId() == rhs.getId()) {
+            return true;
+        }
+        return false;
+    }
+
+    private void populateSensorsForInputDeviceLocked(int deviceId, InputSensorInfo[] sensorInfos) {
+        List<Sensor> sensors = new ArrayList<Sensor>();
+        for (int i = 0; i < sensorInfos.length; i++) {
+            Sensor sensor = new Sensor(sensorInfos[i]);
+            if (DEBUG) {
+                Slog.d(TAG, "Device " + deviceId + " sensor " + sensor.getStringType() + " added");
+            }
+            sensors.add(sensor);
+        }
+        mSensors.put(deviceId, sensors);
+    }
+
+    private void initializeSensors() {
+        synchronized (mInputSensorLock) {
+            mSensors.clear();
+            int[] deviceIds = mInputManager.getInputDeviceIds();
+            for (int i = 0; i < deviceIds.length; i++) {
+                final int deviceId = deviceIds[i];
+                updateInputDeviceSensorInfoLocked(deviceId);
+            }
+        }
+    }
+
+    /**
+     * Get a sensor object for input device, with specific sensor type.
+     * @param deviceId The input devicd ID
+     * @param sensorType The sensor type
+     * @return The sensor object if exists or null
+     */
+    @GuardedBy("mInputSensorLock")
+    private Sensor getInputDeviceSensorLocked(int deviceId, int sensorType) {
+        List<Sensor> sensors = mSensors.get(deviceId);
+        for (Sensor sensor : sensors) {
+            if (sensor.getType() == sensorType) {
+                return sensor;
+            }
+        }
+        return null;
+    }
+
+    @GuardedBy("mInputSensorLock")
+    private int findSensorEventListenerLocked(SensorEventListener listener) {
+        for (int i = 0; i < mInputSensorEventListeners.size(); i++) {
+            if (mInputSensorEventListeners.get(i).getListener() == listener) {
+                return i;
+            }
+        }
+        return Integer.MIN_VALUE;
+    }
+
+    private void onInputSensorChanged(int deviceId, int sensorType, int accuracy, long timestamp,
+            float[] values) {
+        if (DEBUG) {
+            Slog.d(TAG, "Sensor changed: deviceId =" + deviceId
+                    + " timestamp=" + timestamp + " sensorType=" + sensorType);
+        }
+        synchronized (mInputSensorLock) {
+            SensorEvent event = createSensorEvent(
+                    InputDevice.getDevice(deviceId), sensorType, accuracy, timestamp, values);
+            if (event == null) {
+                Slog.wtf(TAG, "Failed to create SensorEvent.");
+                return;
+            }
+            for (int i = 0; i < mInputSensorEventListeners.size(); i++) {
+                InputSensorEventListenerDelegate listener =
+                        mInputSensorEventListeners.get(i);
+                if (listener.hasSensorRegistered(deviceId, sensorType)) {
+                    listener.sendSensorChanged(event);
+                }
+            }
+        }
+    }
+
+    private void onInputSensorAccuracyChanged(int deviceId, int sensorType, int accuracy) {
+        if (DEBUG) {
+            Slog.d(TAG, "Sensor accuracy changed: "
+                    + "accuracy=" + accuracy + ", sensorType=" + sensorType);
+        }
+        synchronized (mInputSensorLock) {
+            for (int i = 0; i < mInputSensorEventListeners.size(); i++) {
+                InputSensorEventListenerDelegate listener =
+                        mInputSensorEventListeners.get(i);
+                if (listener.hasSensorRegistered(deviceId, sensorType)) {
+                    listener.sendSensorAccuracyChanged(deviceId, sensorType, accuracy);
+                }
+            }
+        }
+    }
+
+    private final class InputSensorEventListener extends IInputSensorEventListener.Stub {
+        @Override
+        public void onInputSensorChanged(int deviceId, int sensorType, int accuracy, long timestamp,
+                float[] values) throws RemoteException {
+            InputDeviceSensorManager.this.onInputSensorChanged(
+                    deviceId, sensorType, accuracy, timestamp, values);
+        }
+
+        @Override
+        public void onInputSensorAccuracyChanged(int deviceId, int sensorType, int accuracy)
+                throws RemoteException {
+            InputDeviceSensorManager.this.onInputSensorAccuracyChanged(deviceId, sensorType,
+                    accuracy);
+        }
+
+    }
+
+    private static final class InputSensorEventListenerDelegate extends Handler {
+        private final SensorEventListener mListener;
+        private final int mDelayUs;
+        private final int mMaxBatchReportLatencyUs;
+        private List<Sensor> mSensors = new ArrayList<Sensor>();
+
+        InputSensorEventListenerDelegate(SensorEventListener listener, Sensor sensor,
+                int delayUs, int maxBatchReportLatencyUs, Handler handler) {
+            super(handler != null ? handler.getLooper() : Looper.myLooper());
+            mListener = listener;
+            mSensors.add(sensor);
+            mDelayUs = delayUs;
+            mMaxBatchReportLatencyUs = maxBatchReportLatencyUs;
+        }
+
+        public List<Sensor> getSensors() {
+            return mSensors;
+        }
+
+        public boolean isEmpty() {
+            return mSensors.isEmpty();
+        }
+
+        /**
+         * Remove sensor from sensor list for listener
+         */
+        public void removeSensor(Sensor sensor) {
+            // If sensor is not specified the listener will be unregistered for all sensors
+            // and the sensor list is cleared.
+            if (sensor == null) {
+                mSensors.clear();
+            }
+            for (Sensor s : mSensors) {
+                if (sensorEquals(s, sensor)) {
+                    mSensors.remove(sensor);
+                }
+            }
+        }
+
+        /**
+         * Add a sensor to listener's sensor list
+         */
+        public void addSensor(@NonNull Sensor sensor) {
+            for (Sensor s : mSensors) {
+                if (sensorEquals(s, sensor)) {
+                    Slog.w(TAG, "Adding sensor " + sensor + " already exist!");
+                    return;
+                }
+            }
+            mSensors.add(sensor);
+        }
+
+        /**
+         * Check if the listener has been registered to the sensor
+         * @param deviceId The input device ID of the sensor
+         * @param sensorType The sensor type of the sensor
+         * @return true if specified sensor is registered for the listener.
+         */
+        public boolean hasSensorRegistered(int deviceId, int sensorType) {
+            for (Sensor sensor : mSensors) {
+                if (sensor.getType() == sensorType && sensor.getId() == deviceId) {
+                    return true;
+                }
+            }
+            return false;
+        }
+
+        /**
+         * Get listener handle for the delegate
+         */
+        public SensorEventListener getListener() {
+            return mListener;
+        }
+
+        /**
+         * Send sensor changed message
+         */
+        public void sendSensorChanged(SensorEvent event) {
+            SomeArgs args = SomeArgs.obtain();
+            obtainMessage(MSG_SENSOR_CHANGED, event).sendToTarget();
+        }
+
+        /**
+         * Send sensor accuracy changed message
+         */
+        public void sendSensorAccuracyChanged(int deviceId, int sensorType, int accuracy) {
+            SomeArgs args = SomeArgs.obtain();
+            obtainMessage(MSG_SENSOR_ACCURACY_CHANGED, deviceId, sensorType, accuracy)
+                    .sendToTarget();
+        }
+
+        @Override
+        public void handleMessage(Message msg) {
+            switch (msg.what) {
+                case MSG_SENSOR_ACCURACY_CHANGED: {
+                    final int deviceId = msg.arg1;
+                    final int sensorType = msg.arg2;
+                    final int accuracy = (int) msg.obj;
+                    for (Sensor sensor : mSensors) {
+                        if (sensor.getId() == deviceId && sensor.getType() == sensorType) {
+                            mListener.onAccuracyChanged(sensor, accuracy);
+                        }
+                    }
+                    break;
+                }
+                case MSG_SENSOR_CHANGED: {
+                    SensorEvent event = (SensorEvent) msg.obj;
+                    mListener.onSensorChanged(event);
+                    break;
+                }
+            }
+        }
+    }
+
+    /**
+     * Create SensorEvent object for input device, with specified device ID, sensor Type,
+     * sensor event timestamp, accuracy, and sensor values.
+     */
+    private SensorEvent createSensorEvent(InputDevice inputDevice, int sensorType, int accuracy,
+            long timestamp, float[] values) {
+        synchronized (mInputSensorLock) {
+            Sensor sensor = getInputDeviceSensorLocked(inputDevice.getId(), sensorType);
+            if (sensor == null) {
+                Slog.wtf(TAG, "Can't get sensor type " + sensorType + " for input device "
+                        + inputDevice);
+            }
+            SensorEvent event = new SensorEvent(sensor, accuracy, timestamp, values);
+            if (event == null) {
+                Slog.wtf(TAG, "Failed to create SensorEvent.");
+            }
+            return event;
+        }
+    }
+
+    /**
+     * Return the default sensor object for input device, for specific sensor type.
+     */
+    private Sensor getSensorForInputDevice(int deviceId, int type) {
+        synchronized (mInputSensorLock) {
+            for (Map.Entry<Integer, List<Sensor>> entry : mSensors.entrySet()) {
+                for (Sensor sensor : entry.getValue()) {
+                    if (sensor.getId() == deviceId && sensor.getType() == type) {
+                        if (DEBUG) {
+                            Slog.d(TAG, "Device " + deviceId + " sensor " + sensor.getStringType());
+                        }
+                        return sensor;
+                    }
+                }
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Return list of sensors that belong to an input device, specified by input device ID.
+     */
+    private List<Sensor> getFullSensorListForDevice(int deviceId) {
+        List<Sensor> sensors = new ArrayList<Sensor>();
+        synchronized (mInputSensorLock) {
+            for (Map.Entry<Integer, List<Sensor>> entry : mSensors.entrySet()) {
+                for (Sensor sensor : entry.getValue()) {
+                    if (sensor.getId() == deviceId) {
+                        if (DEBUG) {
+                            Slog.d(TAG, "Device " + deviceId + " sensor " + sensor.getStringType());
+                        }
+                        sensors.add(sensor);
+                    }
+                }
+            }
+        }
+        return sensors;
+    }
+
+    private boolean registerListenerInternal(SensorEventListener listener, Sensor sensor,
+            int delayUs, int maxBatchReportLatencyUs, Handler handler) {
+        if (DEBUG) {
+            Slog.d(TAG, "registerListenerImpl listener=" + listener + " sensor=" + sensor
+                    + " delayUs=" + delayUs
+                    + " maxBatchReportLatencyUs=" + maxBatchReportLatencyUs);
+        }
+        if (listener == null) {
+            Slog.e(TAG, "listener is null");
+            return false;
+        }
+
+        if (sensor == null) {
+            Slog.e(TAG, "sensor is null");
+            return false;
+        }
+
+        // Trigger Sensors should use the requestTriggerSensor call.
+        if (sensor.getReportingMode() == Sensor.REPORTING_MODE_ONE_SHOT) {
+            Slog.e(TAG, "Trigger Sensors should use the requestTriggerSensor.");
+            return false;
+        }
+        if (maxBatchReportLatencyUs < 0 || delayUs < 0) {
+            Slog.e(TAG, "maxBatchReportLatencyUs and delayUs should be non-negative");
+            return false;
+        }
+
+        if (getSensorForInputDevice(sensor.getId(), sensor.getType()) != null) {
+            synchronized (mInputSensorLock) {
+                final int deviceId = sensor.getId();
+                InputDevice inputDevice = InputDevice.getDevice(deviceId);
+                if (!inputDevice.hasSensor()) {
+                    Slog.e(TAG, "The device doesn't have the sensor:" + sensor);
+                    return false;
+                }
+                if (!mInputManager.enableSensor(deviceId, sensor.getType(), delayUs,
+                        maxBatchReportLatencyUs)) {
+                    Slog.e(TAG, "Can't enable the sensor:" + sensor);
+                    return false;
+                }
+            }
+        }
+
+        synchronized (mInputSensorLock) {
+            // Register the InputManagerService sensor listener if not yet.
+            if (mInputServiceSensorListener == null) {
+                mInputServiceSensorListener = new InputSensorEventListener();
+                if (!mInputManager.registerSensorListener(mInputServiceSensorListener)) {
+                    Slog.e(TAG, "Failed registering the sensor listener");
+                    return false;
+                }
+            }
+
+            int idx = findSensorEventListenerLocked(listener);
+            if (idx < 0) {
+                InputSensorEventListenerDelegate d =
+                        new InputSensorEventListenerDelegate(listener, sensor, delayUs,
+                                maxBatchReportLatencyUs,
+                                handler == null ? mSensorHandler : handler);
+                mInputSensorEventListeners.add(d);
+            } else {
+                // The listener is already registered, see if it wants to listen to more sensors.
+                mInputSensorEventListeners.get(idx).addSensor(sensor);
+            }
+        }
+
+        return true;
+    }
+
+    private void unregisterListenerInternal(SensorEventListener listener, Sensor sensor) {
+        if (DEBUG) {
+            Slog.d(TAG, "unregisterListenerImpl listener=" + listener + " sensor=" + sensor);
+        }
+        if (listener == null) {  // it's OK for the sensor to be null
+            throw new IllegalArgumentException("listener must not be null");
+        }
+        synchronized (mInputSensorLock) {
+            int idx = findSensorEventListenerLocked(listener);
+            // Track the sensor types and the device Id the listener has registered.
+            final List<Sensor> sensorsRegistered;
+            if (idx >= 0) {
+                InputSensorEventListenerDelegate delegate =
+                        mInputSensorEventListeners.get(idx);
+                sensorsRegistered = new ArrayList<Sensor>(delegate.getSensors());
+                // Get the sensor types the listener is listening to
+                delegate.removeSensor(sensor);
+                if (delegate.isEmpty()) {
+                    // If no sensors to listen, remove the listener delegate
+                    mInputSensorEventListeners.remove(idx);
+                }
+            } else {
+                Slog.e(TAG, "Listener is not registered");
+                return;
+            }
+            // If no delegation remains, unregister the listener to input service
+            if (mInputServiceSensorListener != null && mInputSensorEventListeners.size() == 0) {
+                mInputManager.unregisterSensorListener(mInputServiceSensorListener);
+                mInputServiceSensorListener = null;
+            }
+            // For each sensor type check if it is still in use by other listeners.
+            for (Sensor s : sensorsRegistered) {
+                final int deviceId = s.getId();
+                final int sensorType = s.getType();
+                // See if we can disable the sensor
+                boolean enableSensor = false;
+                for (int i = 0; i < mInputSensorEventListeners.size(); i++) {
+                    InputSensorEventListenerDelegate delegate =
+                            mInputSensorEventListeners.get(i);
+                    if (delegate.hasSensorRegistered(deviceId, sensorType)) {
+                        enableSensor = true;
+                        Slog.w(TAG, "device " + deviceId + " still uses sensor " + sensorType);
+                        break;
+                    }
+                }
+                // Sensor is not listened, disable it.
+                if (!enableSensor) {
+                    if (DEBUG) {
+                        Slog.d(TAG, "device " + deviceId + " sensor " + sensorType + " disabled");
+                    }
+                    mInputManager.disableSensor(deviceId, sensorType);
+                }
+            }
+        }
+    }
+
+    private boolean flush(SensorEventListener listener) {
+        synchronized (mInputSensorLock) {
+            int idx = findSensorEventListenerLocked(listener);
+            if (idx < 0) {
+                return false;
+            }
+            for (Sensor sensor : mInputSensorEventListeners.get(idx).getSensors()) {
+                final int deviceId = sensor.getId();
+                if (!mInputManager.flushSensor(deviceId, sensor.getType())) {
+                    return false;
+                }
+            }
+            return true;
+        }
+    }
+
+    /**
+     * Sensor Manager class associated with specific input device
+     */
+    public class InputSensorManager extends SensorManager {
+        // Input device ID that the sensors belong to
+        final int mId;
+
+        InputSensorManager(int deviceId) {
+            mId = deviceId;
+        }
+
+        @Override
+        public Sensor getDefaultSensor(int type) {
+            return getSensorForInputDevice(mId, type);
+        }
+
+        @Override
+        protected List<Sensor> getFullSensorList() {
+            return getFullSensorListForDevice(mId);
+        }
+
+        @Override
+        protected List<Sensor> getFullDynamicSensorList() {
+            return new ArrayList<>();
+        }
+
+        @Override
+        protected boolean registerListenerImpl(SensorEventListener listener, Sensor sensor,
+                int delayUs, Handler handler, int maxBatchReportLatencyUs, int reservedFlags) {
+            return registerListenerInternal(listener, sensor, delayUs,
+                    maxBatchReportLatencyUs, handler);
+        }
+
+        @Override
+        protected void unregisterListenerImpl(SensorEventListener listener, Sensor sensor) {
+            unregisterListenerInternal(listener, sensor);
+        }
+
+        @Override
+        protected boolean flushImpl(SensorEventListener listener) {
+            return flush(listener);
+        }
+
+        @Override
+        protected SensorDirectChannel createDirectChannelImpl(MemoryFile memoryFile,
+                HardwareBuffer hardwareBuffer) {
+            return null;
+        }
+
+        @Override
+        protected void destroyDirectChannelImpl(SensorDirectChannel channel) {
+
+        }
+
+        @Override
+        protected int configureDirectChannelImpl(SensorDirectChannel channel, Sensor s, int rate) {
+            return 0;
+        }
+
+        @Override
+        protected void registerDynamicSensorCallbackImpl(DynamicSensorCallback callback,
+                Handler handler) {
+
+        }
+
+        @Override
+        protected void unregisterDynamicSensorCallbackImpl(
+                DynamicSensorCallback callback) {
+
+        }
+
+        @Override
+        protected boolean requestTriggerSensorImpl(TriggerEventListener listener, Sensor sensor) {
+            return true;
+        }
+
+        @Override
+        protected boolean cancelTriggerSensorImpl(TriggerEventListener listener, Sensor sensor,
+                boolean disable) {
+            return true;
+        }
+
+        @Override
+        protected boolean initDataInjectionImpl(boolean enable) {
+            return false;
+        }
+
+        @Override
+        protected boolean injectSensorDataImpl(Sensor sensor, float[] values, int accuracy,
+                long timestamp) {
+            return false;
+        }
+
+        @Override
+        protected boolean setOperationParameterImpl(SensorAdditionalInfo parameter) {
+            return false;
+        }
+    }
+
+}
diff --git a/core/java/android/hardware/input/InputManager.java b/core/java/android/hardware/input/InputManager.java
index dd71cce..300d99b 100644
--- a/core/java/android/hardware/input/InputManager.java
+++ b/core/java/android/hardware/input/InputManager.java
@@ -28,6 +28,7 @@
 import android.compat.annotation.ChangeId;
 import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
+import android.hardware.SensorManager;
 import android.os.BlockUntrustedTouchesMode;
 import android.os.Build;
 import android.os.CombinedVibrationEffect;
@@ -100,6 +101,7 @@
     private TabletModeChangedListener mTabletModeChangedListener;
     private List<OnTabletModeChangedListenerDelegate> mOnTabletModeChangedListeners;
 
+    private InputDeviceSensorManager mInputDeviceSensorManager;
     /**
      * Broadcast Action: Query available keyboard layouts.
      * <p>
@@ -193,7 +195,7 @@
      */
     @BlockUntrustedTouchesMode
     public static final int DEFAULT_BLOCK_UNTRUSTED_TOUCHES_MODE =
-            BlockUntrustedTouchesMode.BLOCK;
+            BlockUntrustedTouchesMode.PERMISSIVE;
 
     /**
      * Prevent touches from being consumed by apps if these touches passed through a non-trusted
@@ -291,6 +293,18 @@
     }
 
     /**
+     * Clear the instance of the input manager.
+     *
+     * @hide
+     */
+    @VisibleForTesting
+    public static void clearInstance() {
+        synchronized (InputManager.class) {
+            sInstance = null;
+        }
+    }
+
+    /**
      * Gets an instance of the input manager.
      *
      * @return The input manager instance.
@@ -1152,6 +1166,86 @@
     }
 
     /**
+     * Get sensors information as list.
+     *
+     * @hide
+     */
+    public InputSensorInfo[] getSensorList(int deviceId) {
+        try {
+            return mIm.getSensorList(deviceId);
+        } catch (RemoteException ex) {
+            throw ex.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Enable input device sensor
+     *
+     * @hide
+     */
+    public boolean enableSensor(int deviceId, int sensorType, int samplingPeriodUs,
+            int maxBatchReportLatencyUs) {
+        try {
+            return mIm.enableSensor(deviceId, sensorType, samplingPeriodUs,
+                    maxBatchReportLatencyUs);
+        } catch (RemoteException ex) {
+            throw ex.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Enable input device sensor
+     *
+     * @hide
+     */
+    public void disableSensor(int deviceId, int sensorType) {
+        try {
+            mIm.disableSensor(deviceId, sensorType);
+        } catch (RemoteException ex) {
+            throw ex.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Flush input device sensor
+     *
+     * @hide
+     */
+    public boolean flushSensor(int deviceId, int sensorType) {
+        try {
+            return mIm.flushSensor(deviceId, sensorType);
+        } catch (RemoteException ex) {
+            throw ex.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Register input device sensor listener
+     *
+     * @hide
+     */
+    public boolean registerSensorListener(IInputSensorEventListener listener) {
+        try {
+            return mIm.registerSensorListener(listener);
+        } catch (RemoteException ex) {
+            throw ex.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Unregister input device sensor listener
+     *
+     * @hide
+     */
+    public void unregisterSensorListener(IInputSensorEventListener listener) {
+        try {
+            mIm.unregisterSensorListener(listener);
+        } catch (RemoteException ex) {
+            throw ex.rethrowFromSystemServer();
+        }
+    }
+
+    /**
      * Add a runtime association between the input port and the display port. This overrides any
      * static associations.
      * @param inputPort The port of the input device.
@@ -1289,7 +1383,7 @@
     }
 
     /**
-     * Gets a vibrator service associated with an input device, assuming it has one.
+     * Gets a vibrator service associated with an input device, always create a new instance.
      * @return The vibrator, never null.
      * @hide
      */
@@ -1365,6 +1459,19 @@
     }
 
     /**
+     * Gets a sensor manager service associated with an input device, always create a new instance.
+     * @return The sensor manager, never null.
+     * @hide
+     */
+    @NonNull
+    public SensorManager getInputDeviceSensorManager(int deviceId) {
+        if (mInputDeviceSensorManager == null) {
+            mInputDeviceSensorManager = new InputDeviceSensorManager(this);
+        }
+        return mInputDeviceSensorManager.getSensorManager(deviceId);
+    }
+
+    /**
      * Listens for changes in input devices.
      */
     public interface InputDeviceListener {
diff --git a/core/java/android/hardware/input/InputSensorInfo.aidl b/core/java/android/hardware/input/InputSensorInfo.aidl
new file mode 100644
index 0000000..d9a604a
--- /dev/null
+++ b/core/java/android/hardware/input/InputSensorInfo.aidl
@@ -0,0 +1,19 @@
+/*
+ * 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 android.hardware.input;
+
+parcelable InputSensorInfo;
diff --git a/core/java/android/hardware/input/InputSensorInfo.java b/core/java/android/hardware/input/InputSensorInfo.java
new file mode 100644
index 0000000..99b1879
--- /dev/null
+++ b/core/java/android/hardware/input/InputSensorInfo.java
@@ -0,0 +1,330 @@
+/*
+ * 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 android.hardware.input;
+
+import android.annotation.NonNull;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import com.android.internal.util.DataClass;
+/**
+ * This class represents a motion sensor for input devices.
+ *
+ * @hide
+ */
+@DataClass(
+        genToString = true,
+        genHiddenConstructor = true,
+        genHiddenConstDefs = true)
+public class InputSensorInfo implements Parcelable {
+
+    private @NonNull String  mName;
+    private @NonNull String  mVendor;
+    private int     mVersion;
+    private int     mHandle;
+    private int     mType;
+    private float   mMaxRange;
+    private float   mResolution;
+    private float   mPower;
+    private int     mMinDelay;
+    private int     mFifoReservedEventCount;
+    private int     mFifoMaxEventCount;
+    private @NonNull String  mStringType;
+    private @NonNull String  mRequiredPermission;
+    private int     mMaxDelay;
+    private int     mFlags;
+    private int     mId;
+
+
+
+    // Code below generated by codegen v1.0.20.
+    //
+    // DO NOT MODIFY!
+    // CHECKSTYLE:OFF Generated code
+    //
+    // To regenerate run:
+    // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/hardware/input/InputSensorInfo.java
+    //
+    // To exclude the generated code from IntelliJ auto-formatting enable (one-time):
+    //   Settings > Editor > Code Style > Formatter Control
+    //@formatter:off
+
+
+    /**
+     * Creates a new InputSensorInfo.
+     *
+     * @hide
+     */
+    @DataClass.Generated.Member
+    public InputSensorInfo(
+            @NonNull String name,
+            @NonNull String vendor,
+            int version,
+            int handle,
+            int type,
+            float maxRange,
+            float resolution,
+            float power,
+            int minDelay,
+            int fifoReservedEventCount,
+            int fifoMaxEventCount,
+            @NonNull String stringType,
+            @NonNull String requiredPermission,
+            int maxDelay,
+            int flags,
+            int id) {
+        this.mName = name;
+        com.android.internal.util.AnnotationValidations.validate(
+                NonNull.class, null, mName);
+        this.mVendor = vendor;
+        com.android.internal.util.AnnotationValidations.validate(
+                NonNull.class, null, mVendor);
+        this.mVersion = version;
+        this.mHandle = handle;
+        this.mType = type;
+        this.mMaxRange = maxRange;
+        this.mResolution = resolution;
+        this.mPower = power;
+        this.mMinDelay = minDelay;
+        this.mFifoReservedEventCount = fifoReservedEventCount;
+        this.mFifoMaxEventCount = fifoMaxEventCount;
+        this.mStringType = stringType;
+        com.android.internal.util.AnnotationValidations.validate(
+                NonNull.class, null, mStringType);
+        this.mRequiredPermission = requiredPermission;
+        com.android.internal.util.AnnotationValidations.validate(
+                NonNull.class, null, mRequiredPermission);
+        this.mMaxDelay = maxDelay;
+        this.mFlags = flags;
+        this.mId = id;
+
+        // onConstructed(); // You can define this method to get a callback
+    }
+
+    @DataClass.Generated.Member
+    public @NonNull String getName() {
+        return mName;
+    }
+
+    @DataClass.Generated.Member
+    public @NonNull String getVendor() {
+        return mVendor;
+    }
+
+    @DataClass.Generated.Member
+    public int getVersion() {
+        return mVersion;
+    }
+
+    @DataClass.Generated.Member
+    public int getHandle() {
+        return mHandle;
+    }
+
+    @DataClass.Generated.Member
+    public int getType() {
+        return mType;
+    }
+
+    @DataClass.Generated.Member
+    public float getMaxRange() {
+        return mMaxRange;
+    }
+
+    @DataClass.Generated.Member
+    public float getResolution() {
+        return mResolution;
+    }
+
+    @DataClass.Generated.Member
+    public float getPower() {
+        return mPower;
+    }
+
+    @DataClass.Generated.Member
+    public int getMinDelay() {
+        return mMinDelay;
+    }
+
+    @DataClass.Generated.Member
+    public int getFifoReservedEventCount() {
+        return mFifoReservedEventCount;
+    }
+
+    @DataClass.Generated.Member
+    public int getFifoMaxEventCount() {
+        return mFifoMaxEventCount;
+    }
+
+    @DataClass.Generated.Member
+    public @NonNull String getStringType() {
+        return mStringType;
+    }
+
+    @DataClass.Generated.Member
+    public @NonNull String getRequiredPermission() {
+        return mRequiredPermission;
+    }
+
+    @DataClass.Generated.Member
+    public int getMaxDelay() {
+        return mMaxDelay;
+    }
+
+    @DataClass.Generated.Member
+    public int getFlags() {
+        return mFlags;
+    }
+
+    @DataClass.Generated.Member
+    public int getId() {
+        return mId;
+    }
+
+    @Override
+    @DataClass.Generated.Member
+    public String toString() {
+        // You can override field toString logic by defining methods like:
+        // String fieldNameToString() { ... }
+
+        return "InputSensorInfo { " +
+                "name = " + mName + ", " +
+                "vendor = " + mVendor + ", " +
+                "version = " + mVersion + ", " +
+                "handle = " + mHandle + ", " +
+                "type = " + mType + ", " +
+                "maxRange = " + mMaxRange + ", " +
+                "resolution = " + mResolution + ", " +
+                "power = " + mPower + ", " +
+                "minDelay = " + mMinDelay + ", " +
+                "fifoReservedEventCount = " + mFifoReservedEventCount + ", " +
+                "fifoMaxEventCount = " + mFifoMaxEventCount + ", " +
+                "stringType = " + mStringType + ", " +
+                "requiredPermission = " + mRequiredPermission + ", " +
+                "maxDelay = " + mMaxDelay + ", " +
+                "flags = " + mFlags + ", " +
+                "id = " + mId +
+        " }";
+    }
+
+    @Override
+    @DataClass.Generated.Member
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
+        // You can override field parcelling by defining methods like:
+        // void parcelFieldName(Parcel dest, int flags) { ... }
+
+        dest.writeString(mName);
+        dest.writeString(mVendor);
+        dest.writeInt(mVersion);
+        dest.writeInt(mHandle);
+        dest.writeInt(mType);
+        dest.writeFloat(mMaxRange);
+        dest.writeFloat(mResolution);
+        dest.writeFloat(mPower);
+        dest.writeInt(mMinDelay);
+        dest.writeInt(mFifoReservedEventCount);
+        dest.writeInt(mFifoMaxEventCount);
+        dest.writeString(mStringType);
+        dest.writeString(mRequiredPermission);
+        dest.writeInt(mMaxDelay);
+        dest.writeInt(mFlags);
+        dest.writeInt(mId);
+    }
+
+    @Override
+    @DataClass.Generated.Member
+    public int describeContents() { return 0; }
+
+    /** @hide */
+    @SuppressWarnings({"unchecked", "RedundantCast"})
+    @DataClass.Generated.Member
+    protected InputSensorInfo(@NonNull Parcel in) {
+        // You can override field unparcelling by defining methods like:
+        // static FieldType unparcelFieldName(Parcel in) { ... }
+
+        String name = in.readString();
+        String vendor = in.readString();
+        int version = in.readInt();
+        int handle = in.readInt();
+        int type = in.readInt();
+        float maxRange = in.readFloat();
+        float resolution = in.readFloat();
+        float power = in.readFloat();
+        int minDelay = in.readInt();
+        int fifoReservedEventCount = in.readInt();
+        int fifoMaxEventCount = in.readInt();
+        String stringType = in.readString();
+        String requiredPermission = in.readString();
+        int maxDelay = in.readInt();
+        int flags = in.readInt();
+        int id = in.readInt();
+
+        this.mName = name;
+        com.android.internal.util.AnnotationValidations.validate(
+                NonNull.class, null, mName);
+        this.mVendor = vendor;
+        com.android.internal.util.AnnotationValidations.validate(
+                NonNull.class, null, mVendor);
+        this.mVersion = version;
+        this.mHandle = handle;
+        this.mType = type;
+        this.mMaxRange = maxRange;
+        this.mResolution = resolution;
+        this.mPower = power;
+        this.mMinDelay = minDelay;
+        this.mFifoReservedEventCount = fifoReservedEventCount;
+        this.mFifoMaxEventCount = fifoMaxEventCount;
+        this.mStringType = stringType;
+        com.android.internal.util.AnnotationValidations.validate(
+                NonNull.class, null, mStringType);
+        this.mRequiredPermission = requiredPermission;
+        com.android.internal.util.AnnotationValidations.validate(
+                NonNull.class, null, mRequiredPermission);
+        this.mMaxDelay = maxDelay;
+        this.mFlags = flags;
+        this.mId = id;
+
+        // onConstructed(); // You can define this method to get a callback
+    }
+
+    @DataClass.Generated.Member
+    public static final @NonNull Parcelable.Creator<InputSensorInfo> CREATOR
+            = new Parcelable.Creator<InputSensorInfo>() {
+        @Override
+        public InputSensorInfo[] newArray(int size) {
+            return new InputSensorInfo[size];
+        }
+
+        @Override
+        public InputSensorInfo createFromParcel(@NonNull Parcel in) {
+            return new InputSensorInfo(in);
+        }
+    };
+
+    @DataClass.Generated(
+            time = 1605294854951L,
+            codegenVersion = "1.0.20",
+            sourceFile = "frameworks/base/core/java/android/hardware/input/InputSensorInfo.java",
+            inputSignatures = "private @android.annotation.NonNull java.lang.String mName\nprivate @android.annotation.NonNull java.lang.String mVendor\nprivate  int mVersion\nprivate  int mHandle\nprivate  int mType\nprivate  float mMaxRange\nprivate  float mResolution\nprivate  float mPower\nprivate  int mMinDelay\nprivate  int mFifoReservedEventCount\nprivate  int mFifoMaxEventCount\nprivate @android.annotation.NonNull java.lang.String mStringType\nprivate @android.annotation.NonNull java.lang.String mRequiredPermission\nprivate  int mMaxDelay\nprivate  int mFlags\nprivate  int mId\nclass InputSensorInfo extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genToString=true, genHiddenConstructor=true, genHiddenConstDefs=true)")
+    @Deprecated
+    private void __metadata() {}
+
+
+    //@formatter:on
+    // End of generated code
+
+}
diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java
index 6831eca..df9a7c2 100644
--- a/core/java/android/inputmethodservice/InputMethodService.java
+++ b/core/java/android/inputmethodservice/InputMethodService.java
@@ -1700,8 +1700,12 @@
         if (config.orientation != Configuration.ORIENTATION_LANDSCAPE) {
             return false;
         }
-        if (mInputEditorInfo != null
-                && (mInputEditorInfo.imeOptions & EditorInfo.IME_FLAG_NO_FULLSCREEN) != 0) {
+        if ((mInputEditorInfo != null
+                && (mInputEditorInfo.imeOptions & EditorInfo.IME_FLAG_NO_FULLSCREEN) != 0)
+                // If app window has portrait orientation, regardless of what display orientation
+                // is, IME shouldn't use fullscreen-mode.
+                || (mInputEditorInfo.internalImeOptions
+                        & EditorInfo.IME_FLAG_APP_WINDOW_PORTRAIT) != 0) {
             return false;
         }
         return true;
diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl
index fb01283..95a2f2e 100644
--- a/core/java/android/net/IConnectivityManager.aidl
+++ b/core/java/android/net/IConnectivityManager.aidl
@@ -31,6 +31,7 @@
 import android.net.ProxyInfo;
 import android.os.Bundle;
 import android.os.IBinder;
+import android.os.INetworkActivityListener;
 import android.os.Messenger;
 import android.os.ParcelFileDescriptor;
 import android.os.PersistableBundle;
@@ -233,4 +234,10 @@
                 in PersistableBundle extras);
 
     void systemReady();
+
+    void registerNetworkActivityListener(in INetworkActivityListener l);
+
+    void unregisterNetworkActivityListener(in INetworkActivityListener l);
+
+    boolean isDefaultNetworkActive();
 }
diff --git a/core/java/android/net/INetworkManagementEventObserver.aidl b/core/java/android/net/INetworkManagementEventObserver.aidl
index f0fe92e..55ae218 100644
--- a/core/java/android/net/INetworkManagementEventObserver.aidl
+++ b/core/java/android/net/INetworkManagementEventObserver.aidl
@@ -85,11 +85,14 @@
     /**
      * Interface data activity status is changed.
      *
-     * @param iface The interface.
+     * @param label Unique identifier indicates the network type of the data activity change.
      * @param active  True if the interface is actively transmitting data, false if it is idle.
      * @param tsNanos Elapsed realtime in nanos when the state of the network interface changed.
+     * @param uid Uid of this event. It represents the uid that was responsible for waking the
+     *            radio. For those events that are reported by system itself, not from specific uid,
+     *            use -1 for the events which means no uid.
      */
-    void interfaceClassDataActivityChanged(String label, boolean active, long tsNanos);
+    void interfaceClassDataActivityChanged(String label, boolean active, long tsNanos, int uid);
 
     /**
      * Information about available DNS servers has been received.
diff --git a/core/java/android/net/NetworkStatsHistory.java b/core/java/android/net/NetworkStatsHistory.java
index fba7561..bf25602 100644
--- a/core/java/android/net/NetworkStatsHistory.java
+++ b/core/java/android/net/NetworkStatsHistory.java
@@ -26,9 +26,9 @@
 import static android.net.NetworkStatsHistory.Entry.UNKNOWN;
 import static android.net.NetworkStatsHistory.ParcelUtils.readLongArray;
 import static android.net.NetworkStatsHistory.ParcelUtils.writeLongArray;
-import static android.net.NetworkUtils.multiplySafeByRational;
 import static android.text.format.DateUtils.SECOND_IN_MILLIS;
 
+import static com.android.internal.net.NetworkUtilsInternal.multiplySafeByRational;
 import static com.android.internal.util.ArrayUtils.total;
 
 import android.compat.annotation.UnsupportedAppUsage;
diff --git a/core/java/android/net/NetworkUtils.java b/core/java/android/net/NetworkUtils.java
index d84ee2a..b5962c5 100644
--- a/core/java/android/net/NetworkUtils.java
+++ b/core/java/android/net/NetworkUtils.java
@@ -16,14 +16,9 @@
 
 package android.net;
 
-import static android.system.OsConstants.AF_INET;
-import static android.system.OsConstants.AF_INET6;
-
-import android.annotation.NonNull;
 import android.compat.annotation.UnsupportedAppUsage;
 import android.os.Build;
 import android.system.ErrnoException;
-import android.system.Os;
 import android.util.Log;
 import android.util.Pair;
 
@@ -155,14 +150,6 @@
     public static native Network getDnsNetwork() throws ErrnoException;
 
     /**
-     * Allow/Disallow creating AF_INET/AF_INET6 sockets and DNS lookups for current process.
-     *
-     * @param allowNetworking whether to allow or disallow creating AF_INET/AF_INET6 sockets
-     *                        and DNS lookups.
-     */
-    public static native void setAllowNetworkingForProcess(boolean allowNetworking);
-
-    /**
      * Get the tcp repair window associated with the {@code fd}.
      *
      * @param fd the tcp socket's {@link FileDescriptor}.
@@ -437,60 +424,4 @@
         return routedIPCount;
     }
 
-    private static final int[] ADDRESS_FAMILIES = new int[] {AF_INET, AF_INET6};
-
-    /**
-     * Returns true if the hostname is weakly validated.
-     * @param hostname Name of host to validate.
-     * @return True if it's a valid-ish hostname.
-     *
-     * @hide
-     */
-    public static boolean isWeaklyValidatedHostname(@NonNull String hostname) {
-        // TODO(b/34953048): Use a validation method that permits more accurate,
-        // but still inexpensive, checking of likely valid DNS hostnames.
-        final String weakHostnameRegex = "^[a-zA-Z0-9_.-]+$";
-        if (!hostname.matches(weakHostnameRegex)) {
-            return false;
-        }
-
-        for (int address_family : ADDRESS_FAMILIES) {
-            if (Os.inet_pton(address_family, hostname) != null) {
-                return false;
-            }
-        }
-
-        return true;
-    }
-
-    /**
-     * Safely multiple a value by a rational.
-     * <p>
-     * Internally it uses integer-based math whenever possible, but switches
-     * over to double-based math if values would overflow.
-     * @hide
-     */
-    public static long multiplySafeByRational(long value, long num, long den) {
-        if (den == 0) {
-            throw new ArithmeticException("Invalid Denominator");
-        }
-        long x = value;
-        long y = num;
-
-        // Logic shamelessly borrowed from Math.multiplyExact()
-        long r = x * y;
-        long ax = Math.abs(x);
-        long ay = Math.abs(y);
-        if (((ax | ay) >>> 31 != 0)) {
-            // Some bits greater than 2^31 that might cause overflow
-            // Check the result using the divide operator
-            // and check for the special case of Long.MIN_VALUE * -1
-            if (((y != 0) && (r / y != x)) ||
-                    (x == Long.MIN_VALUE && y == -1)) {
-                // Use double math to avoid overflowing
-                return (long) (((double) num / den) * value);
-            }
-        }
-        return r / den;
-    }
 }
diff --git a/core/java/android/net/vcn/VcnConfig.java b/core/java/android/net/vcn/VcnConfig.java
index 148acf1..d4a3fa7 100644
--- a/core/java/android/net/vcn/VcnConfig.java
+++ b/core/java/android/net/vcn/VcnConfig.java
@@ -15,30 +15,104 @@
  */
 package android.net.vcn;
 
+import static com.android.internal.annotations.VisibleForTesting.Visibility;
+
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.os.PersistableBundle;
+import android.util.ArraySet;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.Preconditions;
+import com.android.server.vcn.util.PersistableBundleUtils;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Objects;
+import java.util.Set;
 
 /**
  * This class represents a configuration for a Virtual Carrier Network.
  *
+ * <p>Each {@link VcnGatewayConnectionConfig} instance added represents a connection that will be
+ * brought up on demand based on active {@link NetworkRequest}(s).
+ *
+ * @see VcnManager for more information on the Virtual Carrier Network feature
  * @hide
  */
 public final class VcnConfig implements Parcelable {
     @NonNull private static final String TAG = VcnConfig.class.getSimpleName();
 
-    private VcnConfig() {
+    private static final String GATEWAY_CONNECTION_CONFIGS_KEY = "mGatewayConnectionConfigs";
+    @NonNull private final Set<VcnGatewayConnectionConfig> mGatewayConnectionConfigs;
+
+    private VcnConfig(@NonNull Set<VcnGatewayConnectionConfig> tunnelConfigs) {
+        mGatewayConnectionConfigs = Collections.unmodifiableSet(tunnelConfigs);
+
         validate();
     }
-    // TODO: Implement getters, validators, etc
 
     /**
-     * Validates this configuration.
+     * Deserializes a VcnConfig from a PersistableBundle.
      *
      * @hide
      */
+    @VisibleForTesting(visibility = Visibility.PRIVATE)
+    public VcnConfig(@NonNull PersistableBundle in) {
+        final PersistableBundle gatewayConnectionConfigsBundle =
+                in.getPersistableBundle(GATEWAY_CONNECTION_CONFIGS_KEY);
+        mGatewayConnectionConfigs =
+                new ArraySet<>(
+                        PersistableBundleUtils.toList(
+                                gatewayConnectionConfigsBundle, VcnGatewayConnectionConfig::new));
+
+        validate();
+    }
+
     private void validate() {
-        // TODO: implement validation logic
+        Preconditions.checkCollectionNotEmpty(
+                mGatewayConnectionConfigs, "gatewayConnectionConfigs");
+    }
+
+    /** Retrieves the set of configured tunnels. */
+    @NonNull
+    public Set<VcnGatewayConnectionConfig> getGatewayConnectionConfigs() {
+        return Collections.unmodifiableSet(mGatewayConnectionConfigs);
+    }
+
+    /**
+     * Serializes this object to a PersistableBundle.
+     *
+     * @hide
+     */
+    @NonNull
+    public PersistableBundle toPersistableBundle() {
+        final PersistableBundle result = new PersistableBundle();
+
+        final PersistableBundle gatewayConnectionConfigsBundle =
+                PersistableBundleUtils.fromList(
+                        new ArrayList<>(mGatewayConnectionConfigs),
+                        VcnGatewayConnectionConfig::toPersistableBundle);
+        result.putPersistableBundle(GATEWAY_CONNECTION_CONFIGS_KEY, gatewayConnectionConfigsBundle);
+
+        return result;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(mGatewayConnectionConfigs);
+    }
+
+    @Override
+    public boolean equals(@Nullable Object other) {
+        if (!(other instanceof VcnConfig)) {
+            return false;
+        }
+
+        final VcnConfig rhs = (VcnConfig) other;
+        return mGatewayConnectionConfigs.equals(rhs.mGatewayConnectionConfigs);
     }
 
     // Parcelable methods
@@ -49,15 +123,16 @@
     }
 
     @Override
-    public void writeToParcel(Parcel out, int flags) {}
+    public void writeToParcel(Parcel out, int flags) {
+        out.writeParcelable(toPersistableBundle(), flags);
+    }
 
     @NonNull
     public static final Parcelable.Creator<VcnConfig> CREATOR =
             new Parcelable.Creator<VcnConfig>() {
                 @NonNull
                 public VcnConfig createFromParcel(Parcel in) {
-                    // TODO: Ensure all methods are pulled from the parcels
-                    return new VcnConfig();
+                    return new VcnConfig((PersistableBundle) in.readParcelable(null));
                 }
 
                 @NonNull
@@ -68,7 +143,23 @@
 
     /** This class is used to incrementally build {@link VcnConfig} objects. */
     public static class Builder {
-        // TODO: Implement this builder
+        @NonNull
+        private final Set<VcnGatewayConnectionConfig> mGatewayConnectionConfigs = new ArraySet<>();
+
+        /**
+         * Adds a configuration for an individual gateway connection.
+         *
+         * @param gatewayConnectionConfig the configuration for an individual gateway connection
+         * @return this {@link Builder} instance, for chaining
+         */
+        @NonNull
+        public Builder addGatewayConnectionConfig(
+                @NonNull VcnGatewayConnectionConfig gatewayConnectionConfig) {
+            Objects.requireNonNull(gatewayConnectionConfig, "gatewayConnectionConfig was null");
+
+            mGatewayConnectionConfigs.add(gatewayConnectionConfig);
+            return this;
+        }
 
         /**
          * Builds and validates the VcnConfig.
@@ -77,7 +168,7 @@
          */
         @NonNull
         public VcnConfig build() {
-            return new VcnConfig();
+            return new VcnConfig(mGatewayConnectionConfigs);
         }
     }
 }
diff --git a/core/java/android/net/vcn/VcnGatewayConnectionConfig.java b/core/java/android/net/vcn/VcnGatewayConnectionConfig.java
index 8160edc..039360a 100644
--- a/core/java/android/net/vcn/VcnGatewayConnectionConfig.java
+++ b/core/java/android/net/vcn/VcnGatewayConnectionConfig.java
@@ -15,7 +15,27 @@
  */
 package android.net.vcn;
 
+import static android.net.NetworkCapabilities.NetCapability;
+
+import static com.android.internal.annotations.VisibleForTesting.Visibility;
+
+import android.annotation.IntRange;
 import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.net.NetworkCapabilities;
+import android.os.PersistableBundle;
+import android.util.ArraySet;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.Preconditions;
+import com.android.server.vcn.util.PersistableBundleUtils;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Objects;
+import java.util.Set;
+import java.util.concurrent.TimeUnit;
 
 /**
  * This class represents a configuration for a connection to a Virtual Carrier Network gateway.
@@ -49,38 +69,399 @@
  *   <li>{@link android.net.NetworkCapabilities.NET_CAPABILITY_MCX}
  * </ul>
  *
+ * <p>The meteredness and roaming of the VCN {@link Network} will be determined by that of the
+ * underlying Network(s).
+ *
  * @hide
  */
 public final class VcnGatewayConnectionConfig {
-    private VcnGatewayConnectionConfig() {
+    // TODO: Use MIN_MTU_V6 once it is public, @hide
+    @VisibleForTesting(visibility = Visibility.PRIVATE)
+    static final int MIN_MTU_V6 = 1280;
+
+    private static final Set<Integer> ALLOWED_CAPABILITIES;
+
+    static {
+        Set<Integer> allowedCaps = new ArraySet<>();
+        allowedCaps.add(NetworkCapabilities.NET_CAPABILITY_MMS);
+        allowedCaps.add(NetworkCapabilities.NET_CAPABILITY_SUPL);
+        allowedCaps.add(NetworkCapabilities.NET_CAPABILITY_DUN);
+        allowedCaps.add(NetworkCapabilities.NET_CAPABILITY_FOTA);
+        allowedCaps.add(NetworkCapabilities.NET_CAPABILITY_IMS);
+        allowedCaps.add(NetworkCapabilities.NET_CAPABILITY_CBS);
+        allowedCaps.add(NetworkCapabilities.NET_CAPABILITY_IA);
+        allowedCaps.add(NetworkCapabilities.NET_CAPABILITY_RCS);
+        allowedCaps.add(NetworkCapabilities.NET_CAPABILITY_XCAP);
+        allowedCaps.add(NetworkCapabilities.NET_CAPABILITY_EIMS);
+        allowedCaps.add(NetworkCapabilities.NET_CAPABILITY_INTERNET);
+        allowedCaps.add(NetworkCapabilities.NET_CAPABILITY_MCX);
+
+        ALLOWED_CAPABILITIES = Collections.unmodifiableSet(allowedCaps);
+    }
+
+    private static final int DEFAULT_MAX_MTU = 1500;
+
+    /**
+     * The maximum number of retry intervals that may be specified.
+     *
+     * <p>Limited to ensure an upper bound on config sizes.
+     */
+    private static final int MAX_RETRY_INTERVAL_COUNT = 10;
+
+    /**
+     * The minimum allowable repeating retry interval
+     *
+     * <p>To ensure the device is not constantly being woken up, this retry interval MUST be greater
+     * than this value.
+     *
+     * @see {@link Builder#setRetryInterval()}
+     */
+    private static final long MINIMUM_REPEATING_RETRY_INTERVAL_MS = TimeUnit.MINUTES.toMillis(15);
+
+    private static final long[] DEFAULT_RETRY_INTERVALS_MS =
+            new long[] {
+                TimeUnit.SECONDS.toMillis(1),
+                TimeUnit.SECONDS.toMillis(2),
+                TimeUnit.SECONDS.toMillis(5),
+                TimeUnit.SECONDS.toMillis(30),
+                TimeUnit.MINUTES.toMillis(1),
+                TimeUnit.MINUTES.toMillis(5),
+                TimeUnit.MINUTES.toMillis(15)
+            };
+
+    private static final String EXPOSED_CAPABILITIES_KEY = "mExposedCapabilities";
+    @NonNull private final Set<Integer> mExposedCapabilities;
+
+    private static final String UNDERLYING_CAPABILITIES_KEY = "mUnderlyingCapabilities";
+    @NonNull private final Set<Integer> mUnderlyingCapabilities;
+
+    // TODO: Add Ike/ChildSessionParams as a subclass - maybe VcnIkeGatewayConnectionConfig
+
+    private static final String MAX_MTU_KEY = "mMaxMtu";
+    private final int mMaxMtu;
+
+    private static final String RETRY_INTERVAL_MS_KEY = "mRetryIntervalsMs";
+    @NonNull private final long[] mRetryIntervalsMs;
+
+    @VisibleForTesting(visibility = Visibility.PRIVATE)
+    public VcnGatewayConnectionConfig(
+            @NonNull Set<Integer> exposedCapabilities,
+            @NonNull Set<Integer> underlyingCapabilities,
+            @NonNull long[] retryIntervalsMs,
+            @IntRange(from = MIN_MTU_V6) int maxMtu) {
+        mExposedCapabilities = exposedCapabilities;
+        mUnderlyingCapabilities = underlyingCapabilities;
+        mRetryIntervalsMs = retryIntervalsMs;
+        mMaxMtu = maxMtu;
+
         validate();
     }
 
-    // TODO: Implement getters, validators, etc
+    /** @hide */
+    @VisibleForTesting(visibility = Visibility.PRIVATE)
+    public VcnGatewayConnectionConfig(@NonNull PersistableBundle in) {
+        final PersistableBundle exposedCapsBundle =
+                in.getPersistableBundle(EXPOSED_CAPABILITIES_KEY);
+        final PersistableBundle underlyingCapsBundle =
+                in.getPersistableBundle(UNDERLYING_CAPABILITIES_KEY);
+
+        mExposedCapabilities = new ArraySet<>(PersistableBundleUtils.toList(
+                exposedCapsBundle, PersistableBundleUtils.INTEGER_DESERIALIZER));
+        mUnderlyingCapabilities = new ArraySet<>(PersistableBundleUtils.toList(
+                underlyingCapsBundle, PersistableBundleUtils.INTEGER_DESERIALIZER));
+        mRetryIntervalsMs = in.getLongArray(RETRY_INTERVAL_MS_KEY);
+        mMaxMtu = in.getInt(MAX_MTU_KEY);
+
+        validate();
+    }
+
+    private void validate() {
+        Preconditions.checkArgument(
+                mExposedCapabilities != null && !mExposedCapabilities.isEmpty(),
+                "exposedCapsBundle was null or empty");
+        for (Integer cap : getAllExposedCapabilities()) {
+            checkValidCapability(cap);
+        }
+
+        Preconditions.checkArgument(
+                mUnderlyingCapabilities != null && !mUnderlyingCapabilities.isEmpty(),
+                "underlyingCapabilities was null or empty");
+        for (Integer cap : getAllUnderlyingCapabilities()) {
+            checkValidCapability(cap);
+        }
+
+        Objects.requireNonNull(mRetryIntervalsMs, "retryIntervalsMs was null");
+        validateRetryInterval(mRetryIntervalsMs);
+
+        Preconditions.checkArgument(
+                mMaxMtu >= MIN_MTU_V6, "maxMtu must be at least IPv6 min MTU (1280)");
+    }
+
+    private static void checkValidCapability(int capability) {
+        Preconditions.checkArgument(
+                ALLOWED_CAPABILITIES.contains(capability),
+                "NetworkCapability " + capability + "out of range");
+    }
+
+    private static void validateRetryInterval(@Nullable long[] retryIntervalsMs) {
+        Preconditions.checkArgument(
+                retryIntervalsMs != null
+                        && retryIntervalsMs.length > 0
+                        && retryIntervalsMs.length <= MAX_RETRY_INTERVAL_COUNT,
+                "retryIntervalsMs was null, empty or exceed max interval count");
+
+        final long repeatingInterval = retryIntervalsMs[retryIntervalsMs.length - 1];
+        if (repeatingInterval < MINIMUM_REPEATING_RETRY_INTERVAL_MS) {
+            throw new IllegalArgumentException(
+                    "Repeating retry interval was too short, must be a minimum of 15 minutes: "
+                            + repeatingInterval);
+        }
+    }
 
     /**
-     * Validates this configuration
+     * Returns all exposed capabilities.
      *
      * @hide
      */
-    private void validate() {
-        // TODO: implement validation logic
+    @NonNull
+    public Set<Integer> getAllExposedCapabilities() {
+        return Collections.unmodifiableSet(mExposedCapabilities);
     }
 
-    // Parcelable methods
+    /**
+     * Checks if this config is configured to support/expose a specific capability.
+     *
+     * @param capability the capability to check for
+     */
+    public boolean hasExposedCapability(@NetCapability int capability) {
+        checkValidCapability(capability);
 
-    /** This class is used to incrementally build {@link VcnGatewayConnectionConfig} objects */
+        return mExposedCapabilities.contains(capability);
+    }
+
+    /**
+     * Returns all capabilities required of underlying networks.
+     *
+     * @hide
+     */
+    @NonNull
+    public Set<Integer> getAllUnderlyingCapabilities() {
+        return Collections.unmodifiableSet(mUnderlyingCapabilities);
+    }
+
+    /**
+     * Checks if this config requires an underlying network to have the specified capability.
+     *
+     * @param capability the capability to check for
+     */
+    public boolean requiresUnderlyingCapability(@NetCapability int capability) {
+        checkValidCapability(capability);
+
+        return mUnderlyingCapabilities.contains(capability);
+    }
+
+    /** Retrieves the configured retry intervals. */
+    @NonNull
+    public long[] getRetryIntervalsMs() {
+        return Arrays.copyOf(mRetryIntervalsMs, mRetryIntervalsMs.length);
+    }
+
+    /** Retrieves the maximum MTU allowed for this Gateway Connection. */
+    @IntRange(from = MIN_MTU_V6)
+    public int getMaxMtu() {
+        return mMaxMtu;
+    }
+
+    /**
+     * Converts this config to a PersistableBundle.
+     *
+     * @hide
+     */
+    @NonNull
+    @VisibleForTesting(visibility = Visibility.PROTECTED)
+    public PersistableBundle toPersistableBundle() {
+        final PersistableBundle result = new PersistableBundle();
+
+        final PersistableBundle exposedCapsBundle =
+                PersistableBundleUtils.fromList(
+                        new ArrayList<>(mExposedCapabilities),
+                        PersistableBundleUtils.INTEGER_SERIALIZER);
+        final PersistableBundle underlyingCapsBundle =
+                PersistableBundleUtils.fromList(
+                        new ArrayList<>(mUnderlyingCapabilities),
+                        PersistableBundleUtils.INTEGER_SERIALIZER);
+
+        result.putPersistableBundle(EXPOSED_CAPABILITIES_KEY, exposedCapsBundle);
+        result.putPersistableBundle(UNDERLYING_CAPABILITIES_KEY, underlyingCapsBundle);
+        result.putLongArray(RETRY_INTERVAL_MS_KEY, mRetryIntervalsMs);
+        result.putInt(MAX_MTU_KEY, mMaxMtu);
+
+        return result;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(
+                mExposedCapabilities,
+                mUnderlyingCapabilities,
+                Arrays.hashCode(mRetryIntervalsMs),
+                mMaxMtu);
+    }
+
+    @Override
+    public boolean equals(@Nullable Object other) {
+        if (!(other instanceof VcnGatewayConnectionConfig)) {
+            return false;
+        }
+
+        final VcnGatewayConnectionConfig rhs = (VcnGatewayConnectionConfig) other;
+        return mExposedCapabilities.equals(rhs.mExposedCapabilities)
+                && mUnderlyingCapabilities.equals(rhs.mUnderlyingCapabilities)
+                && Arrays.equals(mRetryIntervalsMs, rhs.mRetryIntervalsMs)
+                && mMaxMtu == rhs.mMaxMtu;
+    }
+
+    /** This class is used to incrementally build {@link VcnGatewayConnectionConfig} objects. */
     public static class Builder {
-        // TODO: Implement this builder
+        @NonNull private final Set<Integer> mExposedCapabilities = new ArraySet();
+        @NonNull private final Set<Integer> mUnderlyingCapabilities = new ArraySet();
+        @NonNull private long[] mRetryIntervalsMs = DEFAULT_RETRY_INTERVALS_MS;
+        private int mMaxMtu = DEFAULT_MAX_MTU;
+
+        // TODO: (b/175829816) Consider VCN-exposed capabilities that may be transport dependent.
+        //       Consider the case where the VCN might only expose MMS on WiFi, but defer to MMS
+        //       when on Cell.
 
         /**
-         * Builds and validates the VcnGatewayConnectionConfig
+         * Add a capability that this VCN Gateway Connection will support.
+         *
+         * @param exposedCapability the app-facing capability to be exposed by this VCN Gateway
+         *     Connection (i.e., the capabilities that this VCN Gateway Connection will support).
+         * @return this {@link Builder} instance, for chaining
+         * @see VcnGatewayConnectionConfig for a list of capabilities may be exposed by a Gateway
+         *     Connection
+         */
+        public Builder addExposedCapability(@NetCapability int exposedCapability) {
+            checkValidCapability(exposedCapability);
+
+            mExposedCapabilities.add(exposedCapability);
+            return this;
+        }
+
+        /**
+         * Remove a capability that this VCN Gateway Connection will support.
+         *
+         * @param exposedCapability the app-facing capability to not be exposed by this VCN Gateway
+         *     Connection (i.e., the capabilities that this VCN Gateway Connection will support)
+         * @return this {@link Builder} instance, for chaining
+         * @see VcnGatewayConnectionConfig for a list of capabilities may be exposed by a Gateway
+         *     Connection
+         */
+        public Builder removeExposedCapability(@NetCapability int exposedCapability) {
+            checkValidCapability(exposedCapability);
+
+            mExposedCapabilities.remove(exposedCapability);
+            return this;
+        }
+
+        /**
+         * Require a capability for Networks underlying this VCN Gateway Connection.
+         *
+         * @param underlyingCapability the capability that a network MUST have in order to be an
+         *     underlying network for this VCN Gateway Connection.
+         * @return this {@link Builder} instance, for chaining
+         * @see VcnGatewayConnectionConfig for a list of capabilities may be required of underlying
+         *     networks
+         */
+        public Builder addRequiredUnderlyingCapability(@NetCapability int underlyingCapability) {
+            checkValidCapability(underlyingCapability);
+
+            mUnderlyingCapabilities.add(underlyingCapability);
+            return this;
+        }
+
+        /**
+         * Remove a requirement of a capability for Networks underlying this VCN Gateway Connection.
+         *
+         * <p>Calling this method will allow Networks that do NOT have this capability to be
+         * selected as an underlying network for this VCN Gateway Connection. However, underlying
+         * networks MAY still have the removed capability.
+         *
+         * @param underlyingCapability the capability that a network DOES NOT need to have in order
+         *     to be an underlying network for this VCN Gateway Connection.
+         * @return this {@link Builder} instance, for chaining
+         * @see VcnGatewayConnectionConfig for a list of capabilities may be required of underlying
+         *     networks
+         */
+        public Builder removeRequiredUnderlyingCapability(@NetCapability int underlyingCapability) {
+            checkValidCapability(underlyingCapability);
+
+            mUnderlyingCapabilities.remove(underlyingCapability);
+            return this;
+        }
+
+        /**
+         * Set the retry interval between VCN establishment attempts upon successive failures.
+         *
+         * <p>The last retry interval will be repeated until safe mode is entered, or a connection
+         * is successfully established, at which point the retry timers will be reset. For power
+         * reasons, the last (repeated) retry interval MUST be at least 15 minutes.
+         *
+         * <p>Retry intervals MAY be subject to system power saving modes. That is to say that if
+         * the system enters a power saving mode, the retry may not occur until the device leaves
+         * the specified power saving mode. Intervals are sequential, and intervals will NOT be
+         * skipped if system power saving results in delaying retries (even if it exceed multiple
+         * retry intervals).
+         *
+         * <p>Each Gateway Connection will retry according to the retry intervals configured, but if
+         * safe mode is enabled, all Gateway Connection(s) will be disabled.
+         *
+         * @param retryIntervalsMs an array of between 1 and 10 millisecond intervals after which
+         *     the VCN will attempt to retry a session initiation. The last (repeating) retry
+         *     interval must be at least 15 minutes. Defaults to: {@code [1s, 2s, 5s, 30s, 1m, 5m,
+         *     15m]}
+         * @return this {@link Builder} instance, for chaining
+         * @see VcnManager for additional discussion on fail-safe mode
+         */
+        @NonNull
+        public Builder setRetryInterval(@NonNull long[] retryIntervalsMs) {
+            validateRetryInterval(retryIntervalsMs);
+
+            mRetryIntervalsMs = retryIntervalsMs;
+            return this;
+        }
+
+        /**
+         * Sets the maximum MTU allowed for this VCN Gateway Connection.
+         *
+         * <p>This MTU is applied to the VCN Gateway Connection exposed Networks, and represents the
+         * MTU of the virtualized network.
+         *
+         * <p>The system may reduce the MTU below the maximum specified based on signals such as the
+         * MTU of the underlying networks (and adjusted for Gateway Connection overhead).
+         *
+         * @param maxMtu the maximum MTU allowed for this Gateway Connection. Must be greater than
+         *     the IPv6 minimum MTU of 1280. Defaults to 1500.
+         * @return this {@link Builder} instance, for chaining
+         */
+        @NonNull
+        public Builder setMaxMtu(@IntRange(from = MIN_MTU_V6) int maxMtu) {
+            Preconditions.checkArgument(
+                    maxMtu >= MIN_MTU_V6, "maxMtu must be at least IPv6 min MTU (1280)");
+
+            mMaxMtu = maxMtu;
+            return this;
+        }
+
+        /**
+         * Builds and validates the VcnGatewayConnectionConfig.
          *
          * @return an immutable VcnGatewayConnectionConfig instance
          */
         @NonNull
         public VcnGatewayConnectionConfig build() {
-            return new VcnGatewayConnectionConfig();
+            return new VcnGatewayConnectionConfig(
+                    mExposedCapabilities, mUnderlyingCapabilities, mRetryIntervalsMs, mMaxMtu);
         }
     }
 }
diff --git a/core/java/android/net/vcn/VcnManager.java b/core/java/android/net/vcn/VcnManager.java
index 6769b9e..19c183f 100644
--- a/core/java/android/net/vcn/VcnManager.java
+++ b/core/java/android/net/vcn/VcnManager.java
@@ -23,10 +23,37 @@
 import android.content.Context;
 import android.os.ParcelUuid;
 import android.os.RemoteException;
+import android.os.ServiceSpecificException;
+
+import java.io.IOException;
 
 /**
  * VcnManager publishes APIs for applications to configure and manage Virtual Carrier Networks.
  *
+ * <p>A VCN creates a virtualization layer to allow MVNOs to aggregate heterogeneous physical
+ * networks, unifying them as a single carrier network. This enables infrastructure flexibility on
+ * the part of MVNOs without impacting user connectivity, abstracting the physical network
+ * technologies as an implementation detail of their public network.
+ *
+ * <p>Each VCN virtualizes an Carrier's network by building tunnels to a carrier's core network over
+ * carrier-managed physical links and supports a IP mobility layer to ensure seamless transitions
+ * between the underlying networks. Each VCN is configured based on a Subscription Group (see {@link
+ * android.telephony.SubscriptionManager}) and aggregates all networks that are brought up based on
+ * a profile or suggestion in the specified Subscription Group.
+ *
+ * <p>The VCN can be configured to expose one or more {@link android.net.Network}(s), each with
+ * different capabilities, allowing for APN virtualization.
+ *
+ * <p>If a tunnel fails to connect, or otherwise encounters a fatal error, the VCN will attempt to
+ * reestablish the connection. If the tunnel still has not reconnected after a system-determined
+ * timeout, the VCN Safe Mode (see below) will be entered.
+ *
+ * <p>The VCN Safe Mode ensures that users (and carriers) have a fallback to restore system
+ * connectivity to update profiles, diagnose issues, contact support, or perform other remediation
+ * tasks. In Safe Mode, the system will allow underlying cellular networks to be used as default.
+ * Additionally, during Safe Mode, the VCN will continue to retry the connections, and will
+ * automatically exit Safe Mode if all active tunnels connect successfully.
+ *
  * @hide
  */
 @SystemService(Context.VCN_MANAGEMENT_SERVICE)
@@ -63,15 +90,20 @@
      * @param config the configuration parameters for the VCN
      * @throws SecurityException if the caller does not have carrier privileges, or is not running
      *     as the primary user
+     * @throws IOException if the configuration failed to be persisted. A caller encountering this
+     *     exception should attempt to retry (possibly after a delay).
      * @hide
      */
     @RequiresPermission("carrier privileges") // TODO (b/72967236): Define a system-wide constant
-    public void setVcnConfig(@NonNull ParcelUuid subscriptionGroup, @NonNull VcnConfig config) {
+    public void setVcnConfig(@NonNull ParcelUuid subscriptionGroup, @NonNull VcnConfig config)
+            throws IOException {
         requireNonNull(subscriptionGroup, "subscriptionGroup was null");
         requireNonNull(config, "config was null");
 
         try {
             mService.setVcnConfig(subscriptionGroup, config);
+        } catch (ServiceSpecificException e) {
+            throw new IOException(e);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -88,14 +120,18 @@
      * @param subscriptionGroup the subscription group that the configuration should be applied to
      * @throws SecurityException if the caller does not have carrier privileges, or is not running
      *     as the primary user
+     * @throws IOException if the configuration failed to be cleared. A caller encountering this
+     *     exception should attempt to retry (possibly after a delay).
      * @hide
      */
     @RequiresPermission("carrier privileges") // TODO (b/72967236): Define a system-wide constant
-    public void clearVcnConfig(@NonNull ParcelUuid subscriptionGroup) {
+    public void clearVcnConfig(@NonNull ParcelUuid subscriptionGroup) throws IOException {
         requireNonNull(subscriptionGroup, "subscriptionGroup was null");
 
         try {
             mService.clearVcnConfig(subscriptionGroup);
+        } catch (ServiceSpecificException e) {
+            throw new IOException(e);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
diff --git a/core/java/android/os/BatteryConsumer.java b/core/java/android/os/BatteryConsumer.java
index c476a59..bf8ac6e 100644
--- a/core/java/android/os/BatteryConsumer.java
+++ b/core/java/android/os/BatteryConsumer.java
@@ -36,7 +36,9 @@
      * @hide
      */
     @IntDef(prefix = {"POWER_COMPONENT_"}, value = {
+            POWER_COMPONENT_USAGE,
             POWER_COMPONENT_CPU,
+            POWER_COMPONENT_BLUETOOTH,
     })
     @Retention(RetentionPolicy.SOURCE)
     public static @interface PowerComponent {
@@ -44,8 +46,9 @@
 
     public static final int POWER_COMPONENT_USAGE = 0;
     public static final int POWER_COMPONENT_CPU = 1;
+    public static final int POWER_COMPONENT_BLUETOOTH = 2;
 
-    public static final int POWER_COMPONENT_COUNT = 2;
+    public static final int POWER_COMPONENT_COUNT = 3;
 
     public static final int FIRST_CUSTOM_POWER_COMPONENT_ID = 1000;
     public static final int LAST_CUSTOM_POWER_COMPONENT_ID = 9999;
@@ -68,8 +71,10 @@
      * @hide
      */
     @IntDef(prefix = {"TIME_COMPONENT_"}, value = {
+            TIME_COMPONENT_USAGE,
             TIME_COMPONENT_CPU,
             TIME_COMPONENT_CPU_FOREGROUND,
+            TIME_COMPONENT_BLUETOOTH,
     })
     @Retention(RetentionPolicy.SOURCE)
     public static @interface TimeComponent {
@@ -78,8 +83,9 @@
     public static final int TIME_COMPONENT_USAGE = 0;
     public static final int TIME_COMPONENT_CPU = 1;
     public static final int TIME_COMPONENT_CPU_FOREGROUND = 2;
+    public static final int TIME_COMPONENT_BLUETOOTH = 3;
 
-    public static final int TIME_COMPONENT_COUNT = 3;
+    public static final int TIME_COMPONENT_COUNT = 4;
 
     public static final int FIRST_CUSTOM_TIME_COMPONENT_ID = 1000;
     public static final int LAST_CUSTOM_TIME_COMPONENT_ID = 9999;
diff --git a/core/java/android/os/BatteryStatsManager.java b/core/java/android/os/BatteryStatsManager.java
index 3191eda..f21a812 100644
--- a/core/java/android/os/BatteryStatsManager.java
+++ b/core/java/android/os/BatteryStatsManager.java
@@ -26,6 +26,7 @@
 import android.content.Context;
 import android.os.connectivity.CellularBatteryStats;
 import android.os.connectivity.WifiBatteryStats;
+import android.telephony.DataConnectionRealTimeInfo;
 
 import com.android.internal.app.IBatteryStats;
 
@@ -85,7 +86,7 @@
     public static final int NUM_WIFI_STATES = WIFI_STATE_SOFT_AP + 1;
 
     /** @hide */
-    @IntDef(flag = true, prefix = { "WIFI_STATE_" }, value = {
+    @IntDef(prefix = { "WIFI_STATE_" }, value = {
             WIFI_STATE_OFF,
             WIFI_STATE_OFF_SCANNING,
             WIFI_STATE_ON_NO_NETWORKS,
@@ -135,7 +136,7 @@
     public static final int NUM_WIFI_SUPPL_STATES = WIFI_SUPPL_STATE_UNINITIALIZED + 1;
 
     /** @hide */
-    @IntDef(flag = true, prefix = { "WIFI_SUPPL_STATE_" }, value = {
+    @IntDef(prefix = { "WIFI_SUPPL_STATE_" }, value = {
             WIFI_SUPPL_STATE_INVALID,
             WIFI_SUPPL_STATE_DISCONNECTED,
             WIFI_SUPPL_STATE_INTERFACE_DISABLED,
@@ -405,4 +406,50 @@
             e.rethrowFromSystemServer();
         }
     }
+
+    /**
+     * Indicates that the radio power state has changed.
+     *
+     * @param isActive indicates if the mobile radio is powered.
+     * @param uid Uid of this event. For the active state it represents the uid that was responsible
+     *            for waking the radio, or -1 if the system was responsible for waking the radio.
+     *            For inactive state, the UID should always be -1.
+     * @throws RuntimeException if there are binder remote-invocation errors.
+     */
+    @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS)
+    public void reportMobileRadioPowerState(boolean isActive, int uid) throws RuntimeException {
+        try {
+            mBatteryStats.noteMobileRadioPowerState(getDataConnectionPowerState(isActive),
+                    SystemClock.elapsedRealtimeNanos(), uid);
+        } catch (RemoteException e) {
+            e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Indicates that the wifi power state has changed.
+     *
+     * @param isActive indicates if the wifi radio is powered.
+     * @param uid Uid of this event. For the active state it represents the uid that was responsible
+     *            for waking the radio, or -1 if the system was responsible for waking the radio.
+     *            For inactive state, the UID should always be -1.
+     * @throws RuntimeException if there are binder remote-invocation errors.
+     */
+    @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS)
+    public void reportWifiRadioPowerState(boolean isActive, int uid) throws RuntimeException {
+        try {
+            mBatteryStats.noteWifiRadioPowerState(getDataConnectionPowerState(isActive),
+                    SystemClock.elapsedRealtimeNanos(), uid);
+        } catch (RemoteException e) {
+            e.rethrowFromSystemServer();
+        }
+    }
+
+    private static int getDataConnectionPowerState(boolean isActive) {
+        // TODO: DataConnectionRealTimeInfo is under telephony package but the constants are used
+        // for both Wifi and mobile. It would make more sense to separate the constants to a generic
+        // class or move it to generic package.
+        return isActive ? DataConnectionRealTimeInfo.DC_POWER_STATE_HIGH
+                : DataConnectionRealTimeInfo.DC_POWER_STATE_LOW;
+    }
 }
diff --git a/core/java/android/os/Debug.java b/core/java/android/os/Debug.java
index e2e1bbe..9584bc7 100644
--- a/core/java/android/os/Debug.java
+++ b/core/java/android/os/Debug.java
@@ -2582,6 +2582,13 @@
     public static native long getIonMappedSizeKb();
 
     /**
+     * Return memory size in kilobytes used by GPU.
+     *
+     * @hide
+     */
+    public static native long getGpuTotalUsageKb();
+
+    /**
      * Return whether virtually-mapped kernel stacks are enabled (CONFIG_VMAP_STACK).
      * Note: caller needs config_gz read sepolicy permission
      *
diff --git a/core/java/android/os/FileUtils.java b/core/java/android/os/FileUtils.java
index 92fe98c..c014ef6 100644
--- a/core/java/android/os/FileUtils.java
+++ b/core/java/android/os/FileUtils.java
@@ -83,6 +83,7 @@
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.Comparator;
+import java.util.Locale;
 import java.util.Objects;
 import java.util.concurrent.Executor;
 import java.util.concurrent.TimeUnit;
@@ -115,6 +116,9 @@
     private FileUtils() {
     }
 
+    private static final String CAMERA_DIR_LOWER_CASE = "/storage/emulated/" + UserHandle.myUserId()
+            + "/dcim/camera";
+
     /** Regular expression for safe filenames: no spaces or metacharacters.
       *
       * Use a preload holder so that FileUtils can be compile-time initialized.
@@ -1432,18 +1436,27 @@
         }
     }
 
+    // TODO(b/170488060): Consider better approach
     /** {@hide} */
+    @VisibleForTesting
     public static FileDescriptor convertToModernFd(FileDescriptor fd) {
         try {
             Context context = AppGlobals.getInitialApplication();
+            File realFile = ParcelFileDescriptor.getFile(fd);
+            String fileName = realFile.getName();
+            boolean isCameraVideo = !fileName.startsWith(".") && fileName.endsWith(".mp4")
+                    && contains(CAMERA_DIR_LOWER_CASE, realFile.getAbsolutePath().toLowerCase(
+                                    Locale.ROOT));
+
             if (!SystemProperties.getBoolean("sys.fuse.transcode_enabled", false)
-                    || UserHandle.getAppId(Process.myUid()) == getMediaProviderAppId(context)) {
-                // If transcode is enabled we optimize by default, unless explicitly disabled.
-                // Never convert modern fd for MediaProvider, because this requires
+                    || UserHandle.getAppId(Process.myUid()) == getMediaProviderAppId(context)
+                    || !isCameraVideo) {
+                // 1. If transcode is enabled we optimize by default, unless explicitly disabled.
+                // 2. Never convert modern fd for MediaProvider, because this requires
                 // MediaStore#scanFile and can cause infinite loops when MediaProvider scans
+                // 3. Only convert published mp4 videos in the DCIM/Camera dir
                 return null;
             }
-            File realFile = ParcelFileDescriptor.getFile(fd);
             Log.i(TAG, "Changing to modern format dataSource for: " + realFile);
             ContentResolver resolver = context.getContentResolver();
 
diff --git a/core/java/android/os/IRecoverySystem.aidl b/core/java/android/os/IRecoverySystem.aidl
index 5f8b932..2052883 100644
--- a/core/java/android/os/IRecoverySystem.aidl
+++ b/core/java/android/os/IRecoverySystem.aidl
@@ -30,5 +30,6 @@
     boolean requestLskf(in String packageName, in IntentSender sender);
     boolean clearLskf(in String packageName);
     boolean isLskfCaptured(in String packageName);
+    boolean rebootWithLskfAssumeSlotSwitch(in String packageName, in String reason);
     boolean rebootWithLskf(in String packageName, in String reason, in boolean slotSwitch);
 }
diff --git a/core/java/android/os/PowerComponents.java b/core/java/android/os/PowerComponents.java
index 4a73b24..18dca68 100644
--- a/core/java/android/os/PowerComponents.java
+++ b/core/java/android/os/PowerComponents.java
@@ -289,6 +289,15 @@
             return this;
         }
 
+        public void addPowerAndDuration(Builder other) {
+            for (int i = 0; i < mPowerComponents.length; i++) {
+                mPowerComponents[i] += other.mPowerComponents[i];
+            }
+            for (int i = 0; i < mTimeComponents.length; i++) {
+                mTimeComponents[i] += other.mTimeComponents[i];
+            }
+        }
+
         /**
          * Creates a read-only object out of the Builder values.
          */
diff --git a/core/java/android/os/RecoverySystem.java b/core/java/android/os/RecoverySystem.java
index 5f3cfa3..93c1690 100644
--- a/core/java/android/os/RecoverySystem.java
+++ b/core/java/android/os/RecoverySystem.java
@@ -687,8 +687,8 @@
     }
 
     /**
-     * Request that the device reboot and apply the update that has been prepared. Callers are
-     * recommended to use {@link #rebootAndApply(Context, String, boolean)} instead.
+     * Request that the device reboot and apply the update that has been prepared. This API is
+     * deprecated, and is expected to be used by OTA only on devices running Android 11.
      *
      * @param context the Context to use.
      * @param updateToken this parameter is deprecated and won't be used. See details in
@@ -699,18 +699,18 @@
      *               unattended reboot or if the {@code updateToken} did not match the previously
      *               given token
      * @hide
+     * @deprecated Use {@link #rebootAndApply(Context, String, boolean)} instead
      */
     @SystemApi
-    @RequiresPermission(anyOf = {android.Manifest.permission.RECOVERY,
-            android.Manifest.permission.REBOOT})
+    @RequiresPermission(android.Manifest.permission.RECOVERY)
     public static void rebootAndApply(@NonNull Context context, @NonNull String updateToken,
             @NonNull String reason) throws IOException {
         if (updateToken == null) {
             throw new NullPointerException("updateToken == null");
         }
         RecoverySystem rs = (RecoverySystem) context.getSystemService(Context.RECOVERY_SERVICE);
-        // OTA is the sole user before S, and a slot switch is required for ota update.
-        if (!rs.rebootWithLskf(context.getPackageName(), reason, true)) {
+        // OTA is the sole user, who expects a slot switch.
+        if (!rs.rebootWithLskfAssumeSlotSwitch(context.getPackageName(), reason)) {
             throw new IOException("system not prepared to apply update");
         }
     }
@@ -738,7 +738,7 @@
      *
      * @param context the Context to use.
      * @param reason the reboot reason to give to the {@link PowerManager}
-     * @param slotSwitch true if the caller intends to switch the slot on an A/B device.
+     * @param slotSwitch true if the caller expects the slot to be switched on A/B devices.
      * @throws IOException if the reboot couldn't proceed because the device wasn't ready for an
      *               unattended reboot.
      * @hide
@@ -1395,6 +1395,21 @@
         }
     }
 
+
+    /**
+     * Calls the recovery system service to reboot and apply update. This is the legacy API and
+     * expects a slot switch for A/B devices.
+     *
+     */
+    private boolean rebootWithLskfAssumeSlotSwitch(String packageName, String reason)
+            throws IOException {
+        try {
+            return mService.rebootWithLskfAssumeSlotSwitch(packageName, reason);
+        } catch (RemoteException e) {
+            throw new IOException("could not reboot for update");
+        }
+    }
+
     /**
      * Internally, recovery treats each line of the command file as a separate
      * argv, so we only need to protect against newlines and nulls.
diff --git a/core/java/android/os/SystemBatteryConsumer.java b/core/java/android/os/SystemBatteryConsumer.java
index bda2f23..08e358f 100644
--- a/core/java/android/os/SystemBatteryConsumer.java
+++ b/core/java/android/os/SystemBatteryConsumer.java
@@ -21,6 +21,8 @@
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
+import java.util.ArrayList;
+import java.util.List;
 
 
 /**
@@ -118,6 +120,7 @@
     public static final class Builder extends BaseBuilder<Builder> {
         @DrainType
         private final int mDrainType;
+        private List<UidBatteryConsumer.Builder> mUidBatteryConsumers;
 
         Builder(int customPowerComponentCount, int customTimeComponentCount,
                 boolean includeModeledComponents, @DrainType int drainType) {
@@ -126,10 +129,35 @@
         }
 
         /**
+         * Add a UidBatteryConsumer to this SystemBatteryConsumer. For example,
+         * the UidBatteryConsumer with the UID == {@link Process#BLUETOOTH_UID} should
+         * be added to the SystemBatteryConsumer with the drain type == {@link
+         * #DRAIN_TYPE_BLUETOOTH}.
+         * <p>
+         * Calculated power and duration components of the added battery consumers
+         * are aggregated at the time the SystemBatteryConsumer is built by the {@link #build()}
+         * method.
+         * </p>
+         */
+        public void addUidBatteryConsumer(UidBatteryConsumer.Builder uidBatteryConsumerBuilder) {
+            if (mUidBatteryConsumers == null) {
+                mUidBatteryConsumers = new ArrayList<>();
+            }
+            mUidBatteryConsumers.add(uidBatteryConsumerBuilder);
+        }
+
+        /**
          * Creates a read-only object out of the Builder values.
          */
         @NonNull
         public SystemBatteryConsumer build() {
+            if (mUidBatteryConsumers != null) {
+                for (int i = mUidBatteryConsumers.size() - 1; i >= 0; i--) {
+                    UidBatteryConsumer.Builder uidBatteryConsumer = mUidBatteryConsumers.get(i);
+                    mPowerComponentsBuilder.addPowerAndDuration(
+                            uidBatteryConsumer.mPowerComponentsBuilder);
+                }
+            }
             return new SystemBatteryConsumer(this);
         }
     }
diff --git a/core/java/android/os/UidBatteryConsumer.java b/core/java/android/os/UidBatteryConsumer.java
index c5da22b..3161766 100644
--- a/core/java/android/os/UidBatteryConsumer.java
+++ b/core/java/android/os/UidBatteryConsumer.java
@@ -29,11 +29,21 @@
     private final int mUid;
     @Nullable
     private final String mPackageWithHighestDrain;
+    private boolean mSystemComponent;
 
     public int getUid() {
         return mUid;
     }
 
+    /**
+     * Returns true if this battery consumer is considered to be a part of the operating
+     * system itself. For example, the UidBatteryConsumer with the UID {@link Process#BLUETOOTH_UID}
+     * is a system component.
+     */
+    public boolean isSystemComponent() {
+        return mSystemComponent;
+    }
+
     @Nullable
     public String getPackageWithHighestDrain() {
         return mPackageWithHighestDrain;
@@ -42,6 +52,7 @@
     private UidBatteryConsumer(@NonNull Builder builder) {
         super(builder.mPowerComponentsBuilder.build());
         mUid = builder.mUid;
+        mSystemComponent = builder.mSystemComponent;
         mPackageWithHighestDrain = builder.mPackageWithHighestDrain;
     }
 
@@ -84,6 +95,7 @@
         private final BatteryStats.Uid mBatteryStatsUid;
         private final int mUid;
         private String mPackageWithHighestDrain;
+        private boolean mSystemComponent;
 
         public Builder(int customPowerComponentCount, int customTimeComponentCount,
                 boolean includeModeledComponents, BatteryStats.Uid batteryStatsUid) {
@@ -117,5 +129,14 @@
             mPackageWithHighestDrain = packageName;
             return this;
         }
+
+        /**
+         * Marks the UidBatteryConsumer as part of the system. For example,
+         * the UidBatteryConsumer with the UID {@link Process#BLUETOOTH_UID} is considered
+         * as a system component.
+         */
+        public void setSystemComponent(boolean systemComponent) {
+            mSystemComponent = systemComponent;
+        }
     }
 }
diff --git a/core/java/android/os/incremental/OWNERS b/core/java/android/os/incremental/OWNERS
new file mode 100644
index 0000000..3795493
--- /dev/null
+++ b/core/java/android/os/incremental/OWNERS
@@ -0,0 +1,5 @@
+# Bug component: 554432
+alexbuy@google.com
+schfan@google.com
+toddke@google.com
+zyy@google.com
diff --git a/core/java/android/permission/IPermissionManager.aidl b/core/java/android/permission/IPermissionManager.aidl
index 4ad17ef..441908d 100644
--- a/core/java/android/permission/IPermissionManager.aidl
+++ b/core/java/android/permission/IPermissionManager.aidl
@@ -56,13 +56,13 @@
 
     void removeOnPermissionsChangeListener(in IOnPermissionsChangeListener listener);
 
-    List<String> getWhitelistedRestrictedPermissions(String packageName,
+    List<String> getAllowlistedRestrictedPermissions(String packageName,
             int flags, int userId);
 
-    boolean addWhitelistedRestrictedPermission(String packageName, String permName,
+    boolean addAllowlistedRestrictedPermission(String packageName, String permissionName,
             int flags, int userId);
 
-    boolean removeWhitelistedRestrictedPermission(String packageName, String permName,
+    boolean removeAllowlistedRestrictedPermission(String packageName, String permissionName,
             int flags, int userId);
 
     void grantRuntimePermission(String packageName, String permName, int userId);
@@ -87,7 +87,7 @@
 
     List<String> getAutoRevokeExemptionGrantedPackages(int userId);
 
-    boolean setAutoRevokeWhitelisted(String packageName, boolean whitelisted, int userId);
+    boolean setAutoRevokeExempted(String packageName, boolean exempted, int userId);
 
-    boolean isAutoRevokeWhitelisted(String packageName, int userId);
+    boolean isAutoRevokeExempted(String packageName, int userId);
 }
diff --git a/core/java/android/permission/PermissionManager.java b/core/java/android/permission/PermissionManager.java
index d31e012..87f3764 100644
--- a/core/java/android/permission/PermissionManager.java
+++ b/core/java/android/permission/PermissionManager.java
@@ -510,7 +510,7 @@
     public Set<String> getAllowlistedRestrictedPermissions(@NonNull String packageName,
             @PackageManager.PermissionWhitelistFlags int allowlistFlag) {
         try {
-            final List<String> allowlist = mPermissionManager.getWhitelistedRestrictedPermissions(
+            final List<String> allowlist = mPermissionManager.getAllowlistedRestrictedPermissions(
                     packageName, allowlistFlag, mContext.getUserId());
             if (allowlist == null) {
                 return Collections.emptySet();
@@ -578,7 +578,7 @@
             @NonNull String permissionName,
             @PackageManager.PermissionWhitelistFlags int allowlistFlags) {
         try {
-            return mPermissionManager.addWhitelistedRestrictedPermission(packageName,
+            return mPermissionManager.addAllowlistedRestrictedPermission(packageName,
                     permissionName, allowlistFlags, mContext.getUserId());
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
@@ -642,7 +642,7 @@
             @NonNull String permissionName,
             @PackageManager.PermissionWhitelistFlags int allowlistFlags) {
         try {
-            return mPermissionManager.removeWhitelistedRestrictedPermission(packageName,
+            return mPermissionManager.removeAllowlistedRestrictedPermission(packageName,
                     permissionName, allowlistFlags, mContext.getUserId());
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
@@ -668,7 +668,7 @@
             conditional = true)
     public boolean isAutoRevokeExempted(@NonNull String packageName) {
         try {
-            return mPermissionManager.isAutoRevokeWhitelisted(packageName, mContext.getUserId());
+            return mPermissionManager.isAutoRevokeExempted(packageName, mContext.getUserId());
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -697,7 +697,7 @@
             conditional = true)
     public boolean setAutoRevokeExempted(@NonNull String packageName, boolean exempted) {
         try {
-            return mPermissionManager.setAutoRevokeWhitelisted(packageName, exempted,
+            return mPermissionManager.setAutoRevokeExempted(packageName, exempted,
                     mContext.getUserId());
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
diff --git a/core/java/android/provider/ContactsContract.java b/core/java/android/provider/ContactsContract.java
index b2b8db1..376d942 100644
--- a/core/java/android/provider/ContactsContract.java
+++ b/core/java/android/provider/ContactsContract.java
@@ -4313,13 +4313,23 @@
          * <P>
          * Type: INTEGER (A bitmask of CARRIER_PRESENCE_* fields)
          * </P>
+         *
+         * @deprecated The contacts database will only show presence
+         * information on devices where
+         * {@link android.telephony.CarrierConfigManager#KEY_USE_RCS_PRESENCE_BOOL} is true,
+         * otherwise use {@link android.telephony.ims.RcsUceAdapter}.
          */
+        @Deprecated
         public static final String CARRIER_PRESENCE = "carrier_presence";
 
         /**
          * Indicates that the entry is Video Telephony (VT) capable on the
          * current carrier. An allowed bitmask of {@link #CARRIER_PRESENCE}.
+         *
+         * @deprecated Same as {@link DataColumns#CARRIER_PRESENCE}.
+         *
          */
+        @Deprecated
         public static final int CARRIER_PRESENCE_VT_CAPABLE = 0x01;
 
         /**
diff --git a/core/java/android/service/attestation/OWNERS b/core/java/android/service/attestation/OWNERS
new file mode 100644
index 0000000..b9e7b99
--- /dev/null
+++ b/core/java/android/service/attestation/OWNERS
@@ -0,0 +1,2 @@
+chaviw@google.com
+ogunwale@google.com
diff --git a/core/java/android/text/style/SuggestionSpan.java b/core/java/android/text/style/SuggestionSpan.java
index 1f15d46..4a48832 100644
--- a/core/java/android/text/style/SuggestionSpan.java
+++ b/core/java/android/text/style/SuggestionSpan.java
@@ -402,6 +402,10 @@
             }
         } else if (autoCorrection) {
             tp.setUnderlineText(mAutoCorrectionUnderlineColor, mAutoCorrectionUnderlineThickness);
+        } else if (misspelled) {
+            tp.setUnderlineText(mMisspelledUnderlineColor, mMisspelledUnderlineThickness);
+        } else if (grammarError) {
+            tp.setUnderlineText(mGrammarErrorUnderlineColor, mGrammarErrorUnderlineThickness);
         }
     }
 
@@ -425,6 +429,10 @@
             }
         } else if (autoCorrection) {
             return mAutoCorrectionUnderlineColor;
+        } else if (misspelled) {
+            return mMisspelledUnderlineColor;
+        } else if (grammarError) {
+            return mGrammarErrorUnderlineColor;
         }
         return 0;
     }
diff --git a/core/java/android/util/Xml.java b/core/java/android/util/Xml.java
index c8193b3..38decf9 100644
--- a/core/java/android/util/Xml.java
+++ b/core/java/android/util/Xml.java
@@ -18,6 +18,7 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.os.SystemProperties;
 import android.system.ErrnoException;
 import android.system.Os;
 
@@ -64,8 +65,11 @@
     /**
      * Feature flag: when set, {@link #resolveSerializer(OutputStream)} will
      * emit binary XML by default.
+     *
+     * @hide
      */
-    private static final boolean ENABLE_BINARY_DEFAULT = false;
+    public static final boolean ENABLE_BINARY_DEFAULT = SystemProperties
+            .getBoolean("persist.sys.binary_xml", true);
 
     /**
      * Parses the given xml string and fires events on the given SAX handler.
@@ -172,7 +176,7 @@
             if (!in.markSupported()) {
                 in = new BufferedInputStream(in);
             }
-            in.mark(4);
+            in.mark(8);
             in.read(magic);
             in.reset();
         }
diff --git a/core/java/android/view/AccessibilityInteractionController.java b/core/java/android/view/AccessibilityInteractionController.java
index 2e90619..9473845 100644
--- a/core/java/android/view/AccessibilityInteractionController.java
+++ b/core/java/android/view/AccessibilityInteractionController.java
@@ -113,8 +113,6 @@
 
     private AddNodeInfosForViewId mAddNodeInfosForViewId;
 
-    private List<Message> mPendingFindNodeByIdMessages;
-
     @GuardedBy("mLock")
     private int mNumActiveRequestPreparers;
     @GuardedBy("mLock")
@@ -130,7 +128,6 @@
         mViewRootImpl = viewRootImpl;
         mPrefetcher = new AccessibilityNodePrefetcher();
         mA11yManager = mViewRootImpl.mContext.getSystemService(AccessibilityManager.class);
-        mPendingFindNodeByIdMessages = new ArrayList<>();
     }
 
     private void scheduleMessage(Message message, int interrogatingPid, long interrogatingTid,
@@ -180,7 +177,6 @@
         args.arg4 = arguments;
         message.obj = args;
 
-        mPendingFindNodeByIdMessages.add(message);
         scheduleMessage(message, interrogatingPid, interrogatingTid, CONSIDER_REQUEST_PREPARERS);
     }
 
@@ -319,8 +315,6 @@
     }
 
     private void findAccessibilityNodeInfoByAccessibilityIdUiThread(Message message) {
-        mPendingFindNodeByIdMessages.remove(message);
-
         final int flags = message.arg1;
 
         SomeArgs args = (SomeArgs) message.obj;
@@ -335,58 +329,22 @@
 
         args.recycle();
 
-        View rootView = null;
-        AccessibilityNodeInfo rootNode = null;
+        List<AccessibilityNodeInfo> infos = mTempAccessibilityNodeInfoList;
+        infos.clear();
         try {
             if (mViewRootImpl.mView == null || mViewRootImpl.mAttachInfo == null) {
                 return;
             }
             mViewRootImpl.mAttachInfo.mAccessibilityFetchFlags = flags;
-            rootView = findViewByAccessibilityId(accessibilityViewId);
-            if (rootView != null && isShown(rootView)) {
-                rootNode = populateAccessibilityNodeInfoForView(
-                        rootView, arguments, virtualDescendantId);
+            final View root = findViewByAccessibilityId(accessibilityViewId);
+            if (root != null && isShown(root)) {
+                mPrefetcher.prefetchAccessibilityNodeInfos(
+                        root, virtualDescendantId, flags, infos, arguments);
             }
         } finally {
-            updateInfoForViewportAndReturnFindNodeResult(
-                    rootNode == null ? null : AccessibilityNodeInfo.obtain(rootNode),
-                    callback, interactionId, spec, interactiveRegion);
+            updateInfosForViewportAndReturnFindNodeResult(
+                    infos, callback, interactionId, spec, interactiveRegion);
         }
-        List<AccessibilityNodeInfo> infos = mTempAccessibilityNodeInfoList;
-        infos.clear();
-        mPrefetcher.prefetchAccessibilityNodeInfos(
-                rootView, rootNode == null ? null : AccessibilityNodeInfo.obtain(rootNode),
-                virtualDescendantId, flags, infos);
-        mViewRootImpl.mAttachInfo.mAccessibilityFetchFlags = 0;
-        updateInfosForViewPort(infos, spec, interactiveRegion);
-        returnPrefetchResult(interactionId, infos, callback);
-        returnPendingFindAccessibilityNodeInfosInPrefetch(infos);
-    }
-
-    private AccessibilityNodeInfo populateAccessibilityNodeInfoForView(
-            View view, Bundle arguments, int virtualViewId) {
-        AccessibilityNodeProvider provider = view.getAccessibilityNodeProvider();
-        // Determine if we'll be populating extra data
-        final String extraDataRequested = (arguments == null) ? null
-                : arguments.getString(EXTRA_DATA_REQUESTED_KEY);
-        AccessibilityNodeInfo root = null;
-        if (provider == null) {
-            root = view.createAccessibilityNodeInfo();
-            if (root != null) {
-                if (extraDataRequested != null) {
-                    view.addExtraDataToAccessibilityNodeInfo(root, extraDataRequested, arguments);
-                }
-            }
-        } else {
-            root = provider.createAccessibilityNodeInfo(virtualViewId);
-            if (root != null) {
-                if (extraDataRequested != null) {
-                    provider.addExtraDataToAccessibilityNodeInfo(
-                            virtualViewId, root, extraDataRequested, arguments);
-                }
-            }
-        }
-        return root;
     }
 
     public void findAccessibilityNodeInfosByViewIdClientThread(long accessibilityNodeId,
@@ -444,7 +402,6 @@
                 mAddNodeInfosForViewId.reset();
             }
         } finally {
-            mViewRootImpl.mAttachInfo.mAccessibilityFetchFlags = 0;
             updateInfosForViewportAndReturnFindNodeResult(
                     infos, callback, interactionId, spec, interactiveRegion);
         }
@@ -527,7 +484,6 @@
                 }
             }
         } finally {
-            mViewRootImpl.mAttachInfo.mAccessibilityFetchFlags = 0;
             updateInfosForViewportAndReturnFindNodeResult(
                     infos, callback, interactionId, spec, interactiveRegion);
         }
@@ -619,7 +575,6 @@
                 }
             }
         } finally {
-            mViewRootImpl.mAttachInfo.mAccessibilityFetchFlags = 0;
             updateInfoForViewportAndReturnFindNodeResult(
                     focused, callback, interactionId, spec, interactiveRegion);
         }
@@ -674,7 +629,6 @@
                 }
             }
         } finally {
-            mViewRootImpl.mAttachInfo.mAccessibilityFetchFlags = 0;
             updateInfoForViewportAndReturnFindNodeResult(
                     next, callback, interactionId, spec, interactiveRegion);
         }
@@ -831,6 +785,33 @@
         }
     }
 
+    private void applyAppScaleAndMagnificationSpecIfNeeded(List<AccessibilityNodeInfo> infos,
+            MagnificationSpec spec) {
+        if (infos == null) {
+            return;
+        }
+        final float applicationScale = mViewRootImpl.mAttachInfo.mApplicationScale;
+        if (shouldApplyAppScaleAndMagnificationSpec(applicationScale, spec)) {
+            final int infoCount = infos.size();
+            for (int i = 0; i < infoCount; i++) {
+                AccessibilityNodeInfo info = infos.get(i);
+                applyAppScaleAndMagnificationSpecIfNeeded(info, spec);
+            }
+        }
+    }
+
+    private void adjustIsVisibleToUserIfNeeded(List<AccessibilityNodeInfo> infos,
+            Region interactiveRegion) {
+        if (interactiveRegion == null || infos == null) {
+            return;
+        }
+        final int infoCount = infos.size();
+        for (int i = 0; i < infoCount; i++) {
+            AccessibilityNodeInfo info = infos.get(i);
+            adjustIsVisibleToUserIfNeeded(info, interactiveRegion);
+        }
+    }
+
     private void adjustIsVisibleToUserIfNeeded(AccessibilityNodeInfo info,
             Region interactiveRegion) {
         if (interactiveRegion == null || info == null) {
@@ -851,6 +832,17 @@
         return false;
     }
 
+    private void adjustBoundsInScreenIfNeeded(List<AccessibilityNodeInfo> infos) {
+        if (infos == null || shouldBypassAdjustBoundsInScreen()) {
+            return;
+        }
+        final int infoCount = infos.size();
+        for (int i = 0; i < infoCount; i++) {
+            final AccessibilityNodeInfo info = infos.get(i);
+            adjustBoundsInScreenIfNeeded(info);
+        }
+    }
+
     private void adjustBoundsInScreenIfNeeded(AccessibilityNodeInfo info) {
         if (info == null || shouldBypassAdjustBoundsInScreen()) {
             return;
@@ -898,6 +890,17 @@
         return screenMatrix == null || screenMatrix.isIdentity();
     }
 
+    private void associateLeashedParentIfNeeded(List<AccessibilityNodeInfo> infos) {
+        if (infos == null || shouldBypassAssociateLeashedParent()) {
+            return;
+        }
+        final int infoCount = infos.size();
+        for (int i = 0; i < infoCount; i++) {
+            final AccessibilityNodeInfo info = infos.get(i);
+            associateLeashedParentIfNeeded(info);
+        }
+    }
+
     private void associateLeashedParentIfNeeded(AccessibilityNodeInfo info) {
         if (info == null || shouldBypassAssociateLeashedParent()) {
             return;
@@ -971,46 +974,18 @@
         return (appScale != 1.0f || (spec != null && !spec.isNop()));
     }
 
-    private void updateInfosForViewPort(List<AccessibilityNodeInfo> infos, MagnificationSpec spec,
-                                        Region interactiveRegion) {
-        for (int i = 0; i < infos.size(); i++) {
-            updateInfoForViewPort(infos.get(i), spec, interactiveRegion);
-        }
-    }
-
-    private void updateInfoForViewPort(AccessibilityNodeInfo info, MagnificationSpec spec,
-                                       Region interactiveRegion) {
-        associateLeashedParentIfNeeded(info);
-        applyScreenMatrixIfNeeded(info);
-        adjustBoundsInScreenIfNeeded(info);
-        // To avoid applyAppScaleAndMagnificationSpecIfNeeded changing the bounds of node,
-        // then impact the visibility result, we need to adjust visibility before apply scale.
-        adjustIsVisibleToUserIfNeeded(info, interactiveRegion);
-        applyAppScaleAndMagnificationSpecIfNeeded(info, spec);
-    }
-
     private void updateInfosForViewportAndReturnFindNodeResult(List<AccessibilityNodeInfo> infos,
             IAccessibilityInteractionConnectionCallback callback, int interactionId,
             MagnificationSpec spec, Region interactiveRegion) {
-        if (infos != null) {
-            updateInfosForViewPort(infos, spec, interactiveRegion);
-        }
-        returnFindNodesResult(infos, callback, interactionId);
-    }
-
-    private void returnFindNodeResult(AccessibilityNodeInfo info,
-                                      IAccessibilityInteractionConnectionCallback callback,
-                                      int interactionId) {
         try {
-            callback.setFindAccessibilityNodeInfoResult(info, interactionId);
-        } catch (RemoteException re) {
-            /* ignore - the other side will time out */
-        }
-    }
-
-    private void returnFindNodesResult(List<AccessibilityNodeInfo> infos,
-            IAccessibilityInteractionConnectionCallback callback, int interactionId) {
-        try {
+            mViewRootImpl.mAttachInfo.mAccessibilityFetchFlags = 0;
+            associateLeashedParentIfNeeded(infos);
+            applyScreenMatrixIfNeeded(infos);
+            adjustBoundsInScreenIfNeeded(infos);
+            // To avoid applyAppScaleAndMagnificationSpecIfNeeded changing the bounds of node,
+            // then impact the visibility result, we need to adjust visibility before apply scale.
+            adjustIsVisibleToUserIfNeeded(infos, interactiveRegion);
+            applyAppScaleAndMagnificationSpecIfNeeded(infos, spec);
             callback.setFindAccessibilityNodeInfosResult(infos, interactionId);
             if (infos != null) {
                 infos.clear();
@@ -1020,49 +995,22 @@
         }
     }
 
-    private void returnPendingFindAccessibilityNodeInfosInPrefetch(
-            List<AccessibilityNodeInfo> infos) {
-        for (Message pendingMessage : mPendingFindNodeByIdMessages) {
-            SomeArgs args = (SomeArgs) pendingMessage.obj;
-            final int accessibilityViewId = args.argi1;
-            final int virtualDescendantId = args.argi2;
-            final int interactionId = args.argi3;
-            final IAccessibilityInteractionConnectionCallback callback =
-                    (IAccessibilityInteractionConnectionCallback) args.arg1;
-            final long nodeId =
-                    AccessibilityNodeInfo.makeNodeId(accessibilityViewId, virtualDescendantId);
-            for (int i = 0; i < infos.size(); i++) {
-                AccessibilityNodeInfo info = infos.get(i);
-                if (info.getSourceNodeId() == nodeId) {
-                    returnFindNodeResult(
-                            AccessibilityNodeInfo.obtain(info), callback, interactionId);
-                    mHandler.removeMessages(
-                            PrivateHandler.MSG_FIND_ACCESSIBILITY_NODE_INFO_BY_ACCESSIBILITY_ID,
-                            pendingMessage.obj);
-                    args.recycle();
-                    break;
-                }
-            }
-        }
-        mPendingFindNodeByIdMessages.clear();
-    }
-
-    private void returnPrefetchResult(int interactionId, List<AccessibilityNodeInfo> infos,
-                                      IAccessibilityInteractionConnectionCallback callback) {
-        if (infos.size() > 0) {
-            try {
-                callback.setPrefetchAccessibilityNodeInfoResult(infos, interactionId);
-            } catch (RemoteException re) {
-                /* ignore - other side isn't too bothered if this doesn't arrive */
-            }
-        }
-    }
-
     private void updateInfoForViewportAndReturnFindNodeResult(AccessibilityNodeInfo info,
             IAccessibilityInteractionConnectionCallback callback, int interactionId,
             MagnificationSpec spec, Region interactiveRegion) {
-        updateInfoForViewPort(info, spec, interactiveRegion);
-        returnFindNodeResult(info, callback, interactionId);
+        try {
+            mViewRootImpl.mAttachInfo.mAccessibilityFetchFlags = 0;
+            associateLeashedParentIfNeeded(info);
+            applyScreenMatrixIfNeeded(info);
+            adjustBoundsInScreenIfNeeded(info);
+            // To avoid applyAppScaleAndMagnificationSpecIfNeeded changing the bounds of node,
+            // then impact the visibility result, we need to adjust visibility before apply scale.
+            adjustIsVisibleToUserIfNeeded(info, interactiveRegion);
+            applyAppScaleAndMagnificationSpecIfNeeded(info, spec);
+            callback.setFindAccessibilityNodeInfoResult(info, interactionId);
+        } catch (RemoteException re) {
+                /* ignore - the other side will time out */
+        }
     }
 
     private boolean handleClickableSpanActionUiThread(
@@ -1105,11 +1053,20 @@
 
         private final ArrayList<View> mTempViewList = new ArrayList<View>();
 
-        public void prefetchAccessibilityNodeInfos(View view, AccessibilityNodeInfo root,
-                int virtualViewId, int fetchFlags, List<AccessibilityNodeInfo> outInfos) {
-            if (root != null) {
-                AccessibilityNodeProvider provider = view.getAccessibilityNodeProvider();
-                if (provider == null) {
+        public void prefetchAccessibilityNodeInfos(View view, int virtualViewId, int fetchFlags,
+                List<AccessibilityNodeInfo> outInfos, Bundle arguments) {
+            AccessibilityNodeProvider provider = view.getAccessibilityNodeProvider();
+            // Determine if we'll be populating extra data
+            final String extraDataRequested = (arguments == null) ? null
+                    : arguments.getString(EXTRA_DATA_REQUESTED_KEY);
+            if (provider == null) {
+                AccessibilityNodeInfo root = view.createAccessibilityNodeInfo();
+                if (root != null) {
+                    if (extraDataRequested != null) {
+                        view.addExtraDataToAccessibilityNodeInfo(
+                                root, extraDataRequested, arguments);
+                    }
+                    outInfos.add(root);
                     if ((fetchFlags & AccessibilityNodeInfo.FLAG_PREFETCH_PREDECESSORS) != 0) {
                         prefetchPredecessorsOfRealNode(view, outInfos);
                     }
@@ -1119,7 +1076,16 @@
                     if ((fetchFlags & AccessibilityNodeInfo.FLAG_PREFETCH_DESCENDANTS) != 0) {
                         prefetchDescendantsOfRealNode(view, outInfos);
                     }
-                } else {
+                }
+            } else {
+                final AccessibilityNodeInfo root =
+                        provider.createAccessibilityNodeInfo(virtualViewId);
+                if (root != null) {
+                    if (extraDataRequested != null) {
+                        provider.addExtraDataToAccessibilityNodeInfo(
+                                virtualViewId, root, extraDataRequested, arguments);
+                    }
+                    outInfos.add(root);
                     if ((fetchFlags & AccessibilityNodeInfo.FLAG_PREFETCH_PREDECESSORS) != 0) {
                         prefetchPredecessorsOfVirtualNode(root, view, provider, outInfos);
                     }
@@ -1130,19 +1096,13 @@
                         prefetchDescendantsOfVirtualNode(root, provider, outInfos);
                     }
                 }
-                if (ENFORCE_NODE_TREE_CONSISTENT) {
-                    enforceNodeTreeConsistent(root, outInfos);
-                }
+            }
+            if (ENFORCE_NODE_TREE_CONSISTENT) {
+                enforceNodeTreeConsistent(outInfos);
             }
         }
 
-        private boolean shouldStopPrefetching(List prefetchededInfos) {
-            return mHandler.hasUserInteractiveMessagesWaiting()
-                    || prefetchededInfos.size() >= MAX_ACCESSIBILITY_NODE_INFO_BATCH_SIZE;
-        }
-
-        private void enforceNodeTreeConsistent(
-                AccessibilityNodeInfo root, List<AccessibilityNodeInfo> nodes) {
+        private void enforceNodeTreeConsistent(List<AccessibilityNodeInfo> nodes) {
             LongSparseArray<AccessibilityNodeInfo> nodeMap =
                     new LongSparseArray<AccessibilityNodeInfo>();
             final int nodeCount = nodes.size();
@@ -1153,6 +1113,7 @@
 
             // If the nodes are a tree it does not matter from
             // which node we start to search for the root.
+            AccessibilityNodeInfo root = nodeMap.valueAt(0);
             AccessibilityNodeInfo parent = root;
             while (parent != null) {
                 root = parent;
@@ -1219,11 +1180,9 @@
 
         private void prefetchPredecessorsOfRealNode(View view,
                 List<AccessibilityNodeInfo> outInfos) {
-            if (shouldStopPrefetching(outInfos)) {
-                return;
-            }
             ViewParent parent = view.getParentForAccessibility();
-            while (parent instanceof View && !shouldStopPrefetching(outInfos)) {
+            while (parent instanceof View
+                    && outInfos.size() < MAX_ACCESSIBILITY_NODE_INFO_BATCH_SIZE) {
                 View parentView = (View) parent;
                 AccessibilityNodeInfo info = parentView.createAccessibilityNodeInfo();
                 if (info != null) {
@@ -1235,9 +1194,6 @@
 
         private void prefetchSiblingsOfRealNode(View current,
                 List<AccessibilityNodeInfo> outInfos) {
-            if (shouldStopPrefetching(outInfos)) {
-                return;
-            }
             ViewParent parent = current.getParentForAccessibility();
             if (parent instanceof ViewGroup) {
                 ViewGroup parentGroup = (ViewGroup) parent;
@@ -1247,7 +1203,7 @@
                     parentGroup.addChildrenForAccessibility(children);
                     final int childCount = children.size();
                     for (int i = 0; i < childCount; i++) {
-                        if (shouldStopPrefetching(outInfos)) {
+                        if (outInfos.size() >= MAX_ACCESSIBILITY_NODE_INFO_BATCH_SIZE) {
                             return;
                         }
                         View child = children.get(i);
@@ -1275,7 +1231,7 @@
 
         private void prefetchDescendantsOfRealNode(View root,
                 List<AccessibilityNodeInfo> outInfos) {
-            if (shouldStopPrefetching(outInfos) || !(root instanceof ViewGroup)) {
+            if (!(root instanceof ViewGroup)) {
                 return;
             }
             HashMap<View, AccessibilityNodeInfo> addedChildren =
@@ -1286,7 +1242,7 @@
                 root.addChildrenForAccessibility(children);
                 final int childCount = children.size();
                 for (int i = 0; i < childCount; i++) {
-                    if (shouldStopPrefetching(outInfos)) {
+                    if (outInfos.size() >= MAX_ACCESSIBILITY_NODE_INFO_BATCH_SIZE) {
                         return;
                     }
                     View child = children.get(i);
@@ -1311,7 +1267,7 @@
             } finally {
                 children.clear();
             }
-            if (!shouldStopPrefetching(outInfos)) {
+            if (outInfos.size() < MAX_ACCESSIBILITY_NODE_INFO_BATCH_SIZE) {
                 for (Map.Entry<View, AccessibilityNodeInfo> entry : addedChildren.entrySet()) {
                     View addedChild = entry.getKey();
                     AccessibilityNodeInfo virtualRoot = entry.getValue();
@@ -1333,7 +1289,7 @@
             long parentNodeId = root.getParentNodeId();
             int accessibilityViewId = AccessibilityNodeInfo.getAccessibilityViewId(parentNodeId);
             while (accessibilityViewId != AccessibilityNodeInfo.UNDEFINED_ITEM_ID) {
-                if (shouldStopPrefetching(outInfos)) {
+                if (outInfos.size() >= MAX_ACCESSIBILITY_NODE_INFO_BATCH_SIZE) {
                     return;
                 }
                 final int virtualDescendantId =
@@ -1378,7 +1334,7 @@
                 if (parent != null) {
                     final int childCount = parent.getChildCount();
                     for (int i = 0; i < childCount; i++) {
-                        if (shouldStopPrefetching(outInfos)) {
+                        if (outInfos.size() >= MAX_ACCESSIBILITY_NODE_INFO_BATCH_SIZE) {
                             return;
                         }
                         final long childNodeId = parent.getChildId(i);
@@ -1403,7 +1359,7 @@
             final int initialOutInfosSize = outInfos.size();
             final int childCount = root.getChildCount();
             for (int i = 0; i < childCount; i++) {
-                if (shouldStopPrefetching(outInfos)) {
+                if (outInfos.size() >= MAX_ACCESSIBILITY_NODE_INFO_BATCH_SIZE) {
                     return;
                 }
                 final long childNodeId = root.getChildId(i);
@@ -1413,7 +1369,7 @@
                     outInfos.add(child);
                 }
             }
-            if (!shouldStopPrefetching(outInfos)) {
+            if (outInfos.size() < MAX_ACCESSIBILITY_NODE_INFO_BATCH_SIZE) {
                 final int addedChildCount = outInfos.size() - initialOutInfosSize;
                 for (int i = 0; i < addedChildCount; i++) {
                     AccessibilityNodeInfo child = outInfos.get(initialOutInfosSize + i);
@@ -1522,10 +1478,6 @@
         boolean hasAccessibilityCallback(Message message) {
             return message.what < FIRST_NO_ACCESSIBILITY_CALLBACK_MSG ? true : false;
         }
-
-        boolean hasUserInteractiveMessagesWaiting() {
-            return hasMessagesOrCallbacks();
-        }
     }
 
     private final class AddNodeInfosForViewId implements Predicate<View> {
diff --git a/core/java/android/view/IWindow.aidl b/core/java/android/view/IWindow.aidl
index e685b30..fb012eb 100644
--- a/core/java/android/view/IWindow.aidl
+++ b/core/java/android/view/IWindow.aidl
@@ -130,11 +130,6 @@
     void requestAppKeyboardShortcuts(IResultReceiver receiver, int deviceId);
 
     /**
-     * Tell the window that it is either gaining or losing pointer capture.
-     */
-    void dispatchPointerCaptureChanged(boolean hasCapture);
-
-    /**
      * Called when Scroll Capture support is requested for a window.
      *
      * @param callbacks to receive responses
diff --git a/core/java/android/view/InputDevice.java b/core/java/android/view/InputDevice.java
index df96dc3..f4b90e1 100644
--- a/core/java/android/view/InputDevice.java
+++ b/core/java/android/view/InputDevice.java
@@ -22,6 +22,7 @@
 import android.annotation.TestApi;
 import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
+import android.hardware.SensorManager;
 import android.hardware.input.InputDeviceIdentifier;
 import android.hardware.input.InputManager;
 import android.os.Build;
@@ -71,13 +72,18 @@
     private final boolean mHasVibrator;
     private final boolean mHasMicrophone;
     private final boolean mHasButtonUnderPad;
+    private final boolean mHasSensor;
     private final ArrayList<MotionRange> mMotionRanges = new ArrayList<MotionRange>();
 
+    @GuardedBy("mMotionRanges")
     private Vibrator mVibrator; // guarded by mMotionRanges during initialization
 
     @GuardedBy("mMotionRanges")
     private VibratorManager mVibratorManager;
 
+    @GuardedBy("mMotionRanges")
+    private SensorManager mSensorManager;
+
     /**
      * A mask for input source classes.
      *
@@ -442,7 +448,7 @@
     public InputDevice(int id, int generation, int controllerNumber, String name, int vendorId,
             int productId, String descriptor, boolean isExternal, int sources, int keyboardType,
             KeyCharacterMap keyCharacterMap, boolean hasVibrator, boolean hasMicrophone,
-            boolean hasButtonUnderPad) {
+            boolean hasButtonUnderPad, boolean hasSensor) {
         mId = id;
         mGeneration = generation;
         mControllerNumber = controllerNumber;
@@ -457,10 +463,12 @@
         mHasVibrator = hasVibrator;
         mHasMicrophone = hasMicrophone;
         mHasButtonUnderPad = hasButtonUnderPad;
+        mHasSensor = hasSensor;
         mIdentifier = new InputDeviceIdentifier(descriptor, vendorId, productId);
     }
 
     private InputDevice(Parcel in) {
+        mKeyCharacterMap = KeyCharacterMap.CREATOR.createFromParcel(in);
         mId = in.readInt();
         mGeneration = in.readInt();
         mControllerNumber = in.readInt();
@@ -471,10 +479,10 @@
         mIsExternal = in.readInt() != 0;
         mSources = in.readInt();
         mKeyboardType = in.readInt();
-        mKeyCharacterMap = KeyCharacterMap.CREATOR.createFromParcel(in);
         mHasVibrator = in.readInt() != 0;
         mHasMicrophone = in.readInt() != 0;
         mHasButtonUnderPad = in.readInt() != 0;
+        mHasSensor = in.readInt() != 0;
         mIdentifier = new InputDeviceIdentifier(mDescriptor, mVendorId, mProductId);
 
         int numRanges = in.readInt();
@@ -822,6 +830,26 @@
     }
 
     /**
+     * Gets the sensor manager service associated with the input device.
+     * Even if the device does not have a sensor, the result is never null.
+     * Use {@link SensorManager#getSensorList} to get a full list of all supported sensors.
+     *
+     * Note that the sensors associated with the device may be different from
+     * the system sensors, as typically they are builtin sensors physically attached to
+     * input devices.
+     *
+     * @return The sensor manager service associated with the device, never null.
+     */
+    public @NonNull SensorManager getSensorManager() {
+        synchronized (mMotionRanges) {
+            if (mSensorManager == null) {
+                mSensorManager = InputManager.getInstance().getInputDeviceSensorManager(mId);
+            }
+        }
+        return mSensorManager;
+    }
+
+    /**
      * Returns true if input device is enabled.
      * @return Whether the input device is enabled.
      */
@@ -869,6 +897,15 @@
     }
 
     /**
+     * Reports whether the device has a sensor.
+     * @return Whether the device has a sensor.
+     * @hide
+     */
+    public boolean hasSensor() {
+        return mHasSensor;
+    }
+
+    /**
      * Sets the current pointer type.
      * @param pointerType the type of the pointer icon.
      * @hide
@@ -999,6 +1036,7 @@
 
     @Override
     public void writeToParcel(Parcel out, int flags) {
+        mKeyCharacterMap.writeToParcel(out, flags);
         out.writeInt(mId);
         out.writeInt(mGeneration);
         out.writeInt(mControllerNumber);
@@ -1009,10 +1047,10 @@
         out.writeInt(mIsExternal ? 1 : 0);
         out.writeInt(mSources);
         out.writeInt(mKeyboardType);
-        mKeyCharacterMap.writeToParcel(out, flags);
         out.writeInt(mHasVibrator ? 1 : 0);
         out.writeInt(mHasMicrophone ? 1 : 0);
         out.writeInt(mHasButtonUnderPad ? 1 : 0);
+        out.writeInt(mHasSensor ? 1 : 0);
 
         final int numRanges = mMotionRanges.size();
         out.writeInt(numRanges);
@@ -1057,6 +1095,8 @@
 
         description.append("  Has Vibrator: ").append(mHasVibrator).append("\n");
 
+        description.append("  Has Sensor: ").append(mHasSensor).append("\n");
+
         description.append("  Has mic: ").append(mHasMicrophone).append("\n");
 
         description.append("  Sources: 0x").append(Integer.toHexString(mSources)).append(" (");
diff --git a/core/java/android/view/ScrollCaptureTargetResolver.java b/core/java/android/view/ScrollCaptureTargetResolver.java
index 5106534..e4316bb 100644
--- a/core/java/android/view/ScrollCaptureTargetResolver.java
+++ b/core/java/android/view/ScrollCaptureTargetResolver.java
@@ -182,9 +182,8 @@
         }
         mResult = chooseTarget(mResult, target);
         boolean finish = mPendingBoundsRequests == 0
-                || SystemClock.elapsedRealtime() >= mDeadlineMillis;
+                || SystemClock.uptimeMillis() >= mDeadlineMillis;
         if (finish) {
-            System.err.println("We think we're done, or timed out");
             mPendingBoundsRequests = 0;
             mWhenComplete.accept(mResult);
             synchronized (mLock) {
@@ -233,7 +232,7 @@
         for (ScrollCaptureTarget target : mTargets) {
             queryTarget(target);
         }
-        mDeadlineMillis = SystemClock.elapsedRealtime() + mTimeLimitMillis;
+        mDeadlineMillis = SystemClock.uptimeMillis() + mTimeLimitMillis;
         mHandler.postAtTime(mTimeoutRunnable, mDeadlineMillis);
     }
 
@@ -275,7 +274,7 @@
         mHandler.removeCallbacks(mTimeoutRunnable);
 
         boolean doneOrTimedOut = mPendingBoundsRequests == 0
-                || SystemClock.elapsedRealtime() >= mDeadlineMillis;
+                || SystemClock.uptimeMillis() >= mDeadlineMillis;
 
         final View containingView = target.getContainingView();
         if (!nullOrEmpty(scrollBounds) && containingView.isAggregatedVisible()) {
diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java
index f05e671..b5185ae 100644
--- a/core/java/android/view/SurfaceView.java
+++ b/core/java/android/view/SurfaceView.java
@@ -240,7 +240,7 @@
     private static boolean useBlastAdapter(Context context) {
         ContentResolver contentResolver = context.getContentResolver();
         return Settings.Global.getInt(contentResolver,
-                Settings.Global.DEVELOPMENT_USE_BLAST_ADAPTER_SV, 0 /* default */) == 1;
+                Settings.Global.DEVELOPMENT_USE_BLAST_ADAPTER_SV, 1 /* default */) == 1;
     }
 
     private final boolean mUseBlastAdapter;
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index d24380b..52ce5e7 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -8665,7 +8665,7 @@
                 MSG_REQUEST_KEYBOARD_SHORTCUTS, deviceId, 0, receiver).sendToTarget();
     }
 
-    public void dispatchPointerCaptureChanged(boolean on) {
+    private void dispatchPointerCaptureChanged(boolean on) {
         final int what = MSG_POINTER_CAPTURE_CHANGED;
         mHandler.removeMessages(what);
         Message msg = mHandler.obtainMessage(what);
@@ -9438,14 +9438,6 @@
         }
 
         @Override
-        public void dispatchPointerCaptureChanged(boolean hasCapture) {
-            final ViewRootImpl viewAncestor = mViewAncestor.get();
-            if (viewAncestor != null) {
-                viewAncestor.dispatchPointerCaptureChanged(hasCapture);
-            }
-        }
-
-        @Override
         public void requestScrollCapture(IScrollCaptureCallbacks callbacks) {
             final ViewRootImpl viewAncestor = mViewAncestor.get();
             if (viewAncestor != null) {
diff --git a/core/java/android/view/accessibility/AccessibilityInteractionClient.java b/core/java/android/view/accessibility/AccessibilityInteractionClient.java
index aff0b35..f63749b 100644
--- a/core/java/android/view/accessibility/AccessibilityInteractionClient.java
+++ b/core/java/android/view/accessibility/AccessibilityInteractionClient.java
@@ -23,9 +23,7 @@
 import android.os.Binder;
 import android.os.Build;
 import android.os.Bundle;
-import android.os.Handler;
 import android.os.IBinder;
-import android.os.Looper;
 import android.os.Message;
 import android.os.Process;
 import android.os.RemoteException;
@@ -125,12 +123,6 @@
 
     private Message mSameThreadMessage;
 
-    private int mInteractionIdWaitingForPrefetchResult;
-    private int mConnectionIdWaitingForPrefetchResult;
-    private String[] mPackageNamesForNextPrefetchResult;
-    private final Handler mMainHandler;
-    private Runnable mPrefetchResultRunnable;
-
     /**
      * @return The client for the current thread.
      */
@@ -205,7 +197,6 @@
 
     private AccessibilityInteractionClient() {
         /* reducing constructor visibility */
-        mMainHandler = new Handler(Looper.getMainLooper());
     }
 
     /**
@@ -460,16 +451,16 @@
                     Binder.restoreCallingIdentity(identityToken);
                 }
                 if (packageNames != null) {
-                    AccessibilityNodeInfo info =
-                            getFindAccessibilityNodeInfoResultAndClear(interactionId);
-                    if ((prefetchFlags & AccessibilityNodeInfo.FLAG_PREFETCH_MASK) != 0
-                            && info != null) {
-                        setInteractionWaitingForPrefetchResult(interactionId, connectionId,
-                                packageNames);
-                    }
-                    finalizeAndCacheAccessibilityNodeInfo(info, connectionId,
+                    List<AccessibilityNodeInfo> infos = getFindAccessibilityNodeInfosResultAndClear(
+                            interactionId);
+                    finalizeAndCacheAccessibilityNodeInfos(infos, connectionId,
                             bypassCache, packageNames);
-                    return info;
+                    if (infos != null && !infos.isEmpty()) {
+                        for (int i = 1; i < infos.size(); i++) {
+                            infos.get(i).recycle();
+                        }
+                        return infos.get(0);
+                    }
                 }
             } else {
                 if (DEBUG) {
@@ -483,15 +474,6 @@
         return null;
     }
 
-    private void setInteractionWaitingForPrefetchResult(int interactionId, int connectionId,
-            String[] packageNames) {
-        synchronized (mInstanceLock) {
-            mInteractionIdWaitingForPrefetchResult = interactionId;
-            mConnectionIdWaitingForPrefetchResult = connectionId;
-            mPackageNamesForNextPrefetchResult = packageNames;
-        }
-    }
-
     private static String idToString(int accessibilityWindowId, long accessibilityNodeId) {
         return accessibilityWindowId + "/"
                 + AccessibilityNodeInfo.idToString(accessibilityNodeId);
@@ -847,26 +829,6 @@
     }
 
     /**
-     * {@inheritDoc}
-     */
-    @Override
-    public void setPrefetchAccessibilityNodeInfoResult(List<AccessibilityNodeInfo> infos,
-                                                       int interactionId) {
-        synchronized (mInstanceLock) {
-            if (mPrefetchResultRunnable != null) {
-                mMainHandler.removeCallbacks(mPrefetchResultRunnable);
-                mPrefetchResultRunnable = null;
-            }
-            if (!infos.isEmpty() && mInteractionIdWaitingForPrefetchResult == interactionId) {
-                mPrefetchResultRunnable = () -> finalizeAndCacheAccessibilityNodeInfos(
-                        infos, mConnectionIdWaitingForPrefetchResult, false,
-                        mPackageNamesForNextPrefetchResult);
-                mMainHandler.post(mPrefetchResultRunnable);
-            }
-        }
-    }
-
-    /**
      * Gets the result of a request to perform an accessibility action.
      *
      * @param interactionId The interaction id to match the result with the request.
diff --git a/core/java/android/view/accessibility/IAccessibilityInteractionConnectionCallback.aidl b/core/java/android/view/accessibility/IAccessibilityInteractionConnectionCallback.aidl
index 231e75a..049bb31 100644
--- a/core/java/android/view/accessibility/IAccessibilityInteractionConnectionCallback.aidl
+++ b/core/java/android/view/accessibility/IAccessibilityInteractionConnectionCallback.aidl
@@ -47,15 +47,6 @@
         int interactionId);
 
     /**
-     * Sets the result of a prefetch request that returns {@link AccessibilityNodeInfo}s.
-     *
-     * @param root The {@link AccessibilityNodeInfo} for which the prefetching is based off of.
-     * @param infos The result {@link AccessibilityNodeInfo}s.
-     */
-    void setPrefetchAccessibilityNodeInfoResult(
-        in List<AccessibilityNodeInfo> infos, int interactionId);
-
-    /**
      * Sets the result of a request to perform an accessibility action.
      *
      * @param Whether the action was performed.
diff --git a/core/java/android/view/inputmethod/EditorInfo.java b/core/java/android/view/inputmethod/EditorInfo.java
index 7dbf693..1cf25a7 100644
--- a/core/java/android/view/inputmethod/EditorInfo.java
+++ b/core/java/android/view/inputmethod/EditorInfo.java
@@ -28,6 +28,7 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.RequiresPermission;
+import android.content.res.Configuration;
 import android.os.Build.VERSION_CODES;
 import android.os.Bundle;
 import android.os.LocaleList;
@@ -293,6 +294,13 @@
     public static final int IME_FLAG_FORCE_ASCII = 0x80000000;
 
     /**
+     * Flag of {@link #internalImeOptions}: flag is set when app window containing this
+     * {@link EditorInfo} is using {@link Configuration#ORIENTATION_PORTRAIT} mode.
+     * @hide
+     */
+    public static final int IME_FLAG_APP_WINDOW_PORTRAIT = 0x80000000;
+
+    /**
      * Generic unspecified type for {@link #imeOptions}.
      */
     public static final int IME_NULL = 0x00000000;
@@ -312,6 +320,7 @@
      *                               1 1 IME_ACTION_NEXT
      *                               11  IME_ACTION_DONE
      *                               111 IME_ACTION_PREVIOUS
+     *          1                        IME_FLAG_APP_WINDOW_PORTRAIT
      *         1                         IME_FLAG_NO_PERSONALIZED_LEARNING
      *        1                          IME_FLAG_NO_FULLSCREEN
      *       1                           IME_FLAG_NAVIGATE_PREVIOUS
@@ -343,6 +352,20 @@
     public String privateImeOptions = null;
 
     /**
+     * Masks for {@link internalImeOptions}
+     *
+     * <pre>
+     *  1                                IME_FLAG_APP_WINDOW_PORTRAIT
+     * |-------|-------|-------|-------|</pre>
+     */
+
+    /**
+     * Same as {@link android.R.attr#imeOptions} but for framework's internal-use only.
+     * @hide
+     */
+    public int internalImeOptions = IME_NULL;
+
+    /**
      * In some cases an IME may be able to display an arbitrary label for
      * a command the user can perform, which you can specify here. This is
      * typically used as the label for the action to use in-line as a replacement
diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java
index 6526b8c..0a4b784 100644
--- a/core/java/android/view/inputmethod/InputMethodManager.java
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -1361,7 +1361,9 @@
             // We intentionally do not use UserHandle.getCallingUserId() here because for system
             // services InputMethodManagerInternal.getInputMethodListAsUser() should be used
             // instead.
-            return mService.getInputMethodList(UserHandle.myUserId());
+            final Completable.InputMethodInfoList value = Completable.createInputMethodInfoList();
+            mService.getInputMethodList(UserHandle.myUserId(), ResultCallbacks.of(value));
+            return Completable.getResult(value);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -1377,7 +1379,9 @@
     @RequiresPermission(INTERACT_ACROSS_USERS_FULL)
     public List<InputMethodInfo> getInputMethodListAsUser(@UserIdInt int userId) {
         try {
-            return mService.getInputMethodList(userId);
+            final Completable.InputMethodInfoList value = Completable.createInputMethodInfoList();
+            mService.getInputMethodList(userId,  ResultCallbacks.of(value));
+            return Completable.getResult(value);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -1395,7 +1399,9 @@
             // We intentionally do not use UserHandle.getCallingUserId() here because for system
             // services InputMethodManagerInternal.getEnabledInputMethodListAsUser() should be used
             // instead.
-            return mService.getEnabledInputMethodList(UserHandle.myUserId());
+            final Completable.InputMethodInfoList value = Completable.createInputMethodInfoList();
+            mService.getEnabledInputMethodList(UserHandle.myUserId(), ResultCallbacks.of(value));
+            return Completable.getResult(value);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -1411,7 +1417,9 @@
     @RequiresPermission(INTERACT_ACROSS_USERS_FULL)
     public List<InputMethodInfo> getEnabledInputMethodListAsUser(@UserIdInt int userId) {
         try {
-            return mService.getEnabledInputMethodList(userId);
+            final Completable.InputMethodInfoList value = Completable.createInputMethodInfoList();
+            mService.getEnabledInputMethodList(userId, ResultCallbacks.of(value));
+            return Completable.getResult(value);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -1430,8 +1438,13 @@
     public List<InputMethodSubtype> getEnabledInputMethodSubtypeList(InputMethodInfo imi,
             boolean allowsImplicitlySelectedSubtypes) {
         try {
-            return mService.getEnabledInputMethodSubtypeList(
-                    imi == null ? null : imi.getId(), allowsImplicitlySelectedSubtypes);
+            final Completable.InputMethodSubtypeList value =
+                    Completable.createInputMethodSubtypeList();
+            mService.getEnabledInputMethodSubtypeList(
+                    imi == null ? null : imi.getId(),
+                    allowsImplicitlySelectedSubtypes,
+                    ResultCallbacks.of(value));
+            return Completable.getResult(value);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -2970,7 +2983,9 @@
      */
     public InputMethodSubtype getCurrentInputMethodSubtype() {
         try {
-            return mService.getCurrentInputMethodSubtype();
+            final Completable.InputMethodSubtype value = Completable.createInputMethodSubtype();
+            mService.getCurrentInputMethodSubtype(ResultCallbacks.of(value));
+            return Completable.getResult(value);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -3019,7 +3034,11 @@
         }
         final List<InputMethodSubtype> enabledSubtypes;
         try {
-            enabledSubtypes = mService.getEnabledInputMethodSubtypeList(imeId, true);
+            final Completable.InputMethodSubtypeList value =
+                    Completable.createInputMethodSubtypeList();
+            mService.getEnabledInputMethodSubtypeList(
+                    imeId, true, ResultCallbacks.of(value));
+            enabledSubtypes = Completable.getResult(value);
         } catch (RemoteException e) {
             return false;
         }
@@ -3087,7 +3106,9 @@
     @UnsupportedAppUsage
     public int getInputMethodWindowVisibleHeight() {
         try {
-            return mService.getInputMethodWindowVisibleHeight();
+            final Completable.Int value = Completable.createInt();
+            mService.getInputMethodWindowVisibleHeight(ResultCallbacks.of(value));
+            return Completable.getIntResult(value);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -3214,7 +3235,9 @@
 
     public InputMethodSubtype getLastInputMethodSubtype() {
         try {
-            return mService.getLastInputMethodSubtype();
+            final Completable.InputMethodSubtype value = Completable.createInputMethodSubtype();
+            mService.getLastInputMethodSubtype(ResultCallbacks.of(value));
+            return Completable.getResult(value);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
diff --git a/core/java/android/view/textservice/SuggestionsInfo.java b/core/java/android/view/textservice/SuggestionsInfo.java
index ca529f6..1301c49 100644
--- a/core/java/android/view/textservice/SuggestionsInfo.java
+++ b/core/java/android/view/textservice/SuggestionsInfo.java
@@ -53,6 +53,16 @@
      */
     public static final int RESULT_ATTR_LOOKS_LIKE_GRAMMAR_ERROR = 0x0008;
 
+    /**
+     * Flag of the attributes of the suggestions that can be obtained by
+     * {@link #getSuggestionsAttributes}: this tells that the text service has an alternative way to
+     * show UI for the list of correction suggestions to the user. When this flag is set, the
+     * receiver of the result suggestions should mark the erroneous part of the text with a text
+     * signifier (for example, underline), but should not show any UI for the list of correction
+     * suggestions to the user (for example, in a popup window).
+     */
+    public static final int RESULT_ATTR_DONT_SHOW_UI_FOR_SUGGESTIONS = 0x0010;
+
     private final int mSuggestionsAttributes;
     private final String[] mSuggestions;
     private final boolean mSuggestionsAvailable;
diff --git a/core/java/android/widget/SpellChecker.java b/core/java/android/widget/SpellChecker.java
index 0788635..b06fa1a 100644
--- a/core/java/android/widget/SpellChecker.java
+++ b/core/java/android/widget/SpellChecker.java
@@ -477,6 +477,8 @@
         mTextView.postDelayed(mSpellRunnable, SPELL_PAUSE_DURATION);
     }
 
+    // When calling this method, RESULT_ATTR_LOOKS_LIKE_TYPO or RESULT_ATTR_LOOKS_LIKE_GRAMMAR_ERROR
+    // (or both) should be set in suggestionsInfo.
     private void createMisspelledSuggestionSpan(Editable editable, SuggestionsInfo suggestionsInfo,
             SpellCheckSpan spellCheckSpan, int offset, int length) {
         final int spellCheckSpanStart = editable.getSpanStart(spellCheckSpan);
@@ -506,7 +508,10 @@
         }
 
         final int suggestionsAttrs = suggestionsInfo.getSuggestionsAttributes();
-        int flags = SuggestionSpan.FLAG_EASY_CORRECT;
+        int flags = 0;
+        if ((suggestionsAttrs & SuggestionsInfo.RESULT_ATTR_DONT_SHOW_UI_FOR_SUGGESTIONS) == 0) {
+            flags |= SuggestionSpan.FLAG_EASY_CORRECT;
+        }
         if ((suggestionsAttrs & SuggestionsInfo.RESULT_ATTR_LOOKS_LIKE_TYPO) != 0) {
             flags |= SuggestionSpan.FLAG_MISSPELLED;
         }
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 12c91fa..977a0e8 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -17,6 +17,7 @@
 package android.widget;
 
 import static android.Manifest.permission.INTERACT_ACROSS_USERS_FULL;
+import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
 import static android.view.ContentInfo.FLAG_CONVERT_TO_PLAIN_TEXT;
 import static android.view.ContentInfo.SOURCE_AUTOFILL;
 import static android.view.ContentInfo.SOURCE_CLIPBOARD;
@@ -8738,6 +8739,9 @@
                     outAttrs.imeOptions |= EditorInfo.IME_FLAG_NO_ENTER_ACTION;
                 }
             }
+            if (getResources().getConfiguration().orientation == ORIENTATION_PORTRAIT) {
+                outAttrs.internalImeOptions |= EditorInfo.IME_FLAG_APP_WINDOW_PORTRAIT;
+            }
             if (isMultilineInputType(outAttrs.inputType)) {
                 // Multi-line text editors should always show an enter key.
                 outAttrs.imeOptions |= EditorInfo.IME_FLAG_NO_ENTER_ACTION;
diff --git a/core/java/android/window/DisplayAreaOrganizer.java b/core/java/android/window/DisplayAreaOrganizer.java
index 8a1d4a0..1254647 100644
--- a/core/java/android/window/DisplayAreaOrganizer.java
+++ b/core/java/android/window/DisplayAreaOrganizer.java
@@ -164,15 +164,19 @@
     }
 
     /**
-     * Creates a persistent task display area. It will be added to be the top most task display area
-     * in the root.
+     * Creates a persistent {@link com.android.server.wm.TaskDisplayArea}.
      *
      * The new created TDA is organized by the organizer, and will be deleted on calling
      * {@link #deleteTaskDisplayArea(WindowContainerToken)} or {@link #unregisterOrganizer()}.
      *
-     * @param displayId the display to create the new task display area in.
-     * @param rootFeatureId the root display area to create the new task display area in. Caller can
-     *                      use {@link #FEATURE_ROOT} as the root of the logical display.
+     * @param displayId the display to create the new TDA in.
+     * @param parentFeatureId the parent to create the new TDA in. If it is a
+     *                        {@link com.android.server.wm.RootDisplayArea}, the new TDA will be
+     *                        placed as the topmost TDA. If it is another TDA, the new TDA will be
+     *                        placed as the topmost child.
+     *                        Caller can use {@link #FEATURE_ROOT} as the root of the logical
+     *                        display, or {@link #FEATURE_DEFAULT_TASK_CONTAINER} as the default
+     *                        TDA.
      * @param name the name for the new task display area.
      * @return the new created task display area.
      * @throws IllegalArgumentException if failed to create a new task display area.
@@ -181,11 +185,11 @@
     @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS)
     @CallSuper
     @NonNull
-    public DisplayAreaAppearedInfo createTaskDisplayArea(int displayId, int rootFeatureId,
+    public DisplayAreaAppearedInfo createTaskDisplayArea(int displayId, int parentFeatureId,
             @NonNull String name) {
         try {
             return getController().createTaskDisplayArea(
-                    mInterface, displayId, rootFeatureId, name);
+                    mInterface, displayId, parentFeatureId, name);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
diff --git a/core/java/android/window/IDisplayAreaOrganizerController.aidl b/core/java/android/window/IDisplayAreaOrganizerController.aidl
index 26fa434..6c097bb 100644
--- a/core/java/android/window/IDisplayAreaOrganizerController.aidl
+++ b/core/java/android/window/IDisplayAreaOrganizerController.aidl
@@ -40,21 +40,25 @@
     void unregisterOrganizer(in IDisplayAreaOrganizer organizer);
 
     /**
-     * Creates a persistent task display area. It will be added to be the top most task display area
-     * in the root.
+     * Creates a persistent {@link com.android.server.wm.TaskDisplayArea}.
      *
      * The new created TDA is organized by the organizer, and will be deleted on calling
      * {@link #deleteTaskDisplayArea(WindowContainerToken)} or {@link #unregisterOrganizer()}.
      *
-     * @param displayId the display to create the new task display area in.
-     * @param rootFeatureId the root display area to create the new task display area in. Caller can
-     *                      use {@link #FEATURE_ROOT} as the root of the logical display.
+     * @param displayId the display to create the new TDA in.
+     * @param parentFeatureId the parent to create the new TDA in. If it is a
+     *                        {@link com.android.server.wm.RootDisplayArea}, the new TDA will be
+     *                        placed as the topmost TDA. If it is another TDA, the new TDA will be
+     *                        placed as the topmost child.
+     *                        Caller can use {@link #FEATURE_ROOT} as the root of the logical
+     *                        display, or {@link #FEATURE_DEFAULT_TASK_CONTAINER} as the default
+     *                        TDA.
      * @param name the name for the new task display area.
      * @return the new created task display area.
      * @throws IllegalArgumentException if failed to create a new task display area.
      */
     DisplayAreaAppearedInfo createTaskDisplayArea(in IDisplayAreaOrganizer organizer, int displayId,
-        int rootFeatureId, in String name);
+        int parentFeatureId, in String name);
 
     /**
      * Deletes a persistent task display area. It can only be one that created by an organizer.
diff --git a/core/java/android/window/ITaskOrganizer.aidl b/core/java/android/window/ITaskOrganizer.aidl
index b503184..88b2257 100644
--- a/core/java/android/window/ITaskOrganizer.aidl
+++ b/core/java/android/window/ITaskOrganizer.aidl
@@ -18,6 +18,7 @@
 
 import android.view.SurfaceControl;
 import android.app.ActivityManager;
+import android.window.StartingWindowInfo;
 import android.window.WindowContainerToken;
 
 /**
@@ -30,15 +31,15 @@
      * application is starting. The client is responsible to add/remove the starting window if it
      * has create a starting window for the Task.
      *
-     * @param taskInfo The information about the Task that's available
+     * @param info The information about the Task that's available
      * @param appToken Token of the application being started.
      */
-    void addStartingWindow(in ActivityManager.RunningTaskInfo taskInfo, IBinder appToken);
+    void addStartingWindow(in StartingWindowInfo info, IBinder appToken);
 
     /**
      * Called when the Task want to remove the starting window.
      */
-    void removeStartingWindow(in ActivityManager.RunningTaskInfo taskInfo);
+    void removeStartingWindow(int taskId);
 
     /**
      * A callback when the Task is available for the registered organizer. The client is responsible
diff --git a/core/java/android/window/StartingWindowInfo.aidl b/core/java/android/window/StartingWindowInfo.aidl
new file mode 100644
index 0000000..69b18f0
--- /dev/null
+++ b/core/java/android/window/StartingWindowInfo.aidl
@@ -0,0 +1,20 @@
+/**
+ * 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 android.window;
+
+/** @hide */
+parcelable StartingWindowInfo;
\ No newline at end of file
diff --git a/core/java/android/window/StartingWindowInfo.java b/core/java/android/window/StartingWindowInfo.java
new file mode 100644
index 0000000..2282cc5
--- /dev/null
+++ b/core/java/android/window/StartingWindowInfo.java
@@ -0,0 +1,150 @@
+/*
+ * 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 android.window;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.TestApi;
+import android.app.ActivityManager;
+import android.app.TaskInfo;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.view.InsetsState;
+import android.view.WindowManager;
+
+/**
+ * Information you can retrieve about a starting window of a particular task that is currently
+ * start in the system.
+ * @hide
+ */
+@TestApi
+public final class StartingWindowInfo implements Parcelable {
+    /**
+     * The {@link TaskInfo} from this task.
+     *  @hide
+     */
+    @NonNull
+    public ActivityManager.RunningTaskInfo taskInfo;
+
+    /**
+     * InsetsState of TopFullscreenOpaqueWindow
+     * @hide
+     */
+    @Nullable
+    public InsetsState topOpaqueWindowInsetsState;
+
+    /**
+     * LayoutParams of TopFullscreenOpaqueWindow
+     * @hide
+     */
+    @Nullable
+    public WindowManager.LayoutParams topOpaqueWindowLayoutParams;
+
+    /**
+     * LayoutParams of MainWindow
+     * @hide
+     */
+    @Nullable
+    public WindowManager.LayoutParams mainWindowLayoutParams;
+
+    /**
+     * @hide
+     */
+    @IntDef(flag = true, prefix = "TYPE_PARAMETER_", value = {
+            TYPE_PARAMETER_NEW_TASK,
+            TYPE_PARAMETER_TASK_SWITCH,
+            TYPE_PARAMETER_PROCESS_RUNNING,
+            TYPE_PARAMETER_ALLOW_TASK_SNAPSHOT,
+            TYPE_PARAMETER_ACTIVITY_CREATED
+    })
+    public @interface StartingTypeParams {}
+
+    /**
+     * The parameters of the starting window...
+     * @hide
+     */
+    public static final int TYPE_PARAMETER_NEW_TASK = 0x00000001;
+    /** @hide */
+    public static final int TYPE_PARAMETER_TASK_SWITCH = 0x00000002;
+    /** @hide */
+    public static final int TYPE_PARAMETER_PROCESS_RUNNING = 0x00000004;
+    /** @hide */
+    public static final int TYPE_PARAMETER_ALLOW_TASK_SNAPSHOT = 0x00000008;
+    /** @hide */
+    public static final int TYPE_PARAMETER_ACTIVITY_CREATED = 0x00000010;
+
+    /**
+     * The parameters which effect the starting window type.
+     * @see android.window.StartingWindowInfo.StartingTypeParams
+     * @hide
+     */
+    public int startingWindowTypeParameter;
+
+    public StartingWindowInfo() {
+
+    }
+
+    private StartingWindowInfo(@NonNull Parcel source) {
+        readFromParcel(source);
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
+        dest.writeTypedObject(taskInfo, flags);
+        dest.writeInt(startingWindowTypeParameter);
+        dest.writeTypedObject(topOpaqueWindowInsetsState, flags);
+        dest.writeTypedObject(topOpaqueWindowLayoutParams, flags);
+        dest.writeTypedObject(mainWindowLayoutParams, flags);
+    }
+
+    void readFromParcel(@NonNull Parcel source) {
+        taskInfo = source.readTypedObject(ActivityManager.RunningTaskInfo.CREATOR);
+        startingWindowTypeParameter = source.readInt();
+        topOpaqueWindowInsetsState = source.readTypedObject(InsetsState.CREATOR);
+        topOpaqueWindowLayoutParams = source.readTypedObject(
+                WindowManager.LayoutParams.CREATOR);
+        mainWindowLayoutParams = source.readTypedObject(WindowManager.LayoutParams.CREATOR);
+    }
+
+    @Override
+    public String toString() {
+        return "StartingWindowInfo{taskId=" + taskInfo.taskId
+                + " displayId=" + taskInfo.displayId
+                + " topActivityType=" + taskInfo.topActivityType
+                + " preferredStartingWindowType="
+                + Integer.toHexString(startingWindowTypeParameter)
+                + " insetsState=" + topOpaqueWindowInsetsState
+                + " topWindowLayoutParams=" + topOpaqueWindowLayoutParams
+                + " mainWindowLayoutParams=" + mainWindowLayoutParams;
+    }
+
+    public static final @android.annotation.NonNull Creator<StartingWindowInfo> CREATOR =
+            new Creator<StartingWindowInfo>() {
+                public StartingWindowInfo createFromParcel(@NonNull Parcel source) {
+                    return new StartingWindowInfo(source);
+                }
+                public StartingWindowInfo[] newArray(int size) {
+                    return new StartingWindowInfo[size];
+                }
+            };
+}
diff --git a/core/java/android/window/TaskOrganizer.java b/core/java/android/window/TaskOrganizer.java
index 12c4b5b..73b2fe1 100644
--- a/core/java/android/window/TaskOrganizer.java
+++ b/core/java/android/window/TaskOrganizer.java
@@ -89,19 +89,19 @@
      * application is starting. The client is responsible to add/remove the starting window if it
      * has create a starting window for the Task.
      *
-     * @param taskInfo The information about the Task that's available
+     * @param info The information about the Task that's available
      * @param appToken Token of the application being started.
      *        context to for resources
      */
     @BinderThread
-    public void addStartingWindow(@NonNull ActivityManager.RunningTaskInfo taskInfo,
+    public void addStartingWindow(@NonNull StartingWindowInfo info,
             @NonNull IBinder appToken) {}
 
     /**
      * Called when the Task want to remove the starting window.
      */
     @BinderThread
-    public void removeStartingWindow(@NonNull ActivityManager.RunningTaskInfo taskInfo) {}
+    public void removeStartingWindow(int taskId) {}
 
     /**
      * Called when a task with the registered windowing mode can be controlled by this task
@@ -221,13 +221,15 @@
 
     private final ITaskOrganizer mInterface = new ITaskOrganizer.Stub() {
         @Override
-        public void addStartingWindow(ActivityManager.RunningTaskInfo taskInfo, IBinder appToken) {
-            mExecutor.execute(() -> TaskOrganizer.this.addStartingWindow(taskInfo, appToken));
+
+        public void addStartingWindow(StartingWindowInfo windowInfo,
+                IBinder appToken) {
+            mExecutor.execute(() -> TaskOrganizer.this.addStartingWindow(windowInfo, appToken));
         }
 
         @Override
-        public void removeStartingWindow(ActivityManager.RunningTaskInfo taskInfo) {
-            mExecutor.execute(() -> TaskOrganizer.this.removeStartingWindow(taskInfo));
+        public void removeStartingWindow(int taskId) {
+            mExecutor.execute(() -> TaskOrganizer.this.removeStartingWindow(taskId));
         }
 
         @Override
diff --git a/core/java/com/android/internal/inputmethod/CallbackUtils.java b/core/java/com/android/internal/inputmethod/CallbackUtils.java
index a77583f..248feb8 100644
--- a/core/java/com/android/internal/inputmethod/CallbackUtils.java
+++ b/core/java/com/android/internal/inputmethod/CallbackUtils.java
@@ -19,10 +19,14 @@
 import android.annotation.AnyThread;
 import android.annotation.NonNull;
 import android.os.RemoteException;
+import android.view.inputmethod.InputMethodInfo;
+import android.view.inputmethod.InputMethodSubtype;
 
 import com.android.internal.view.InputBindResult;
 
+import java.util.List;
 import java.util.function.BooleanSupplier;
+import java.util.function.IntSupplier;
 import java.util.function.Supplier;
 
 /**
@@ -67,7 +71,7 @@
     /**
      * A utility method using given {@link IBooleanResultCallback} to callback the result.
      *
-     * @param callback {@link IInputBindResultResultCallback} to be called back.
+     * @param callback {@link IBooleanResultCallback} to be called back.
      * @param resultSupplier the supplier from which the result is provided.
      */
     public static void onResult(@NonNull IBooleanResultCallback callback,
@@ -89,4 +93,111 @@
             callback.onResult(result);
         } catch (RemoteException ignored) { }
     }
+
+    /**
+     * A utility method using given {@link IInputMethodSubtypeResultCallback} to callback the
+     * result.
+     *
+     * @param callback {@link IInputMethodSubtypeResultCallback} to be called back.
+     * @param resultSupplier the supplier from which the result is provided.
+     */
+    public static void onResult(@NonNull IInputMethodSubtypeResultCallback callback,
+            @NonNull Supplier<InputMethodSubtype> resultSupplier) {
+        InputMethodSubtype result = null;
+        Throwable exception = null;
+
+        try {
+            result = resultSupplier.get();
+        } catch (Throwable throwable) {
+            exception = throwable;
+        }
+
+        try {
+            if (exception != null) {
+                callback.onError(ThrowableHolder.of(exception));
+                return;
+            }
+            callback.onResult(result);
+        } catch (RemoteException ignored) { }
+    }
+
+    /**
+     * A utility method using given {@link IInputMethodSubtypeListResultCallback} to callback the
+     * result.
+     *
+     * @param callback {@link IInputMethodSubtypeListResultCallback} to be called back.
+     * @param resultSupplier the supplier from which the result is provided.
+     */
+    public static void onResult(@NonNull IInputMethodSubtypeListResultCallback callback,
+            @NonNull Supplier<List<InputMethodSubtype>> resultSupplier) {
+        List<InputMethodSubtype> result = null;
+        Throwable exception = null;
+
+        try {
+            result = resultSupplier.get();
+        } catch (Throwable throwable) {
+            exception = throwable;
+        }
+
+        try {
+            if (exception != null) {
+                callback.onError(ThrowableHolder.of(exception));
+                return;
+            }
+            callback.onResult(result);
+        } catch (RemoteException ignored) { }
+    }
+
+    /**
+     * A utility method using given {@link IInputMethodInfoListResultCallback} to callback the
+     * result.
+     *
+     * @param callback {@link IInputMethodInfoListResultCallback} to be called back.
+     * @param resultSupplier the supplier from which the result is provided.
+     */
+    public static void onResult(@NonNull IInputMethodInfoListResultCallback callback,
+            @NonNull Supplier<List<InputMethodInfo>> resultSupplier) {
+        List<InputMethodInfo> result = null;
+        Throwable exception = null;
+
+        try {
+            result = resultSupplier.get();
+        } catch (Throwable throwable) {
+            exception = throwable;
+        }
+
+        try {
+            if (exception != null) {
+                callback.onError(ThrowableHolder.of(exception));
+                return;
+            }
+            callback.onResult(result);
+        } catch (RemoteException ignored) { }
+    }
+
+    /**
+     * A utility method using given {@link IIntResultCallback} to callback the result.
+     *
+     * @param callback {@link IIntResultCallback} to be called back.
+     * @param resultSupplier the supplier from which the result is provided.
+     */
+    public static void onResult(@NonNull IIntResultCallback callback,
+            @NonNull IntSupplier resultSupplier) {
+        int result = 0;
+        Throwable exception = null;
+
+        try {
+            result = resultSupplier.getAsInt();
+        } catch (Throwable throwable) {
+            exception = throwable;
+        }
+
+        try {
+            if (exception != null) {
+                callback.onError(ThrowableHolder.of(exception));
+                return;
+            }
+            callback.onResult(result);
+        } catch (RemoteException ignored) { }
+    }
 }
diff --git a/core/java/com/android/internal/inputmethod/Completable.java b/core/java/com/android/internal/inputmethod/Completable.java
index bd8c23e..1913fcd 100644
--- a/core/java/com/android/internal/inputmethod/Completable.java
+++ b/core/java/com/android/internal/inputmethod/Completable.java
@@ -23,10 +23,12 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.util.Log;
+import android.view.inputmethod.InputMethodSubtype;
 
 import com.android.internal.annotations.GuardedBy;
 
 import java.lang.annotation.Retention;
+import java.util.List;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
 
@@ -373,6 +375,27 @@
     }
 
     /**
+     * @return an instance of {@link Completable.InputMethodSubtype}.
+     */
+    public static Completable.InputMethodSubtype createInputMethodSubtype() {
+        return new Completable.InputMethodSubtype();
+    }
+
+    /**
+     * @return an instance of {@link Completable.InputMethodSubtypeList}.
+     */
+    public static Completable.InputMethodSubtypeList createInputMethodSubtypeList() {
+        return new Completable.InputMethodSubtypeList();
+    }
+
+    /**
+     * @return an instance of {@link Completable.InputMethodInfoList}.
+     */
+    public static Completable.InputMethodInfoList createInputMethodInfoList() {
+        return new Completable.InputMethodInfoList();
+    }
+
+    /**
      * Completable object of {@link java.lang.Boolean}.
      */
     public static final class Boolean extends Values<java.lang.Boolean> { }
@@ -401,6 +424,24 @@
             extends Values<com.android.internal.view.InputBindResult> { }
 
     /**
+     * Completable object of {@link android.view.inputmethod.InputMethodSubtype}.
+     */
+    public static final class InputMethodSubtype
+            extends Values<android.view.inputmethod.InputMethodSubtype> { }
+
+    /**
+     * Completable object of {@link List<android.view.inputmethod.InputMethodSubtype>}.
+     */
+    public static final class InputMethodSubtypeList
+            extends Values<List<android.view.inputmethod.InputMethodSubtype>> { }
+
+    /**
+     * Completable object of {@link List<android.view.inputmethod.InputMethodInfo>}.
+     */
+    public static final class InputMethodInfoList
+            extends Values<List<android.view.inputmethod.InputMethodInfo>> { }
+
+    /**
      * Await the result by the {@link Completable.Values}.
      *
      * @return the result once {@link ValueBase#onComplete()}
@@ -413,6 +454,17 @@
     }
 
     /**
+     * Await the int result by the {@link Completable.Int}.
+     *
+     * @return the result once {@link ValueBase#onComplete()}
+     */
+    @AnyThread
+    public static int getIntResult(@NonNull Completable.Int value) {
+        value.await();
+        return value.getValue();
+    }
+
+    /**
      * Await the result by the {@link Completable.Int}, and log it if there is no result after
      * given timeout.
      *
diff --git a/core/java/com/android/internal/inputmethod/IInputMethodInfoListResultCallback.aidl b/core/java/com/android/internal/inputmethod/IInputMethodInfoListResultCallback.aidl
new file mode 100644
index 0000000..0dfd5da
--- /dev/null
+++ b/core/java/com/android/internal/inputmethod/IInputMethodInfoListResultCallback.aidl
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.inputmethod;
+
+import android.view.inputmethod.InputMethodInfo;
+import com.android.internal.inputmethod.ThrowableHolder;
+
+oneway interface IInputMethodInfoListResultCallback {
+    void onResult(in List<InputMethodInfo> result);
+    void onError(in ThrowableHolder exception);
+}
\ No newline at end of file
diff --git a/core/java/com/android/internal/inputmethod/IInputMethodSubtypeListResultCallback.aidl b/core/java/com/android/internal/inputmethod/IInputMethodSubtypeListResultCallback.aidl
new file mode 100644
index 0000000..619c87e
--- /dev/null
+++ b/core/java/com/android/internal/inputmethod/IInputMethodSubtypeListResultCallback.aidl
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.inputmethod;
+
+import android.view.inputmethod.InputMethodSubtype;
+import com.android.internal.inputmethod.ThrowableHolder;
+
+oneway interface IInputMethodSubtypeListResultCallback {
+    void onResult(in List<InputMethodSubtype> result);
+    void onError(in ThrowableHolder exception);
+}
\ No newline at end of file
diff --git a/core/java/com/android/internal/inputmethod/IInputMethodSubtypeResultCallback.aidl b/core/java/com/android/internal/inputmethod/IInputMethodSubtypeResultCallback.aidl
new file mode 100644
index 0000000..66c0902
--- /dev/null
+++ b/core/java/com/android/internal/inputmethod/IInputMethodSubtypeResultCallback.aidl
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.inputmethod;
+
+import android.view.inputmethod.InputMethodSubtype;
+import com.android.internal.inputmethod.ThrowableHolder;
+
+oneway interface IInputMethodSubtypeResultCallback {
+    void onResult(in InputMethodSubtype result);
+    void onError(in ThrowableHolder exception);
+}
\ No newline at end of file
diff --git a/core/java/com/android/internal/inputmethod/IIntResultCallback.aidl b/core/java/com/android/internal/inputmethod/IIntResultCallback.aidl
index bc5ed0d..ceda66c 100644
--- a/core/java/com/android/internal/inputmethod/IIntResultCallback.aidl
+++ b/core/java/com/android/internal/inputmethod/IIntResultCallback.aidl
@@ -16,6 +16,9 @@
 
 package com.android.internal.inputmethod;
 
+import com.android.internal.inputmethod.ThrowableHolder;
+
 oneway interface IIntResultCallback {
     void onResult(int result);
+    void onError(in ThrowableHolder exception);
 }
diff --git a/core/java/com/android/internal/inputmethod/ResultCallbacks.java b/core/java/com/android/internal/inputmethod/ResultCallbacks.java
index b07c5f8..6ce851b 100644
--- a/core/java/com/android/internal/inputmethod/ResultCallbacks.java
+++ b/core/java/com/android/internal/inputmethod/ResultCallbacks.java
@@ -20,10 +20,13 @@
 import android.annotation.BinderThread;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.view.inputmethod.InputMethodInfo;
+import android.view.inputmethod.InputMethodSubtype;
 
 import com.android.internal.view.InputBindResult;
 
 import java.lang.ref.WeakReference;
+import java.util.List;
 import java.util.concurrent.atomic.AtomicReference;
 
 /**
@@ -73,6 +76,16 @@
                 }
                 value.onComplete(result);
             }
+
+            @BinderThread
+            @Override
+            public void onError(ThrowableHolder throwableHolder) {
+                final Completable.Int value = unwrap(atomicRef);
+                if (value == null) {
+                    return;
+                }
+                value.onError(throwableHolder);
+            }
         };
     }
 
@@ -228,4 +241,115 @@
             }
         };
     }
+
+    /**
+     * Creates {@link IInputMethodSubtypeResultCallback.Stub} that is to set
+     * {@link Completable.InputMethodSubtype} when receiving the result.
+     *
+     * @param value {@link Completable.InputMethodSubtype} to be set when receiving the result.
+     * @return {@link IInputMethodSubtypeResultCallback.Stub} that can be passed as a binder
+     * IPC parameter.
+     */
+    @AnyThread
+    public static IInputMethodSubtypeResultCallback.Stub of(
+            @NonNull Completable.InputMethodSubtype value) {
+        final AtomicReference<WeakReference<Completable.InputMethodSubtype>>
+                atomicRef = new AtomicReference<>(new WeakReference<>(value));
+
+        return new IInputMethodSubtypeResultCallback.Stub() {
+            @BinderThread
+            @Override
+            public void onResult(InputMethodSubtype result) {
+                final Completable.InputMethodSubtype value = unwrap(atomicRef);
+                if (value == null) {
+                    return;
+                }
+                value.onComplete(result);
+            }
+
+            @BinderThread
+            @Override
+            public void onError(ThrowableHolder throwableHolder) {
+                final Completable.InputMethodSubtype value = unwrap(atomicRef);
+                if (value == null) {
+                    return;
+                }
+                value.onError(throwableHolder);
+            }
+        };
+    }
+
+    /**
+     * Creates {@link IInputMethodSubtypeListResultCallback.Stub} that is to set
+     * {@link Completable.InputMethodSubtypeList} when receiving the result.
+     *
+     * @param value {@link Completable.InputMethodSubtypeList} to be set when receiving the result.
+     * @return {@link IInputMethodSubtypeListResultCallback.Stub} that can be passed as a binder
+     * IPC parameter.
+     */
+    @AnyThread
+    public static IInputMethodSubtypeListResultCallback.Stub of(
+            @NonNull Completable.InputMethodSubtypeList value) {
+        final AtomicReference<WeakReference<Completable.InputMethodSubtypeList>>
+                atomicRef = new AtomicReference<>(new WeakReference<>(value));
+
+        return new IInputMethodSubtypeListResultCallback.Stub() {
+            @BinderThread
+            @Override
+            public void onResult(List<InputMethodSubtype> result) {
+                final Completable.InputMethodSubtypeList value = unwrap(atomicRef);
+                if (value == null) {
+                    return;
+                }
+                value.onComplete(result);
+            }
+
+            @BinderThread
+            @Override
+            public void onError(ThrowableHolder throwableHolder) {
+                final Completable.InputMethodSubtypeList value = unwrap(atomicRef);
+                if (value == null) {
+                    return;
+                }
+                value.onError(throwableHolder);
+            }
+        };
+    }
+
+    /**
+     * Creates {@link IInputMethodInfoListResultCallback.Stub} that is to set
+     * {@link Completable.InputMethodInfoList} when receiving the result.
+     *
+     * @param value {@link Completable.InputMethodInfoList} to be set when receiving the result.
+     * @return {@link IInputMethodInfoListResultCallback.Stub} that can be passed as a binder
+     * IPC parameter.
+     */
+    @AnyThread
+    public static IInputMethodInfoListResultCallback.Stub of(
+            @NonNull Completable.InputMethodInfoList value) {
+        final AtomicReference<WeakReference<Completable.InputMethodInfoList>>
+                atomicRef = new AtomicReference<>(new WeakReference<>(value));
+
+        return new IInputMethodInfoListResultCallback.Stub() {
+            @BinderThread
+            @Override
+            public void onResult(List<InputMethodInfo> result) {
+                final Completable.InputMethodInfoList value = unwrap(atomicRef);
+                if (value == null) {
+                    return;
+                }
+                value.onComplete(result);
+            }
+
+            @BinderThread
+            @Override
+            public void onError(ThrowableHolder throwableHolder) {
+                final Completable.InputMethodInfoList value = unwrap(atomicRef);
+                if (value == null) {
+                    return;
+                }
+                value.onError(throwableHolder);
+            }
+        };
+    }
 }
diff --git a/core/java/com/android/internal/net/NetworkUtilsInternal.java b/core/java/com/android/internal/net/NetworkUtilsInternal.java
new file mode 100644
index 0000000..571d7e7
--- /dev/null
+++ b/core/java/com/android/internal/net/NetworkUtilsInternal.java
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.net;
+
+import static android.system.OsConstants.AF_INET;
+import static android.system.OsConstants.AF_INET6;
+
+import android.annotation.NonNull;
+import android.system.Os;
+
+/** @hide */
+public class NetworkUtilsInternal {
+
+    private static final int[] ADDRESS_FAMILIES = new int[] {AF_INET, AF_INET6};
+
+    /**
+     * Allow/Disallow creating AF_INET/AF_INET6 sockets and DNS lookups for current process.
+     *
+     * @param allowNetworking whether to allow or disallow creating AF_INET/AF_INET6 sockets
+     *                        and DNS lookups.
+     */
+    public static native void setAllowNetworkingForProcess(boolean allowNetworking);
+
+    /**
+     * Returns true if the hostname is weakly validated.
+     * @param hostname Name of host to validate.
+     * @return True if it's a valid-ish hostname.
+     *
+     * @hide
+     */
+    public static boolean isWeaklyValidatedHostname(@NonNull String hostname) {
+        // TODO(b/34953048): Use a validation method that permits more accurate,
+        // but still inexpensive, checking of likely valid DNS hostnames.
+        final String weakHostnameRegex = "^[a-zA-Z0-9_.-]+$";
+        if (!hostname.matches(weakHostnameRegex)) {
+            return false;
+        }
+
+        for (int address_family : ADDRESS_FAMILIES) {
+            if (Os.inet_pton(address_family, hostname) != null) {
+                return false;
+            }
+        }
+
+        return true;
+    }
+
+    /**
+     * Safely multiple a value by a rational.
+     * <p>
+     * Internally it uses integer-based math whenever possible, but switches
+     * over to double-based math if values would overflow.
+     * @hide
+     */
+    public static long multiplySafeByRational(long value, long num, long den) {
+        if (den == 0) {
+            throw new ArithmeticException("Invalid Denominator");
+        }
+        long x = value;
+        long y = num;
+
+        // Logic shamelessly borrowed from Math.multiplyExact()
+        long r = x * y;
+        long ax = Math.abs(x);
+        long ay = Math.abs(y);
+        if (((ax | ay) >>> 31 != 0)) {
+            // Some bits greater than 2^31 that might cause overflow
+            // Check the result using the divide operator
+            // and check for the special case of Long.MIN_VALUE * -1
+            if (((y != 0) && (r / y != x))
+                    || (x == Long.MIN_VALUE && y == -1)) {
+                // Use double math to avoid overflowing
+                return (long) (((double) num / den) * value);
+            }
+        }
+        return r / den;
+    }
+}
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index 5aedd1e..0fa0df6 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -953,7 +953,8 @@
     /**
      * The Bluetooth controller activity (time in tx, rx, idle, and power consumed) for the device.
      */
-    ControllerActivityCounterImpl mBluetoothActivity;
+    @VisibleForTesting
+    protected ControllerActivityCounterImpl mBluetoothActivity;
 
     /**
      * The Modem controller activity (time in tx, rx, idle, and power consumed) for the device.
@@ -1106,6 +1107,16 @@
     private long[] mCpuFreqs;
 
     /**
+     * Times spent by the system server process grouped by cluster and CPU speed.
+     */
+    private LongSamplingCounterArray mSystemServerCpuTimesUs;
+
+    /**
+     * Times spent by the system server threads grouped by cluster and CPU speed.
+     */
+    private LongSamplingCounterArray mSystemServerThreadCpuTimesUs;
+
+    /**
      * Times spent by the system server threads handling incoming binder requests.
      */
     private LongSamplingCounterArray mBinderThreadCpuTimesUs;
@@ -10844,14 +10855,6 @@
         }
     }
 
-    /**
-     * Starts tracking CPU time-in-state for threads of the system server process,
-     * keeping a separate account of threads receiving incoming binder calls.
-     */
-    public void startTrackingSystemServerCpuTime() {
-        mSystemServerCpuThreadReader.startTrackingThreadCpuTime();
-    }
-
     public void setCallback(BatteryCallback cb) {
         mCallback = cb;
     }
@@ -11504,6 +11507,8 @@
 
         MeasuredEnergyStats.resetIfNotNull(mGlobalMeasuredEnergyStats);
 
+        resetIfNotNull(mSystemServerCpuTimesUs, false, elapsedRealtimeUs);
+        resetIfNotNull(mSystemServerThreadCpuTimesUs, false, elapsedRealtimeUs);
         resetIfNotNull(mBinderThreadCpuTimesUs, false, elapsedRealtimeUs);
 
         mLastHistoryStepDetails = null;
@@ -12703,17 +12708,27 @@
             return;
         }
 
-        if (mBinderThreadCpuTimesUs == null) {
+        if (mSystemServerCpuTimesUs == null) {
+            mSystemServerCpuTimesUs = new LongSamplingCounterArray(mOnBatteryTimeBase);
+            mSystemServerThreadCpuTimesUs = new LongSamplingCounterArray(mOnBatteryTimeBase);
             mBinderThreadCpuTimesUs = new LongSamplingCounterArray(mOnBatteryTimeBase);
         }
+        mSystemServerCpuTimesUs.addCountLocked(systemServiceCpuThreadTimes.processCpuTimesUs);
+        mSystemServerThreadCpuTimesUs.addCountLocked(systemServiceCpuThreadTimes.threadCpuTimesUs);
         mBinderThreadCpuTimesUs.addCountLocked(systemServiceCpuThreadTimes.binderThreadCpuTimesUs);
 
         if (DEBUG_BINDER_STATS) {
-            Slog.d(TAG, "System server threads per CPU cluster (incoming binder threads)");
+            Slog.d(TAG, "System server threads per CPU cluster (binder threads/total threads/%)");
+            long totalCpuTimeMs = 0;
+            long totalThreadTimeMs = 0;
             long binderThreadTimeMs = 0;
             int cpuIndex = 0;
-            final long[] binderThreadCpuTimesUs = mBinderThreadCpuTimesUs.getCountsLocked(
-                    BatteryStats.STATS_SINCE_CHARGED);
+            final long[] systemServerCpuTimesUs =
+                    mSystemServerCpuTimesUs.getCountsLocked(0);
+            final long[] systemServerThreadCpuTimesUs =
+                    mSystemServerThreadCpuTimesUs.getCountsLocked(0);
+            final long[] binderThreadCpuTimesUs =
+                    mBinderThreadCpuTimesUs.getCountsLocked(0);
             int index = 0;
             int numCpuClusters = mPowerProfile.getNumCpuClusters();
             for (int cluster = 0; cluster < numCpuClusters; cluster++) {
@@ -12724,15 +12739,28 @@
                     if (speed != 0) {
                         sb.append(", ");
                     }
+                    long totalCountMs = systemServerThreadCpuTimesUs[index] / 1000;
                     long binderCountMs = binderThreadCpuTimesUs[index] / 1000;
-                    sb.append(TextUtils.formatSimple("%10d", binderCountMs));
+                    sb.append(String.format("%d/%d(%.1f%%)",
+                            binderCountMs,
+                            totalCountMs,
+                            totalCountMs != 0 ? (double) binderCountMs * 100 / totalCountMs : 0));
 
+                    totalCpuTimeMs += systemServerCpuTimesUs[index] / 1000;
+                    totalThreadTimeMs += totalCountMs;
                     binderThreadTimeMs += binderCountMs;
                     index++;
                 }
                 cpuIndex += mPowerProfile.getNumCoresInCpuCluster(cluster);
                 Slog.d(TAG, sb.toString());
             }
+
+            Slog.d(TAG, "Total system server CPU time (ms): " + totalCpuTimeMs);
+            Slog.d(TAG, "Total system server thread time (ms): " + totalThreadTimeMs);
+            Slog.d(TAG, String.format("Total Binder thread time (ms): %d (%.1f%%)",
+                    binderThreadTimeMs,
+                    binderThreadTimeMs != 0
+                            ? (double) binderThreadTimeMs * 100 / totalThreadTimeMs : 0));
         }
     }
 
@@ -14007,16 +14035,60 @@
     }
 
 
-    /**
-     * Estimates the time spent by the system server handling incoming binder requests.
-     */
     @Override
     public long[] getSystemServiceTimeAtCpuSpeeds() {
-        if (mBinderThreadCpuTimesUs == null) {
+        // Estimates the time spent by the system server handling incoming binder requests.
+        //
+        // The data that we can get from the kernel is this:
+        //   - CPU duration for a (thread - cluster - CPU speed) combination
+        //   - CPU duration for a (UID - cluster - CPU speed) combination
+        //
+        // The configuration we have in the Power Profile is this:
+        //   - Average CPU power for a (cluster - CPU speed) combination.
+        //
+        // The model used by BatteryStats can be illustrated with this example:
+        //
+        // - Let's say the system server has 10 threads.
+        // - These 10 threads spent 1000 ms of CPU time in aggregate
+        // - Of the 10 threads 4 were execute exclusively incoming binder calls.
+        // - These 4 "binder" threads consumed 600 ms of CPU time in aggregate
+        // - The real time spent by the system server process doing all of this is, say, 200 ms.
+        //
+        // We will assume that power consumption is proportional to the time spent by the CPU
+        // across all threads.  This is a crude assumption, but we don't have more detailed data.
+        // Thus,
+        //   binderRealTime = realTime * aggregateBinderThreadTime / aggregateAllThreadTime
+        //
+        // In our example,
+        //   binderRealTime = 200 * 600 / 1000 = 120ms
+        //
+        // We can then multiply this estimated time by the average power to obtain an estimate
+        // of the total power consumed by incoming binder calls for the given cluster/speed
+        // combination.
+
+        if (mSystemServerCpuTimesUs == null) {
             return null;
         }
 
-        return mBinderThreadCpuTimesUs.getCountsLocked(BatteryStats.STATS_SINCE_CHARGED);
+        final long[] systemServerCpuTimesUs = mSystemServerCpuTimesUs.getCountsLocked(
+                BatteryStats.STATS_SINCE_CHARGED);
+        final long [] systemServerThreadCpuTimesUs = mSystemServerThreadCpuTimesUs.getCountsLocked(
+                BatteryStats.STATS_SINCE_CHARGED);
+        final long[] binderThreadCpuTimesUs = mBinderThreadCpuTimesUs.getCountsLocked(
+                BatteryStats.STATS_SINCE_CHARGED);
+
+        final int size = systemServerCpuTimesUs.length;
+        final long[] results = new long[size];
+
+        for (int i = 0; i < size; i++) {
+            if (systemServerThreadCpuTimesUs[i] == 0) {
+                continue;
+            }
+
+            results[i] = systemServerCpuTimesUs[i] * binderThreadCpuTimesUs[i]
+                    / systemServerThreadCpuTimesUs[i];
+        }
+        return results;
     }
 
     /**
@@ -14412,7 +14484,7 @@
         }
 
         updateSystemServiceCallStats();
-        if (mBinderThreadCpuTimesUs != null) {
+        if (mSystemServerThreadCpuTimesUs != null) {
             pw.println("Per UID System server binder time in ms:");
             long[] systemServiceTimeAtCpuSpeeds = getSystemServiceTimeAtCpuSpeeds();
             for (int i = 0; i < size; i++) {
@@ -15999,6 +16071,9 @@
             mUidStats.append(uid, u);
         }
 
+        mSystemServerCpuTimesUs = LongSamplingCounterArray.readFromParcel(in, mOnBatteryTimeBase);
+        mSystemServerThreadCpuTimesUs = LongSamplingCounterArray.readFromParcel(in,
+                mOnBatteryTimeBase);
         mBinderThreadCpuTimesUs = LongSamplingCounterArray.readFromParcel(in, mOnBatteryTimeBase);
     }
 
@@ -16207,6 +16282,8 @@
         } else {
             out.writeInt(0);
         }
+        LongSamplingCounterArray.writeToParcel(out, mSystemServerCpuTimesUs);
+        LongSamplingCounterArray.writeToParcel(out, mSystemServerThreadCpuTimesUs);
         LongSamplingCounterArray.writeToParcel(out, mBinderThreadCpuTimesUs);
     }
 
diff --git a/core/java/com/android/internal/os/BluetoothPowerCalculator.java b/core/java/com/android/internal/os/BluetoothPowerCalculator.java
index 11099be..f5690e0 100644
--- a/core/java/com/android/internal/os/BluetoothPowerCalculator.java
+++ b/core/java/com/android/internal/os/BluetoothPowerCalculator.java
@@ -15,8 +15,13 @@
  */
 package com.android.internal.os;
 
+import android.os.BatteryConsumer;
 import android.os.BatteryStats;
+import android.os.BatteryUsageStats;
+import android.os.BatteryUsageStatsQuery;
 import android.os.Process;
+import android.os.SystemBatteryConsumer;
+import android.os.UidBatteryConsumer;
 import android.os.UserHandle;
 import android.util.Log;
 import android.util.SparseArray;
@@ -30,8 +35,16 @@
     private final double mRxMa;
     private final double mTxMa;
     private final boolean mHasBluetoothPowerController;
-    private double mAppTotalPowerMah = 0;
-    private long mAppTotalTimeMs = 0;
+
+    private static class PowerAndDuration {
+        public long durationMs;
+        public double powerMah;
+    }
+
+    // Objects used for passing calculation results. Fields are used to avoid allocations.
+    private final PowerAndDuration mUidPowerAndDuration = new PowerAndDuration();
+    private final PowerAndDuration mTotalPowerAndDuration = new PowerAndDuration();
+    private final PowerAndDuration mSystemPowerAndDuration = new PowerAndDuration();
 
     public BluetoothPowerCalculator(PowerProfile profile) {
         mIdleMa = profile.getAveragePower(PowerProfile.POWER_BLUETOOTH_CONTROLLER_IDLE);
@@ -41,16 +54,90 @@
     }
 
     @Override
+    public void calculate(BatteryUsageStats.Builder builder, BatteryStats batteryStats,
+            long rawRealtimeUs, long rawUptimeUs, BatteryUsageStatsQuery query,
+            SparseArray<UserHandle> asUsers) {
+        if (!mHasBluetoothPowerController || !batteryStats.hasBluetoothActivityReporting()) {
+            return;
+        }
+
+        mTotalPowerAndDuration.durationMs = 0;
+        mTotalPowerAndDuration.powerMah = 0;
+
+        SystemBatteryConsumer.Builder systemBatteryConsumerBuilder =
+                builder.getOrCreateSystemBatteryConsumerBuilder(
+                        SystemBatteryConsumer.DRAIN_TYPE_BLUETOOTH);
+
+        final SparseArray<UidBatteryConsumer.Builder> uidBatteryConsumerBuilders =
+                builder.getUidBatteryConsumerBuilders();
+        for (int i = uidBatteryConsumerBuilders.size() - 1; i >= 0; i--) {
+            final UidBatteryConsumer.Builder app = uidBatteryConsumerBuilders.valueAt(i);
+            calculateApp(app);
+            if (app.getUid() == Process.BLUETOOTH_UID) {
+                app.setSystemComponent(true);
+                systemBatteryConsumerBuilder.addUidBatteryConsumer(app);
+            }
+        }
+
+        final BatteryStats.ControllerActivityCounter counter =
+                batteryStats.getBluetoothControllerActivity();
+
+        calculatePowerAndDuration(counter, mSystemPowerAndDuration);
+
+        // Subtract what the apps used, but clamp to 0.
+        final long systemComponentDurationMs = Math.max(0,
+                mSystemPowerAndDuration.durationMs - mTotalPowerAndDuration.durationMs);
+        final double systemComponentPowerMah = Math.max(0,
+                mSystemPowerAndDuration.powerMah - mTotalPowerAndDuration.powerMah);
+
+        systemBatteryConsumerBuilder
+                .setUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_BLUETOOTH,
+                        systemComponentDurationMs)
+                .setConsumedPower(BatteryConsumer.POWER_COMPONENT_BLUETOOTH,
+                        systemComponentPowerMah);
+    }
+
+    private void calculateApp(UidBatteryConsumer.Builder app) {
+        calculatePowerAndDuration(app.getBatteryStatsUid().getBluetoothControllerActivity(),
+                mUidPowerAndDuration);
+
+        app.setUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_BLUETOOTH,
+                mUidPowerAndDuration.durationMs)
+                .setConsumedPower(BatteryConsumer.POWER_COMPONENT_BLUETOOTH,
+                        mUidPowerAndDuration.powerMah);
+
+        mTotalPowerAndDuration.powerMah += mUidPowerAndDuration.powerMah;
+        mTotalPowerAndDuration.durationMs += mUidPowerAndDuration.durationMs;
+    }
+
+    @Override
     public void calculate(List<BatterySipper> sippers, BatteryStats batteryStats,
             long rawRealtimeUs, long rawUptimeUs, int statsType, SparseArray<UserHandle> asUsers) {
         if (!mHasBluetoothPowerController || !batteryStats.hasBluetoothActivityReporting()) {
             return;
         }
 
+        mTotalPowerAndDuration.durationMs = 0;
+        mTotalPowerAndDuration.powerMah = 0;
+
         super.calculate(sippers, batteryStats, rawRealtimeUs, rawUptimeUs, statsType, asUsers);
 
         BatterySipper bs = new BatterySipper(BatterySipper.DrainType.BLUETOOTH, null, 0);
-        calculateRemaining(bs, batteryStats, rawRealtimeUs, rawUptimeUs, statsType);
+        calculatePowerAndDuration(batteryStats.getBluetoothControllerActivity(),
+                mSystemPowerAndDuration);
+
+        // Subtract what the apps used, but clamp to 0.
+        double powerMah =
+                Math.max(0, mSystemPowerAndDuration.powerMah - mTotalPowerAndDuration.powerMah);
+        final long durationMs =
+                Math.max(0, mSystemPowerAndDuration.durationMs - mTotalPowerAndDuration.durationMs);
+        if (DEBUG && powerMah != 0) {
+            Log.d(TAG, "Bluetooth active: time=" + (durationMs)
+                    + " power=" + formatCharge(powerMah));
+        }
+
+        bs.bluetoothPowerMah = powerMah;
+        bs.bluetoothRunningTimeMs = durationMs;
 
         for (int i = sippers.size() - 1; i >= 0; i--) {
             BatterySipper app = sippers.get(i);
@@ -69,65 +156,42 @@
     protected void calculateApp(BatterySipper app, BatteryStats.Uid u, long rawRealtimeUs,
                              long rawUptimeUs, int statsType) {
 
-        final BatteryStats.ControllerActivityCounter counter = u.getBluetoothControllerActivity();
-        if (counter == null) {
-            return;
-        }
+        calculatePowerAndDuration(u.getBluetoothControllerActivity(), mUidPowerAndDuration);
 
-        final long idleTimeMs = counter.getIdleTimeCounter().getCountLocked(statsType);
-        final long rxTimeMs = counter.getRxTimeCounter().getCountLocked(statsType);
-        final long txTimeMs = counter.getTxTimeCounters()[0].getCountLocked(statsType);
-        final long totalTimeMs = idleTimeMs + txTimeMs + rxTimeMs;
-        double powerMah = counter.getPowerCounter().getCountLocked(statsType)
-                / (double)(1000*60*60);
-
-        if (powerMah == 0) {
-            powerMah = ((idleTimeMs * mIdleMa) + (rxTimeMs * mRxMa) + (txTimeMs * mTxMa))
-                    / (1000*60*60);
-        }
-
-        app.bluetoothPowerMah = powerMah;
-        app.bluetoothRunningTimeMs = totalTimeMs;
+        app.bluetoothPowerMah = mUidPowerAndDuration.powerMah;
+        app.bluetoothRunningTimeMs = mUidPowerAndDuration.durationMs;
         app.btRxBytes = u.getNetworkActivityBytes(BatteryStats.NETWORK_BT_RX_DATA, statsType);
         app.btTxBytes = u.getNetworkActivityBytes(BatteryStats.NETWORK_BT_TX_DATA, statsType);
 
-        mAppTotalPowerMah += powerMah;
-        mAppTotalTimeMs += totalTimeMs;
+        mTotalPowerAndDuration.powerMah += mUidPowerAndDuration.powerMah;
+        mTotalPowerAndDuration.durationMs += mUidPowerAndDuration.durationMs;
     }
 
-    private void calculateRemaining(BatterySipper app, BatteryStats stats, long rawRealtimeUs,
-                                   long rawUptimeUs, int statsType) {
-        final BatteryStats.ControllerActivityCounter counter =
-                stats.getBluetoothControllerActivity();
+    private void calculatePowerAndDuration(BatteryStats.ControllerActivityCounter counter,
+            PowerAndDuration powerAndDuration) {
+        if (counter == null) {
+            powerAndDuration.durationMs = 0;
+            powerAndDuration.powerMah = 0;
+            return;
+        }
 
-        final long idleTimeMs = counter.getIdleTimeCounter().getCountLocked(statsType);
-        final long txTimeMs = counter.getTxTimeCounters()[0].getCountLocked(statsType);
-        final long rxTimeMs = counter.getRxTimeCounter().getCountLocked(statsType);
+        final long idleTimeMs =
+                counter.getIdleTimeCounter().getCountLocked(BatteryStats.STATS_SINCE_CHARGED);
+        final long rxTimeMs =
+                counter.getRxTimeCounter().getCountLocked(BatteryStats.STATS_SINCE_CHARGED);
+        final long txTimeMs =
+                counter.getTxTimeCounters()[0].getCountLocked(BatteryStats.STATS_SINCE_CHARGED);
         final long totalTimeMs = idleTimeMs + txTimeMs + rxTimeMs;
-        double powerMah = counter.getPowerCounter().getCountLocked(statsType)
-                 / (double)(1000*60*60);
+        double powerMah =
+                counter.getPowerCounter().getCountLocked(BatteryStats.STATS_SINCE_CHARGED)
+                        / (double) (1000 * 60 * 60);
 
         if (powerMah == 0) {
-            // Some devices do not report the power, so calculate it.
             powerMah = ((idleTimeMs * mIdleMa) + (rxTimeMs * mRxMa) + (txTimeMs * mTxMa))
-                    / (1000*60*60);
+                    / (1000 * 60 * 60);
         }
 
-        // Subtract what the apps used, but clamp to 0.
-        powerMah = Math.max(0, powerMah - mAppTotalPowerMah);
-
-        if (DEBUG && powerMah != 0) {
-            Log.d(TAG, "Bluetooth active: time=" + (totalTimeMs)
-                    + " power=" + formatCharge(powerMah));
-        }
-
-        app.bluetoothPowerMah = powerMah;
-        app.bluetoothRunningTimeMs = Math.max(0, totalTimeMs - mAppTotalTimeMs);
-    }
-
-    @Override
-    public void reset() {
-        mAppTotalPowerMah = 0;
-        mAppTotalTimeMs = 0;
+        powerAndDuration.durationMs = totalTimeMs;
+        powerAndDuration.powerMah = powerMah;
     }
 }
diff --git a/core/java/com/android/internal/os/KernelSingleProcessCpuThreadReader.java b/core/java/com/android/internal/os/KernelSingleProcessCpuThreadReader.java
index 4d2a08a..e6a9623 100644
--- a/core/java/com/android/internal/os/KernelSingleProcessCpuThreadReader.java
+++ b/core/java/com/android/internal/os/KernelSingleProcessCpuThreadReader.java
@@ -16,12 +16,23 @@
 
 package com.android.internal.os;
 
+import static android.os.Process.PROC_OUT_LONG;
+import static android.os.Process.PROC_SPACE_TERM;
+
 import android.annotation.Nullable;
+import android.os.Process;
+import android.system.Os;
+import android.system.OsConstants;
 import android.util.Slog;
 
 import com.android.internal.annotations.VisibleForTesting;
 
 import java.io.IOException;
+import java.nio.file.DirectoryIteratorException;
+import java.nio.file.DirectoryStream;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
 import java.util.Arrays;
 
 /**
@@ -34,65 +45,93 @@
     private static final String TAG = "KernelSingleProcCpuThreadRdr";
 
     private static final boolean DEBUG = false;
+    private static final boolean NATIVE_ENABLED = true;
+
+    /**
+     * The name of the file to read CPU statistics from, must be found in {@code
+     * /proc/$PID/task/$TID}
+     */
+    private static final String CPU_STATISTICS_FILENAME = "time_in_state";
+
+    private static final String PROC_STAT_FILENAME = "stat";
+
+    /** Directory under /proc/$PID containing CPU stats files for threads */
+    public static final String THREAD_CPU_STATS_DIRECTORY = "task";
+
+    /** Default mount location of the {@code proc} filesystem */
+    private static final Path DEFAULT_PROC_PATH = Paths.get("/proc");
+
+    /** The initial {@code time_in_state} file for {@link ProcTimeInStateReader} */
+    private static final Path INITIAL_TIME_IN_STATE_PATH = Paths.get("self/time_in_state");
+
+    /** See https://man7.org/linux/man-pages/man5/proc.5.html */
+    private static final int[] PROCESS_FULL_STATS_FORMAT = new int[] {
+            PROC_SPACE_TERM,
+            PROC_SPACE_TERM,
+            PROC_SPACE_TERM,
+            PROC_SPACE_TERM,
+            PROC_SPACE_TERM,
+            PROC_SPACE_TERM,
+            PROC_SPACE_TERM,
+            PROC_SPACE_TERM,
+            PROC_SPACE_TERM,
+            PROC_SPACE_TERM,
+            PROC_SPACE_TERM,
+            PROC_SPACE_TERM,
+            PROC_SPACE_TERM,
+            PROC_SPACE_TERM | PROC_OUT_LONG,                  // 14: utime
+            PROC_SPACE_TERM | PROC_OUT_LONG,                  // 15: stime
+            // Ignore remaining fields
+    };
+
+    private final long[] mProcessFullStatsData = new long[2];
+
+    private static final int PROCESS_FULL_STAT_UTIME = 0;
+    private static final int PROCESS_FULL_STAT_STIME = 1;
+
+    /** Used to read and parse {@code time_in_state} files */
+    private final ProcTimeInStateReader mProcTimeInStateReader;
 
     private final int mPid;
 
-    private final CpuTimeInStateReader mCpuTimeInStateReader;
+    /** Where the proc filesystem is mounted */
+    private final Path mProcPath;
 
-    private int[] mSelectedThreadNativeTids = new int[0];  // Sorted
+    // How long a CPU jiffy is in milliseconds.
+    private final long mJiffyMillis;
+
+    // Path: /proc/<pid>/stat
+    private final String mProcessStatFilePath;
+
+    // Path: /proc/<pid>/task
+    private final Path mThreadsDirectoryPath;
 
     /**
-     * Count of frequencies read from the {@code time_in_state} file.
+     * Count of frequencies read from the {@code time_in_state} file. Read from {@link
+     * #mProcTimeInStateReader#getCpuFrequenciesKhz()}.
      */
     private int mFrequencyCount;
 
-    private boolean mIsTracking;
-
-    /**
-     * A CPU time-in-state provider for testing.  Imitates the behavior of the corresponding
-     * methods in frameworks/native/libs/cputimeinstate/cputimeinstate.c
-     */
-    @VisibleForTesting
-    public interface CpuTimeInStateReader {
-        /**
-         * Returns the overall number of cluster-frequency combinations.
-         */
-        int getCpuFrequencyCount();
-
-        /**
-         * Returns true to indicate success.
-         *
-         * Called from native.
-         */
-        boolean startTrackingProcessCpuTimes(int tgid);
-
-        /**
-         * Returns true to indicate success.
-         *
-         * Called from native.
-         */
-        boolean startAggregatingTaskCpuTimes(int pid, int aggregationKey);
-
-        /**
-         * Must return an array of strings formatted like this:
-         * "aggKey:t0_0 t0_1...:t1_0 t1_1..."
-         * Times should be provided in nanoseconds.
-         *
-         * Called from native.
-         */
-        String[] getAggregatedTaskCpuFreqTimes(int pid);
-    }
-
     /**
      * Create with a path where `proc` is mounted. Used primarily for testing
      *
      * @param pid      PID of the process whose threads are to be read.
+     * @param procPath where `proc` is mounted (to find, see {@code mount | grep ^proc})
      */
     @VisibleForTesting
-    public KernelSingleProcessCpuThreadReader(int pid,
-            @Nullable CpuTimeInStateReader cpuTimeInStateReader) throws IOException {
+    public KernelSingleProcessCpuThreadReader(
+            int pid,
+            Path procPath) throws IOException {
         mPid = pid;
-        mCpuTimeInStateReader = cpuTimeInStateReader;
+        mProcPath = procPath;
+        mProcTimeInStateReader = new ProcTimeInStateReader(
+                mProcPath.resolve(INITIAL_TIME_IN_STATE_PATH));
+        long jiffyHz = Os.sysconf(OsConstants._SC_CLK_TCK);
+        mJiffyMillis = 1000 / jiffyHz;
+        mProcessStatFilePath =
+                mProcPath.resolve(String.valueOf(mPid)).resolve(PROC_STAT_FILENAME).toString();
+        mThreadsDirectoryPath =
+                mProcPath.resolve(String.valueOf(mPid)).resolve(THREAD_CPU_STATS_DIRECTORY);
     }
 
     /**
@@ -103,7 +142,7 @@
     @Nullable
     public static KernelSingleProcessCpuThreadReader create(int pid) {
         try {
-            return new KernelSingleProcessCpuThreadReader(pid, null);
+            return new KernelSingleProcessCpuThreadReader(pid, DEFAULT_PROC_PATH);
         } catch (IOException e) {
             Slog.e(TAG, "Failed to initialize KernelSingleProcessCpuThreadReader", e);
             return null;
@@ -111,98 +150,146 @@
     }
 
     /**
-     * Starts tracking aggregated CPU time-in-state of all threads of the process with the PID
-     * supplied in the constructor.
-     */
-    public void startTrackingThreadCpuTimes() {
-        if (!mIsTracking) {
-            if (!startTrackingProcessCpuTimes(mPid, mCpuTimeInStateReader)) {
-                Slog.e(TAG, "Failed to start tracking process CPU times for " + mPid);
-            }
-            if (mSelectedThreadNativeTids.length > 0) {
-                if (!startAggregatingThreadCpuTimes(mSelectedThreadNativeTids,
-                        mCpuTimeInStateReader)) {
-                    Slog.e(TAG, "Failed to start tracking aggregated thread CPU times for "
-                            + Arrays.toString(mSelectedThreadNativeTids));
-                }
-            }
-            mIsTracking = true;
-        }
-    }
-
-    /**
-     * @param nativeTids an array of native Thread IDs whose CPU times should
-     *                   be aggregated as a group.  This is expected to be a subset
-     *                   of all thread IDs owned by the process.
-     */
-    public void setSelectedThreadIds(int[] nativeTids) {
-        mSelectedThreadNativeTids = nativeTids.clone();
-        if (mIsTracking) {
-            startAggregatingThreadCpuTimes(mSelectedThreadNativeTids, mCpuTimeInStateReader);
-        }
-    }
-
-    /**
-     * Get the CPU frequencies that correspond to the times reported in {@link ProcessCpuUsage}.
+     * Get the CPU frequencies that correspond to the times reported in {@link
+     * ProcessCpuUsage#processCpuTimesMillis} etc.
      */
     public int getCpuFrequencyCount() {
         if (mFrequencyCount == 0) {
-            mFrequencyCount = getCpuFrequencyCount(mCpuTimeInStateReader);
+            mFrequencyCount = mProcTimeInStateReader.getFrequenciesKhz().length;
         }
         return mFrequencyCount;
     }
 
     /**
-     * Get the total CPU usage of the process with the PID specified in the
-     * constructor. The CPU usage time is aggregated across all threads and may
-     * exceed the time the entire process has been running.
+     * Get the total and per-thread CPU usage of the process with the PID specified in the
+     * constructor.
+     *
+     * @param selectedThreadIds a SORTED array of native Thread IDs whose CPU times should
+     *                          be aggregated as a group.  This is expected to be a subset
+     *                          of all thread IDs owned by the process.
      */
     @Nullable
-    public ProcessCpuUsage getProcessCpuUsage() {
+    public ProcessCpuUsage getProcessCpuUsage(int[] selectedThreadIds) {
         if (DEBUG) {
-            Slog.d(TAG, "Reading CPU thread usages for PID " + mPid);
+            Slog.d(TAG, "Reading CPU thread usages with directory " + mProcPath + " process ID "
+                    + mPid);
         }
 
-        ProcessCpuUsage processCpuUsage = new ProcessCpuUsage(getCpuFrequencyCount());
+        int cpuFrequencyCount = getCpuFrequencyCount();
+        ProcessCpuUsage processCpuUsage = new ProcessCpuUsage(cpuFrequencyCount);
 
-        boolean result = readProcessCpuUsage(mPid,
-                processCpuUsage.threadCpuTimesMillis,
-                processCpuUsage.selectedThreadCpuTimesMillis,
-                mCpuTimeInStateReader);
-        if (!result) {
+        if (NATIVE_ENABLED) {
+            boolean result = readProcessCpuUsage(mProcPath.toString(), mPid,
+                    selectedThreadIds, processCpuUsage.processCpuTimesMillis,
+                    processCpuUsage.threadCpuTimesMillis,
+                    processCpuUsage.selectedThreadCpuTimesMillis);
+            if (!result) {
+                return null;
+            }
+            return processCpuUsage;
+        }
+
+        if (!isSorted(selectedThreadIds)) {
+            throw new IllegalArgumentException("selectedThreadIds is not sorted: "
+                    + Arrays.toString(selectedThreadIds));
+        }
+
+        if (!Process.readProcFile(mProcessStatFilePath, PROCESS_FULL_STATS_FORMAT, null,
+                mProcessFullStatsData, null)) {
+            Slog.e(TAG, "Failed to read process stat file " + mProcessStatFilePath);
             return null;
         }
 
-        if (DEBUG) {
-            Slog.d(TAG, "threadCpuTimesMillis = "
-                    + Arrays.toString(processCpuUsage.threadCpuTimesMillis));
-            Slog.d(TAG, "selectedThreadCpuTimesMillis = "
-                    + Arrays.toString(processCpuUsage.selectedThreadCpuTimesMillis));
+        long utime = mProcessFullStatsData[PROCESS_FULL_STAT_UTIME];
+        long stime = mProcessFullStatsData[PROCESS_FULL_STAT_STIME];
+
+        long processCpuTimeMillis = (utime + stime) * mJiffyMillis;
+
+        try (DirectoryStream<Path> threadPaths = Files.newDirectoryStream(mThreadsDirectoryPath)) {
+            for (Path threadDirectory : threadPaths) {
+                readThreadCpuUsage(processCpuUsage, selectedThreadIds, threadDirectory);
+            }
+        } catch (IOException | DirectoryIteratorException e) {
+            // Expected when a process finishes
+            return null;
+        }
+
+        // Estimate per cluster per frequency CPU time for the entire process
+        // by distributing the total process CPU time proportionately to how much
+        // CPU time its threads took on those clusters/frequencies.  This algorithm
+        // works more accurately when when we have equally distributed concurrency.
+        // TODO(b/169279846): obtain actual process CPU times from the kernel
+        long totalCpuTimeAllThreads = 0;
+        for (int i = cpuFrequencyCount - 1; i >= 0; i--) {
+            totalCpuTimeAllThreads += processCpuUsage.threadCpuTimesMillis[i];
+        }
+
+        for (int i = cpuFrequencyCount - 1; i >= 0; i--) {
+            processCpuUsage.processCpuTimesMillis[i] =
+                    processCpuTimeMillis * processCpuUsage.threadCpuTimesMillis[i]
+                            / totalCpuTimeAllThreads;
         }
 
         return processCpuUsage;
     }
 
+    /**
+     * Reads a thread's CPU usage and aggregates the per-cluster per-frequency CPU times.
+     *
+     * @param threadDirectory the {@code /proc} directory of the thread
+     */
+    private void readThreadCpuUsage(ProcessCpuUsage processCpuUsage, int[] selectedThreadIds,
+            Path threadDirectory) {
+        // Get the thread ID from the directory name
+        final int threadId;
+        try {
+            final String directoryName = threadDirectory.getFileName().toString();
+            threadId = Integer.parseInt(directoryName);
+        } catch (NumberFormatException e) {
+            Slog.w(TAG, "Failed to parse thread ID when iterating over /proc/*/task", e);
+            return;
+        }
+
+        // Get the CPU statistics from the directory
+        final Path threadCpuStatPath = threadDirectory.resolve(CPU_STATISTICS_FILENAME);
+        final long[] cpuUsages = mProcTimeInStateReader.getUsageTimesMillis(threadCpuStatPath);
+        if (cpuUsages == null) {
+            return;
+        }
+
+        final int cpuFrequencyCount = getCpuFrequencyCount();
+        final boolean isSelectedThread = Arrays.binarySearch(selectedThreadIds, threadId) >= 0;
+        for (int i = cpuFrequencyCount - 1; i >= 0; i--) {
+            processCpuUsage.threadCpuTimesMillis[i] += cpuUsages[i];
+            if (isSelectedThread) {
+                processCpuUsage.selectedThreadCpuTimesMillis[i] += cpuUsages[i];
+            }
+        }
+    }
+
     /** CPU usage of a process, all of its threads and a selected subset of its threads */
     public static class ProcessCpuUsage {
+        public long[] processCpuTimesMillis;
         public long[] threadCpuTimesMillis;
         public long[] selectedThreadCpuTimesMillis;
 
         public ProcessCpuUsage(int cpuFrequencyCount) {
+            processCpuTimesMillis = new long[cpuFrequencyCount];
             threadCpuTimesMillis = new long[cpuFrequencyCount];
             selectedThreadCpuTimesMillis = new long[cpuFrequencyCount];
         }
     }
 
-    private native int getCpuFrequencyCount(CpuTimeInStateReader reader);
+    private static boolean isSorted(int[] array) {
+        for (int i = 0; i < array.length - 1; i++) {
+            if (array[i] > array[i + 1]) {
+                return false;
+            }
+        }
+        return true;
+    }
 
-    private native boolean startTrackingProcessCpuTimes(int pid, CpuTimeInStateReader reader);
-
-    private native boolean startAggregatingThreadCpuTimes(int[] selectedThreadIds,
-            CpuTimeInStateReader reader);
-
-    private native boolean readProcessCpuUsage(int pid,
-            long[] threadCpuTimesMillis,
-            long[] selectedThreadCpuTimesMillis,
-            CpuTimeInStateReader reader);
+    private native boolean readProcessCpuUsage(String procPath, int pid, int[] selectedThreadIds,
+            long[] processCpuTimesMillis, long[] threadCpuTimesMillis,
+            long[] selectedThreadCpuTimesMillis);
 }
diff --git a/core/java/com/android/internal/os/KernelWakelockReader.java b/core/java/com/android/internal/os/KernelWakelockReader.java
index e595db3..c416814 100644
--- a/core/java/com/android/internal/os/KernelWakelockReader.java
+++ b/core/java/com/android/internal/os/KernelWakelockReader.java
@@ -78,13 +78,16 @@
         boolean useSystemSuspend = (new File(sSysClassWakeupDir)).exists();
 
         if (useSystemSuspend) {
-            // Get both kernel and native wakelock stats from SystemSuspend
-            updateVersion(staleStats);
-            if (getWakelockStatsFromSystemSuspend(staleStats) == null) {
-                Slog.w(TAG, "Failed to get wakelock stats from SystemSuspend");
-                return null;
+            // static read/write lock protection for sKernelWakelockUpdateVersion
+            synchronized (KernelWakelockReader.class) {
+                // Get both kernel and native wakelock stats from SystemSuspend
+                updateVersion(staleStats);
+                if (getWakelockStatsFromSystemSuspend(staleStats) == null) {
+                    Slog.w(TAG, "Failed to get wakelock stats from SystemSuspend");
+                    return null;
+                }
+                return removeOldStats(staleStats);
             }
-            return removeOldStats(staleStats);
         } else {
             Arrays.fill(mKernelWakelockBuffer, (byte) 0);
             int len = 0;
@@ -141,14 +144,17 @@
                 }
             }
 
-            updateVersion(staleStats);
-            // Get native wakelock stats from SystemSuspend
-            if (getWakelockStatsFromSystemSuspend(staleStats) == null) {
-                Slog.w(TAG, "Failed to get Native wakelock stats from SystemSuspend");
+            // static read/write lock protection for sKernelWakelockUpdateVersion
+            synchronized (KernelWakelockReader.class) {
+                updateVersion(staleStats);
+                // Get native wakelock stats from SystemSuspend
+                if (getWakelockStatsFromSystemSuspend(staleStats) == null) {
+                    Slog.w(TAG, "Failed to get Native wakelock stats from SystemSuspend");
+                }
+                // Get kernel wakelock stats
+                parseProcWakelocks(mKernelWakelockBuffer, len, wakeup_sources, staleStats);
+                return removeOldStats(staleStats);
             }
-            // Get kernel wakelock stats
-            parseProcWakelocks(mKernelWakelockBuffer, len, wakeup_sources, staleStats);
-            return removeOldStats(staleStats);
         }
     }
 
diff --git a/core/java/com/android/internal/os/SystemServerCpuThreadReader.java b/core/java/com/android/internal/os/SystemServerCpuThreadReader.java
index fbad75e..fbbee94 100644
--- a/core/java/com/android/internal/os/SystemServerCpuThreadReader.java
+++ b/core/java/com/android/internal/os/SystemServerCpuThreadReader.java
@@ -22,6 +22,8 @@
 import com.android.internal.annotations.VisibleForTesting;
 
 import java.io.IOException;
+import java.nio.file.Path;
+import java.util.Arrays;
 
 /**
  * Reads /proc/UID/task/TID/time_in_state files to obtain statistics on CPU usage
@@ -29,7 +31,9 @@
  */
 public class SystemServerCpuThreadReader {
     private final KernelSingleProcessCpuThreadReader mKernelCpuThreadReader;
+    private int[] mBinderThreadNativeTids = new int[0];  // Sorted
 
+    private long[] mLastProcessCpuTimeUs;
     private long[] mLastThreadCpuTimesUs;
     private long[] mLastBinderThreadCpuTimesUs;
 
@@ -37,6 +41,8 @@
      * Times (in microseconds) spent by the system server UID.
      */
     public static class SystemServiceCpuThreadTimes {
+        // The entire process
+        public long[] processCpuTimesUs;
         // All threads
         public long[] threadCpuTimesUs;
         // Just the threads handling incoming binder calls
@@ -55,10 +61,8 @@
     }
 
     @VisibleForTesting
-    public SystemServerCpuThreadReader(int pid,
-            KernelSingleProcessCpuThreadReader.CpuTimeInStateReader cpuTimeInStateReader)
-            throws IOException {
-        this(new KernelSingleProcessCpuThreadReader(pid, cpuTimeInStateReader));
+    public SystemServerCpuThreadReader(Path procPath, int pid) throws IOException {
+        this(new KernelSingleProcessCpuThreadReader(pid, procPath));
     }
 
     @VisibleForTesting
@@ -66,15 +70,9 @@
         mKernelCpuThreadReader = kernelCpuThreadReader;
     }
 
-    /**
-     * Start tracking CPU time-in-state for the process specified in the constructor.
-     */
-    public void startTrackingThreadCpuTime() {
-        mKernelCpuThreadReader.startTrackingThreadCpuTimes();
-    }
-
     public void setBinderThreadNativeTids(int[] nativeTids) {
-        mKernelCpuThreadReader.setSelectedThreadIds(nativeTids);
+        mBinderThreadNativeTids = nativeTids.clone();
+        Arrays.sort(mBinderThreadNativeTids);
     }
 
     /**
@@ -83,27 +81,33 @@
     @Nullable
     public SystemServiceCpuThreadTimes readDelta() {
         final int numCpuFrequencies = mKernelCpuThreadReader.getCpuFrequencyCount();
-        if (mLastThreadCpuTimesUs == null) {
+        if (mLastProcessCpuTimeUs == null) {
+            mLastProcessCpuTimeUs = new long[numCpuFrequencies];
             mLastThreadCpuTimesUs = new long[numCpuFrequencies];
             mLastBinderThreadCpuTimesUs = new long[numCpuFrequencies];
 
+            mDeltaCpuThreadTimes.processCpuTimesUs = new long[numCpuFrequencies];
             mDeltaCpuThreadTimes.threadCpuTimesUs = new long[numCpuFrequencies];
             mDeltaCpuThreadTimes.binderThreadCpuTimesUs = new long[numCpuFrequencies];
         }
 
         final KernelSingleProcessCpuThreadReader.ProcessCpuUsage processCpuUsage =
-                mKernelCpuThreadReader.getProcessCpuUsage();
+                mKernelCpuThreadReader.getProcessCpuUsage(mBinderThreadNativeTids);
         if (processCpuUsage == null) {
             return null;
         }
 
         for (int i = numCpuFrequencies - 1; i >= 0; i--) {
+            long processCpuTimesUs = processCpuUsage.processCpuTimesMillis[i] * 1000;
             long threadCpuTimesUs = processCpuUsage.threadCpuTimesMillis[i] * 1000;
             long binderThreadCpuTimesUs = processCpuUsage.selectedThreadCpuTimesMillis[i] * 1000;
+            mDeltaCpuThreadTimes.processCpuTimesUs[i] =
+                    Math.max(0, processCpuTimesUs - mLastProcessCpuTimeUs[i]);
             mDeltaCpuThreadTimes.threadCpuTimesUs[i] =
                     Math.max(0, threadCpuTimesUs - mLastThreadCpuTimesUs[i]);
             mDeltaCpuThreadTimes.binderThreadCpuTimesUs[i] =
                     Math.max(0, binderThreadCpuTimesUs - mLastBinderThreadCpuTimesUs[i]);
+            mLastProcessCpuTimeUs[i] = processCpuTimesUs;
             mLastThreadCpuTimesUs[i] = threadCpuTimesUs;
             mLastBinderThreadCpuTimesUs[i] = binderThreadCpuTimesUs;
         }
diff --git a/core/java/com/android/internal/os/Zygote.java b/core/java/com/android/internal/os/Zygote.java
index 5e20cd0..fda87be 100644
--- a/core/java/com/android/internal/os/Zygote.java
+++ b/core/java/com/android/internal/os/Zygote.java
@@ -24,7 +24,6 @@
 import android.net.Credentials;
 import android.net.LocalServerSocket;
 import android.net.LocalSocket;
-import android.net.NetworkUtils;
 import android.os.FactoryTest;
 import android.os.IVold;
 import android.os.Process;
@@ -35,6 +34,8 @@
 import android.system.Os;
 import android.util.Log;
 
+import com.android.internal.net.NetworkUtilsInternal;
+
 import dalvik.annotation.optimization.FastNative;
 import dalvik.system.ZygoteHooks;
 
@@ -340,7 +341,7 @@
 
             // If no GIDs were specified, don't make any permissions changes based on groups.
             if (gids != null && gids.length > 0) {
-                NetworkUtils.setAllowNetworkingForProcess(containsInetGid(gids));
+                NetworkUtilsInternal.setAllowNetworkingForProcess(containsInetGid(gids));
             }
         }
 
diff --git a/core/java/com/android/internal/util/BinaryXmlPullParser.java b/core/java/com/android/internal/util/BinaryXmlPullParser.java
index 68921ad..57552f3 100644
--- a/core/java/com/android/internal/util/BinaryXmlPullParser.java
+++ b/core/java/com/android/internal/util/BinaryXmlPullParser.java
@@ -95,8 +95,8 @@
     private Attribute[] mAttributes;
 
     @Override
-    public void setInput(InputStream is, String inputEncoding) throws XmlPullParserException {
-        if (inputEncoding != null && !StandardCharsets.UTF_8.name().equals(inputEncoding)) {
+    public void setInput(InputStream is, String encoding) throws XmlPullParserException {
+        if (encoding != null && !StandardCharsets.UTF_8.name().equalsIgnoreCase(encoding)) {
             throw new UnsupportedOperationException();
         }
 
@@ -262,19 +262,27 @@
                 break;
             }
             case XmlPullParser.START_DOCUMENT: {
+                mCurrentName = null;
+                mCurrentText = null;
+                if (mAttributeCount > 0) resetAttributes();
                 break;
             }
             case XmlPullParser.END_DOCUMENT: {
+                mCurrentName = null;
+                mCurrentText = null;
+                if (mAttributeCount > 0) resetAttributes();
                 break;
             }
             case XmlPullParser.START_TAG: {
                 mCurrentName = mIn.readInternedUTF();
-                resetAttributes();
+                mCurrentText = null;
+                if (mAttributeCount > 0) resetAttributes();
                 break;
             }
             case XmlPullParser.END_TAG: {
                 mCurrentName = mIn.readInternedUTF();
-                resetAttributes();
+                mCurrentText = null;
+                if (mAttributeCount > 0) resetAttributes();
                 break;
             }
             case XmlPullParser.TEXT:
@@ -283,12 +291,15 @@
             case XmlPullParser.COMMENT:
             case XmlPullParser.DOCDECL:
             case XmlPullParser.IGNORABLE_WHITESPACE: {
+                mCurrentName = null;
                 mCurrentText = mIn.readUTF();
+                if (mAttributeCount > 0) resetAttributes();
                 break;
             }
             case XmlPullParser.ENTITY_REF: {
                 mCurrentName = mIn.readUTF();
                 mCurrentText = resolveEntity(mCurrentName);
+                if (mAttributeCount > 0) resetAttributes();
                 break;
             }
             default: {
@@ -428,7 +439,11 @@
     @Override
     public String getAttributeValue(String namespace, String name) {
         final int index = getAttributeIndex(namespace, name);
-        return mAttributes[index].getValueString();
+        if (index != -1) {
+            return mAttributes[index].getValueString();
+        } else {
+            return null;
+        }
     }
 
     @Override
diff --git a/core/java/com/android/internal/util/BinaryXmlSerializer.java b/core/java/com/android/internal/util/BinaryXmlSerializer.java
index bc3b1f8..9df4bdb 100644
--- a/core/java/com/android/internal/util/BinaryXmlSerializer.java
+++ b/core/java/com/android/internal/util/BinaryXmlSerializer.java
@@ -120,7 +120,7 @@
 
     @Override
     public void setOutput(@NonNull OutputStream os, @Nullable String encoding) throws IOException {
-        if (encoding != null && !StandardCharsets.UTF_8.name().equals(encoding)) {
+        if (encoding != null && !StandardCharsets.UTF_8.name().equalsIgnoreCase(encoding)) {
             throw new UnsupportedOperationException();
         }
 
@@ -144,7 +144,10 @@
     @Override
     public void startDocument(@Nullable String encoding, @Nullable Boolean standalone)
             throws IOException {
-        if (encoding != null && !StandardCharsets.UTF_8.name().equals(encoding)) {
+        if (encoding != null && !StandardCharsets.UTF_8.name().equalsIgnoreCase(encoding)) {
+            throw new UnsupportedOperationException();
+        }
+        if (standalone != null && !standalone) {
             throw new UnsupportedOperationException();
         }
         mOut.writeByte(START_DOCUMENT | TYPE_NULL);
diff --git a/core/java/com/android/internal/util/OWNERS b/core/java/com/android/internal/util/OWNERS
index 8b9acd3..a045451 100644
--- a/core/java/com/android/internal/util/OWNERS
+++ b/core/java/com/android/internal/util/OWNERS
@@ -2,3 +2,4 @@
 per-file MessageUtils*, Protocol*, RingBuffer*, TokenBucket* = jchalard@google.com, lorenzo@google.com, satk@google.com
 per-file Protocol* = etancohen@google.com, lorenzo@google.com
 per-file State* = jchalard@google.com, lorenzo@google.com, satk@google.com
+per-file DataClass* = eugenesusla@google.com
\ No newline at end of file
diff --git a/core/java/com/android/internal/util/XmlSerializerWrapper.java b/core/java/com/android/internal/util/XmlSerializerWrapper.java
index 2131db0..9f28d90a 100644
--- a/core/java/com/android/internal/util/XmlSerializerWrapper.java
+++ b/core/java/com/android/internal/util/XmlSerializerWrapper.java
@@ -28,7 +28,7 @@
 /**
  * Wrapper which delegates all calls through to the given {@link XmlSerializer}.
  */
-public class XmlSerializerWrapper {
+public class XmlSerializerWrapper implements XmlSerializer {
     private final XmlSerializer mWrapped;
 
     public XmlSerializerWrapper(@NonNull XmlSerializer wrapped) {
diff --git a/core/java/com/android/internal/view/BaseIWindow.java b/core/java/com/android/internal/view/BaseIWindow.java
index 8962dc3..ef2275d 100644
--- a/core/java/com/android/internal/view/BaseIWindow.java
+++ b/core/java/com/android/internal/view/BaseIWindow.java
@@ -158,10 +158,6 @@
     }
 
     @Override
-    public void dispatchPointerCaptureChanged(boolean hasCapture) {
-    }
-
-    @Override
     public void requestScrollCapture(IScrollCaptureCallbacks callbacks) {
         try {
             callbacks.onUnavailable();
diff --git a/core/java/com/android/internal/view/IInputMethodManager.aidl b/core/java/com/android/internal/view/IInputMethodManager.aidl
index 455e489..1fadfc5 100644
--- a/core/java/com/android/internal/view/IInputMethodManager.aidl
+++ b/core/java/com/android/internal/view/IInputMethodManager.aidl
@@ -26,6 +26,10 @@
 import com.android.internal.view.IInputMethodClient;
 import com.android.internal.inputmethod.IBooleanResultCallback;
 import com.android.internal.inputmethod.IInputBindResultResultCallback;
+import com.android.internal.inputmethod.IInputMethodInfoListResultCallback;
+import com.android.internal.inputmethod.IInputMethodSubtypeResultCallback;
+import com.android.internal.inputmethod.IInputMethodSubtypeListResultCallback;
+import com.android.internal.inputmethod.IIntResultCallback;
 
 /**
  * Public interface to the global input method manager, used by all client
@@ -36,12 +40,13 @@
             int untrustedDisplayId);
 
     // TODO: Use ParceledListSlice instead
-    List<InputMethodInfo> getInputMethodList(int userId);
+    void getInputMethodList(int userId, in IInputMethodInfoListResultCallback resultCallback);
     // TODO: Use ParceledListSlice instead
-    List<InputMethodInfo> getEnabledInputMethodList(int userId);
-    List<InputMethodSubtype> getEnabledInputMethodSubtypeList(in String imiId,
-            boolean allowsImplicitlySelectedSubtypes);
-    InputMethodSubtype getLastInputMethodSubtype();
+    void getEnabledInputMethodList(int userId,
+            in IInputMethodInfoListResultCallback resultCallback);
+    void getEnabledInputMethodSubtypeList(in String imiId, boolean allowsImplicitlySelectedSubtypes,
+            in IInputMethodSubtypeListResultCallback resultCallback);
+    void getLastInputMethodSubtype(in IInputMethodSubtypeResultCallback resultCallback);
 
     void showSoftInput(in IInputMethodClient client, IBinder windowToken, int flags,
             in ResultReceiver resultReceiver, in IBooleanResultCallback resultCallback);
@@ -66,11 +71,11 @@
             int displayId);
     void showInputMethodAndSubtypeEnablerFromClient(in IInputMethodClient client, String topId);
     void isInputMethodPickerShownForTest(in IBooleanResultCallback resultCallback);
-    InputMethodSubtype getCurrentInputMethodSubtype();
+    void getCurrentInputMethodSubtype(in IInputMethodSubtypeResultCallback resultCallback);
     void setAdditionalInputMethodSubtypes(String id, in InputMethodSubtype[] subtypes);
     // This is kept due to @UnsupportedAppUsage.
     // TODO(Bug 113914148): Consider removing this.
-    int getInputMethodWindowVisibleHeight();
+    void getInputMethodWindowVisibleHeight(IIntResultCallback resultCallback);
 
     void reportActivityView(in IInputMethodClient parentClient, int childDisplayId,
             in float[] matrixValues);
diff --git a/core/java/com/android/server/net/BaseNetworkObserver.java b/core/java/com/android/server/net/BaseNetworkObserver.java
index 2a9c0b4..0e8d61a 100644
--- a/core/java/com/android/server/net/BaseNetworkObserver.java
+++ b/core/java/com/android/server/net/BaseNetworkObserver.java
@@ -64,7 +64,8 @@
     }
 
     @Override
-    public void interfaceClassDataActivityChanged(String label, boolean active, long tsNanos) {
+    public void interfaceClassDataActivityChanged(String label, boolean active, long tsNanos,
+            int uid) {
         // default no-op
     }
 
diff --git a/core/jni/Android.bp b/core/jni/Android.bp
index 8c83d7c..c05e7a2 100644
--- a/core/jni/Android.bp
+++ b/core/jni/Android.bp
@@ -181,6 +181,7 @@
                 "android_content_res_Configuration.cpp",
                 "android_security_Scrypt.cpp",
                 "com_android_internal_content_om_OverlayConfig.cpp",
+                "com_android_internal_net_NetworkUtilsInternal.cpp",
                 "com_android_internal_os_ClassLoaderFactory.cpp",
                 "com_android_internal_os_FuseAppLoop.cpp",
                 "com_android_internal_os_KernelCpuUidBpfMapReader.cpp",
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index 14e74a8..cefa88c 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -187,6 +187,7 @@
 extern int register_android_security_Scrypt(JNIEnv *env);
 extern int register_com_android_internal_content_NativeLibraryHelper(JNIEnv *env);
 extern int register_com_android_internal_content_om_OverlayConfig(JNIEnv *env);
+extern int register_com_android_internal_net_NetworkUtilsInternal(JNIEnv* env);
 extern int register_com_android_internal_os_ClassLoaderFactory(JNIEnv* env);
 extern int register_com_android_internal_os_FuseAppLoop(JNIEnv* env);
 extern int register_com_android_internal_os_KernelCpuUidBpfMapReader(JNIEnv *env);
@@ -1522,6 +1523,7 @@
         REG_JNI(register_android_os_SharedMemory),
         REG_JNI(register_android_os_incremental_IncrementalManager),
         REG_JNI(register_com_android_internal_content_om_OverlayConfig),
+        REG_JNI(register_com_android_internal_net_NetworkUtilsInternal),
         REG_JNI(register_com_android_internal_os_ClassLoaderFactory),
         REG_JNI(register_com_android_internal_os_Zygote),
         REG_JNI(register_com_android_internal_os_ZygoteInit),
diff --git a/core/jni/android_content_res_ApkAssets.cpp b/core/jni/android_content_res_ApkAssets.cpp
index 444bb66..66753e4 100644
--- a/core/jni/android_content_res_ApkAssets.cpp
+++ b/core/jni/android_content_res_ApkAssets.cpp
@@ -315,10 +315,14 @@
   return reinterpret_cast<jlong>(apk_assets.release());
 }
 
-static void NativeDestroy(JNIEnv* /*env*/, jclass /*clazz*/, jlong ptr) {
+static void NativeDestroy(void* ptr) {
   delete reinterpret_cast<ApkAssets*>(ptr);
 }
 
+static jlong NativeGetFinalizer(JNIEnv* /*env*/, jclass /*clazz*/) {
+  return reinterpret_cast<jlong>(&NativeDestroy);
+}
+
 static jstring NativeGetAssetPath(JNIEnv* env, jclass /*clazz*/, jlong ptr) {
   const ApkAssets* apk_assets = reinterpret_cast<const ApkAssets*>(ptr);
   return env->NewStringUTF(apk_assets->GetPath().c_str());
@@ -427,7 +431,7 @@
     {"nativeLoadFdOffsets",
      "(ILjava/io/FileDescriptor;Ljava/lang/String;JJILandroid/content/res/loader/AssetsProvider;)J",
      (void*)NativeLoadFromFdOffset},
-    {"nativeDestroy", "(J)V", (void*)NativeDestroy},
+    {"nativeGetFinalizer", "()J", (void*)NativeGetFinalizer},
     {"nativeGetAssetPath", "(J)Ljava/lang/String;", (void*)NativeGetAssetPath},
     {"nativeGetStringBlock", "(J)J", (void*)NativeGetStringBlock},
     {"nativeIsUpToDate", "(J)Z", (void*)NativeIsUpToDate},
diff --git a/core/jni/android_media_AudioSystem.cpp b/core/jni/android_media_AudioSystem.cpp
index a95ee4f..5cffbef 100644
--- a/core/jni/android_media_AudioSystem.cpp
+++ b/core/jni/android_media_AudioSystem.cpp
@@ -298,20 +298,25 @@
     return old;
 }
 
-#define check_AudioSystem_Command(status) _check_AudioSystem_Command(__func__, (status))
+#define check_AudioSystem_Command(...) _check_AudioSystem_Command(__func__, __VA_ARGS__)
 
-static int _check_AudioSystem_Command(const char* caller, status_t status)
-{
-    ALOGE_IF(status, "Command failed for %s: %d", caller, status);
+static int _check_AudioSystem_Command(const char *caller, status_t status,
+                                      std::vector<status_t> ignoredErrors = {}) {
+    int jniStatus = kAudioStatusOk;
     switch (status) {
     case DEAD_OBJECT:
-        return kAudioStatusMediaServerDied;
+        jniStatus = kAudioStatusMediaServerDied;
+        break;
     case NO_ERROR:
-        return kAudioStatusOk;
+        break;
     default:
+        if (std::find(begin(ignoredErrors), end(ignoredErrors), status) == end(ignoredErrors)) {
+            jniStatus = kAudioStatusError;
+        }
         break;
     }
-    return kAudioStatusError;
+    ALOGE_IF(jniStatus != kAudioStatusOk, "Command failed for %s: %d", caller, status);
+    return jniStatus;
 }
 
 static jint getVectorOfAudioDeviceTypeAddr(JNIEnv *env, jintArray deviceTypes,
@@ -2350,9 +2355,12 @@
 
 static jint android_media_AudioSystem_removeDevicesRoleForStrategy(JNIEnv *env, jobject thiz,
                                                                    jint strategy, jint role) {
-    return (jint)check_AudioSystem_Command(
-            AudioSystem::removeDevicesRoleForStrategy((product_strategy_t)strategy,
-                                                      (device_role_t)role));
+    return (jint)
+            check_AudioSystem_Command(AudioSystem::removeDevicesRoleForStrategy((product_strategy_t)
+                                                                                        strategy,
+                                                                                (device_role_t)
+                                                                                        role),
+                                      {NAME_NOT_FOUND});
 }
 
 static jint android_media_AudioSystem_getDevicesForRoleAndStrategy(JNIEnv *env, jobject thiz,
diff --git a/core/jni/android_net_NetUtils.cpp b/core/jni/android_net_NetUtils.cpp
index 8d4c4e5..2155246 100644
--- a/core/jni/android_net_NetUtils.cpp
+++ b/core/jni/android_net_NetUtils.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright 2008, The Android Open Source Project
+ * Copyright 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.
@@ -28,7 +28,6 @@
 #include <netinet/udp.h>
 
 #include <DnsProxydProtocol.h> // NETID_USE_LOCAL_NAMESERVERS
-#include <android_runtime/AndroidRuntime.h>
 #include <cutils/properties.h>
 #include <nativehelper/JNIPlatformHelp.h>
 #include <nativehelper/ScopedLocalRef.h>
@@ -226,11 +225,6 @@
             class_Network, ctor, dnsNetId & ~NETID_USE_LOCAL_NAMESERVERS, privateDnsBypass);
 }
 
-static void android_net_utils_setAllowNetworkingForProcess(JNIEnv *env, jobject thiz,
-                                                           jboolean hasConnectivity) {
-    setAllowNetworkingForProcess(hasConnectivity == JNI_TRUE);
-}
-
 static jobject android_net_utils_getTcpRepairWindow(JNIEnv *env, jobject thiz, jobject javaFd) {
     if (javaFd == NULL) {
         jniThrowNullPointerException(env, NULL);
@@ -288,7 +282,6 @@
     { "resNetworkResult", "(Ljava/io/FileDescriptor;)Landroid/net/DnsResolver$DnsResponse;", (void*) android_net_utils_resNetworkResult },
     { "resNetworkCancel", "(Ljava/io/FileDescriptor;)V", (void*) android_net_utils_resNetworkCancel },
     { "getDnsNetwork", "()Landroid/net/Network;", (void*) android_net_utils_getDnsNetwork },
-    { "setAllowNetworkingForProcess", "(Z)V", (void *)android_net_utils_setAllowNetworkingForProcess },
 };
 // clang-format on
 
diff --git a/core/jni/android_os_Debug.cpp b/core/jni/android_os_Debug.cpp
index bf79a44..bb51c57 100644
--- a/core/jni/android_os_Debug.cpp
+++ b/core/jni/android_os_Debug.cpp
@@ -847,6 +847,17 @@
     return ionPss;
 }
 
+static jlong android_os_Debug_getGpuTotalUsageKb(JNIEnv* env, jobject clazz) {
+    jlong sizeKb = -1;
+    uint64_t size;
+
+    if (meminfo::ReadGpuTotalUsageKb(&size)) {
+        sizeKb = size;
+    }
+
+    return sizeKb;
+}
+
 static jboolean android_os_Debug_isVmapStack(JNIEnv *env, jobject clazz)
 {
     static enum {
@@ -915,6 +926,8 @@
             (void*)android_os_Debug_getIonPoolsSizeKb },
     { "getIonMappedSizeKb", "()J",
             (void*)android_os_Debug_getIonMappedSizeKb },
+    { "getGpuTotalUsageKb", "()J",
+            (void*)android_os_Debug_getGpuTotalUsageKb },
     { "isVmapStack", "()Z",
             (void*)android_os_Debug_isVmapStack },
 };
diff --git a/core/jni/android_view_InputDevice.cpp b/core/jni/android_view_InputDevice.cpp
index 9f4e3e5..4eaa016 100644
--- a/core/jni/android_view_InputDevice.cpp
+++ b/core/jni/android_view_InputDevice.cpp
@@ -60,13 +60,17 @@
     // Not sure why, but JNI is complaining when I pass this through directly.
     jboolean hasMic = deviceInfo.hasMic() ? JNI_TRUE : JNI_FALSE;
 
-    ScopedLocalRef<jobject> inputDeviceObj(env, env->NewObject(gInputDeviceClassInfo.clazz,
-                gInputDeviceClassInfo.ctor, deviceInfo.getId(), deviceInfo.getGeneration(),
-                deviceInfo.getControllerNumber(), nameObj.get(),
-                static_cast<int32_t>(ident.vendor), static_cast<int32_t>(ident.product),
-                descriptorObj.get(), deviceInfo.isExternal(), deviceInfo.getSources(),
-                deviceInfo.getKeyboardType(), kcmObj.get(), deviceInfo.hasVibrator(),
-                hasMic, deviceInfo.hasButtonUnderPad()));
+    ScopedLocalRef<jobject>
+            inputDeviceObj(env,
+                           env->NewObject(gInputDeviceClassInfo.clazz, gInputDeviceClassInfo.ctor,
+                                          deviceInfo.getId(), deviceInfo.getGeneration(),
+                                          deviceInfo.getControllerNumber(), nameObj.get(),
+                                          static_cast<int32_t>(ident.vendor),
+                                          static_cast<int32_t>(ident.product), descriptorObj.get(),
+                                          deviceInfo.isExternal(), deviceInfo.getSources(),
+                                          deviceInfo.getKeyboardType(), kcmObj.get(),
+                                          deviceInfo.hasVibrator(), hasMic,
+                                          deviceInfo.hasButtonUnderPad(), deviceInfo.hasSensor()));
 
     const std::vector<InputDeviceInfo::MotionRange>& ranges = deviceInfo.getMotionRanges();
     for (const InputDeviceInfo::MotionRange& range: ranges) {
@@ -87,7 +91,8 @@
     gInputDeviceClassInfo.clazz = MakeGlobalRefOrDie(env, gInputDeviceClassInfo.clazz);
 
     gInputDeviceClassInfo.ctor = GetMethodIDOrDie(env, gInputDeviceClassInfo.clazz, "<init>",
-            "(IIILjava/lang/String;IILjava/lang/String;ZIILandroid/view/KeyCharacterMap;ZZZ)V");
+                                                  "(IIILjava/lang/String;IILjava/lang/"
+                                                  "String;ZIILandroid/view/KeyCharacterMap;ZZZZ)V");
 
     gInputDeviceClassInfo.addMotionRange = GetMethodIDOrDie(env, gInputDeviceClassInfo.clazz,
             "addMotionRange", "(IIFFFFF)V");
diff --git a/core/jni/com_android_internal_net_NetworkUtilsInternal.cpp b/core/jni/com_android_internal_net_NetworkUtilsInternal.cpp
new file mode 100644
index 0000000..10fc18d
--- /dev/null
+++ b/core/jni/com_android_internal_net_NetworkUtilsInternal.cpp
@@ -0,0 +1,37 @@
+/*
+ * Copyright 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.
+ */
+
+#include "NetdClient.h"
+#include "core_jni_helpers.h"
+#include "jni.h"
+
+namespace android {
+static void android_net_utils_setAllowNetworkingForProcess(JNIEnv *env, jobject thiz,
+                                                           jboolean hasConnectivity) {
+    setAllowNetworkingForProcess(hasConnectivity == JNI_TRUE);
+}
+
+static const JNINativeMethod gNetworkUtilMethods[] = {
+        {"setAllowNetworkingForProcess", "(Z)V",
+         (void *)android_net_utils_setAllowNetworkingForProcess},
+};
+
+int register_com_android_internal_net_NetworkUtilsInternal(JNIEnv *env) {
+    return RegisterMethodsOrDie(env, "com/android/internal/net/NetworkUtilsInternal",
+                                gNetworkUtilMethods, NELEM(gNetworkUtilMethods));
+}
+
+} // namespace android
diff --git a/core/jni/com_android_internal_os_KernelSingleProcessCpuThreadReader.cpp b/core/jni/com_android_internal_os_KernelSingleProcessCpuThreadReader.cpp
index dfae684..52bed6b 100644
--- a/core/jni/com_android_internal_os_KernelSingleProcessCpuThreadReader.cpp
+++ b/core/jni/com_android_internal_os_KernelSingleProcessCpuThreadReader.cpp
@@ -26,230 +26,239 @@
 #include <android_runtime/Log.h>
 
 #include <nativehelper/ScopedPrimitiveArray.h>
+#include <nativehelper/ScopedUtfChars.h>
 
 namespace android {
 
-static constexpr uint16_t DEFAULT_THREAD_AGGREGATION_KEY = 0;
-static constexpr uint16_t SELECTED_THREAD_AGGREGATION_KEY = 1;
-
-static constexpr uint64_t NSEC_PER_MSEC = 1000000;
-
 // Number of milliseconds in a jiffy - the unit of time measurement for processes and threads
 static const uint32_t gJiffyMillis = (uint32_t)(1000 / sysconf(_SC_CLK_TCK));
 
-// Abstract class for readers of CPU time-in-state. There are two implementations of
-// this class: BpfCpuTimeInStateReader and MockCpuTimeInStateReader.  The former is used
-// by the production code. The latter is used by unit tests to provide mock
-// CPU time-in-state data via a Java implementation.
-class ICpuTimeInStateReader {
-public:
-    virtual ~ICpuTimeInStateReader() {}
+// Given a PID, returns a vector of all TIDs for the process' tasks. Thread IDs are
+// file names in the /proc/<pid>/task directory.
+static bool getThreadIds(const std::string &procPath, const pid_t pid,
+                         std::vector<pid_t> &outThreadIds) {
+    std::string taskPath = android::base::StringPrintf("%s/%u/task", procPath.c_str(), pid);
 
-    // Returns the overall number of cluser-frequency combinations
-    virtual size_t getCpuFrequencyCount();
+    struct dirent **dirlist;
+    int threadCount = scandir(taskPath.c_str(), &dirlist, NULL, NULL);
+    if (threadCount == -1) {
+        ALOGE("Cannot read directory %s", taskPath.c_str());
+        return false;
+    }
 
-    // Marks the CPU time-in-state tracking for threads of the specified TGID
-    virtual bool startTrackingProcessCpuTimes(pid_t) = 0;
+    outThreadIds.reserve(threadCount);
 
-    // Marks the thread specified by its PID for CPU time-in-state tracking.
-    virtual bool startAggregatingTaskCpuTimes(pid_t, uint16_t) = 0;
+    for (int i = 0; i < threadCount; i++) {
+        pid_t tid;
+        if (android::base::ParseInt<pid_t>(dirlist[i]->d_name, &tid)) {
+            outThreadIds.push_back(tid);
+        }
+        free(dirlist[i]);
+    }
+    free(dirlist);
 
-    // Retrieves the accumulated time-in-state data, which is organized as a map
-    // from aggregation keys to vectors of vectors using the format:
-    // { aggKey0 -> [[t0_0_0, t0_0_1, ...], [t0_1_0, t0_1_1, ...], ...],
-    //   aggKey1 -> [[t1_0_0, t1_0_1, ...], [t1_1_0, t1_1_1, ...], ...], ... }
-    // where ti_j_k is the ns tid i spent running on the jth cluster at the cluster's kth lowest
-    // freq.
-    virtual std::optional<std::unordered_map<uint16_t, std::vector<std::vector<uint64_t>>>>
-    getAggregatedTaskCpuFreqTimes(pid_t, const std::vector<uint16_t> &);
-};
+    return true;
+}
 
-// ICpuTimeInStateReader that uses eBPF to provide a map of aggregated CPU time-in-state values.
-// See cputtimeinstate.h/.cpp
-class BpfCpuTimeInStateReader : public ICpuTimeInStateReader {
-public:
-    size_t getCpuFrequencyCount() {
-        std::optional<std::vector<std::vector<uint32_t>>> cpuFreqs = android::bpf::getCpuFreqs();
-        if (!cpuFreqs) {
-            ALOGE("Cannot obtain CPU frequency count");
-            return 0;
+// Reads contents of a time_in_state file and returns times as a vector of times per frequency
+// A time_in_state file contains pairs of frequency - time (in jiffies):
+//
+//    cpu0
+//    300000 30
+//    403200 0
+//    cpu4
+//    710400 10
+//    825600 20
+//    940800 30
+//
+static bool getThreadTimeInState(const std::string &procPath, const pid_t pid, const pid_t tid,
+                                 const size_t frequencyCount,
+                                 std::vector<uint64_t> &outThreadTimeInState) {
+    std::string timeInStateFilePath =
+            android::base::StringPrintf("%s/%u/task/%u/time_in_state", procPath.c_str(), pid, tid);
+    std::string data;
+
+    if (!android::base::ReadFileToString(timeInStateFilePath, &data)) {
+        ALOGE("Cannot read file: %s", timeInStateFilePath.c_str());
+        return false;
+    }
+
+    auto lines = android::base::Split(data, "\n");
+    size_t index = 0;
+    for (const auto &line : lines) {
+        if (line.empty()) {
+            continue;
         }
 
-        size_t freqCount = 0;
-        for (auto cluster : *cpuFreqs) {
-            freqCount += cluster.size();
+        auto numbers = android::base::Split(line, " ");
+        if (numbers.size() != 2) {
+            continue;
         }
-
-        return freqCount;
-    }
-
-    bool startTrackingProcessCpuTimes(pid_t tgid) {
-        return android::bpf::startTrackingProcessCpuTimes(tgid);
-    }
-
-    bool startAggregatingTaskCpuTimes(pid_t pid, uint16_t aggregationKey) {
-        return android::bpf::startAggregatingTaskCpuTimes(pid, aggregationKey);
-    }
-
-    std::optional<std::unordered_map<uint16_t, std::vector<std::vector<uint64_t>>>>
-    getAggregatedTaskCpuFreqTimes(pid_t pid, const std::vector<uint16_t> &aggregationKeys) {
-        return android::bpf::getAggregatedTaskCpuFreqTimes(pid, aggregationKeys);
-    }
-};
-
-// ICpuTimeInStateReader that uses JNI to provide a map of aggregated CPU time-in-state
-// values.
-// This version of CpuTimeInStateReader is used exclusively for providing mock data in tests.
-class MockCpuTimeInStateReader : public ICpuTimeInStateReader {
-private:
-    JNIEnv *mEnv;
-    jobject mCpuTimeInStateReader;
-
-public:
-    MockCpuTimeInStateReader(JNIEnv *env, jobject cpuTimeInStateReader)
-          : mEnv(env), mCpuTimeInStateReader(cpuTimeInStateReader) {}
-
-    size_t getCpuFrequencyCount();
-
-    bool startTrackingProcessCpuTimes(pid_t tgid);
-
-    bool startAggregatingTaskCpuTimes(pid_t pid, uint16_t aggregationKey);
-
-    std::optional<std::unordered_map<uint16_t, std::vector<std::vector<uint64_t>>>>
-    getAggregatedTaskCpuFreqTimes(pid_t tgid, const std::vector<uint16_t> &aggregationKeys);
-};
-
-static ICpuTimeInStateReader *getCpuTimeInStateReader(JNIEnv *env,
-                                                      jobject cpuTimeInStateReaderObject) {
-    if (cpuTimeInStateReaderObject) {
-        return new MockCpuTimeInStateReader(env, cpuTimeInStateReaderObject);
-    } else {
-        return new BpfCpuTimeInStateReader();
-    }
-}
-
-static jint getCpuFrequencyCount(JNIEnv *env, jclass, jobject cpuTimeInStateReaderObject) {
-    std::unique_ptr<ICpuTimeInStateReader> cpuTimeInStateReader(
-            getCpuTimeInStateReader(env, cpuTimeInStateReaderObject));
-    return cpuTimeInStateReader->getCpuFrequencyCount();
-}
-
-static jboolean startTrackingProcessCpuTimes(JNIEnv *env, jclass, jint tgid,
-                                             jobject cpuTimeInStateReaderObject) {
-    std::unique_ptr<ICpuTimeInStateReader> cpuTimeInStateReader(
-            getCpuTimeInStateReader(env, cpuTimeInStateReaderObject));
-    return cpuTimeInStateReader->startTrackingProcessCpuTimes(tgid);
-}
-
-static jboolean startAggregatingThreadCpuTimes(JNIEnv *env, jclass, jintArray selectedThreadIdArray,
-                                               jobject cpuTimeInStateReaderObject) {
-    ScopedIntArrayRO selectedThreadIds(env, selectedThreadIdArray);
-    std::unique_ptr<ICpuTimeInStateReader> cpuTimeInStateReader(
-            getCpuTimeInStateReader(env, cpuTimeInStateReaderObject));
-
-    for (int i = 0; i < selectedThreadIds.size(); i++) {
-        if (!cpuTimeInStateReader->startAggregatingTaskCpuTimes(selectedThreadIds[i],
-                                                                SELECTED_THREAD_AGGREGATION_KEY)) {
+        uint64_t timeInState;
+        if (!android::base::ParseUint<uint64_t>(numbers[1], &timeInState)) {
+            ALOGE("Invalid time_in_state file format: %s", timeInStateFilePath.c_str());
             return false;
         }
-    }
-    return true;
-}
-
-// Converts time-in-state data from a vector of vectors to a flat array.
-// Also converts from nanoseconds to milliseconds.
-static bool flattenTimeInStateData(ScopedLongArrayRW &cpuTimesMillis,
-                                   const std::vector<std::vector<uint64_t>> &data) {
-    size_t frequencyCount = cpuTimesMillis.size();
-    size_t index = 0;
-    for (const auto &cluster : data) {
-        for (const uint64_t &timeNanos : cluster) {
-            if (index < frequencyCount) {
-                cpuTimesMillis[index] = timeNanos / NSEC_PER_MSEC;
-            }
-            index++;
+        if (index < frequencyCount) {
+            outThreadTimeInState[index] = timeInState;
         }
+        index++;
     }
+
     if (index != frequencyCount) {
-        ALOGE("CPU time-in-state reader returned data for %zu frequencies; expected: %zu", index,
-              frequencyCount);
+        ALOGE("Incorrect number of frequencies %u in %s. Expected %u",
+              (uint32_t)outThreadTimeInState.size(), timeInStateFilePath.c_str(),
+              (uint32_t)frequencyCount);
         return false;
     }
 
     return true;
 }
 
-// Reads all CPU time-in-state data accumulated by BPF and aggregates per-frequency
+static int pidCompare(const void *a, const void *b) {
+    return (*(pid_t *)a - *(pid_t *)b);
+}
+
+static inline bool isSelectedThread(const pid_t tid, const pid_t *selectedThreadIds,
+                                    const size_t selectedThreadCount) {
+    return bsearch(&tid, selectedThreadIds, selectedThreadCount, sizeof(pid_t), pidCompare) != NULL;
+}
+
+// Reads all /proc/<pid>/task/*/time_in_state files and aggregates per-frequency
 // time in state data for all threads.  Also, separately aggregates time in state for
 // selected threads whose TIDs are passes as selectedThreadIds.
-static jboolean readProcessCpuUsage(JNIEnv *env, jclass, jint pid,
+static void aggregateThreadCpuTimes(const std::string &procPath, const pid_t pid,
+                                    const std::vector<pid_t> &threadIds,
+                                    const size_t frequencyCount, const pid_t *selectedThreadIds,
+                                    const size_t selectedThreadCount,
+                                    uint64_t *threadCpuTimesMillis,
+                                    uint64_t *selectedThreadCpuTimesMillis) {
+    for (size_t j = 0; j < frequencyCount; j++) {
+        threadCpuTimesMillis[j] = 0;
+        selectedThreadCpuTimesMillis[j] = 0;
+    }
+
+    for (size_t i = 0; i < threadIds.size(); i++) {
+        pid_t tid = threadIds[i];
+        std::vector<uint64_t> timeInState(frequencyCount);
+        if (!getThreadTimeInState(procPath, pid, tid, frequencyCount, timeInState)) {
+            continue;
+        }
+
+        bool selectedThread = isSelectedThread(tid, selectedThreadIds, selectedThreadCount);
+        for (size_t j = 0; j < frequencyCount; j++) {
+            threadCpuTimesMillis[j] += timeInState[j];
+            if (selectedThread) {
+                selectedThreadCpuTimesMillis[j] += timeInState[j];
+            }
+        }
+    }
+    for (size_t i = 0; i < frequencyCount; i++) {
+        threadCpuTimesMillis[i] *= gJiffyMillis;
+        selectedThreadCpuTimesMillis[i] *= gJiffyMillis;
+    }
+}
+
+// Reads process utime and stime from the /proc/<pid>/stat file.
+// Format of this file is described in https://man7.org/linux/man-pages/man5/proc.5.html.
+static bool getProcessCpuTime(const std::string &procPath, const pid_t pid,
+                              uint64_t &outTimeMillis) {
+    std::string statFilePath = android::base::StringPrintf("%s/%u/stat", procPath.c_str(), pid);
+    std::string data;
+    if (!android::base::ReadFileToString(statFilePath, &data)) {
+        return false;
+    }
+
+    auto fields = android::base::Split(data, " ");
+    uint64_t utime, stime;
+
+    // Field 14 (counting from 1) is utime - process time in user space, in jiffies
+    // Field 15 (counting from 1) is stime - process time in system space, in jiffies
+    if (fields.size() < 15 || !android::base::ParseUint(fields[13], &utime) ||
+        !android::base::ParseUint(fields[14], &stime)) {
+        ALOGE("Invalid file format %s", statFilePath.c_str());
+        return false;
+    }
+
+    outTimeMillis = (utime + stime) * gJiffyMillis;
+    return true;
+}
+
+// Estimates per cluster per frequency CPU time for the entire process
+// by distributing the total process CPU time proportionately to how much
+// CPU time its threads took on those clusters/frequencies.  This algorithm
+// works more accurately when when we have equally distributed concurrency.
+// TODO(b/169279846): obtain actual process CPU times from the kernel
+static void estimateProcessTimeInState(const uint64_t processCpuTimeMillis,
+                                       const uint64_t *threadCpuTimesMillis,
+                                       const size_t frequencyCount,
+                                       uint64_t *processCpuTimesMillis) {
+    uint64_t totalCpuTimeAllThreads = 0;
+    for (size_t i = 0; i < frequencyCount; i++) {
+        totalCpuTimeAllThreads += threadCpuTimesMillis[i];
+    }
+
+    if (totalCpuTimeAllThreads != 0) {
+        for (size_t i = 0; i < frequencyCount; i++) {
+            processCpuTimesMillis[i] =
+                    processCpuTimeMillis * threadCpuTimesMillis[i] / totalCpuTimeAllThreads;
+        }
+    } else {
+        for (size_t i = 0; i < frequencyCount; i++) {
+            processCpuTimesMillis[i] = 0;
+        }
+    }
+}
+
+static jboolean readProcessCpuUsage(JNIEnv *env, jclass, jstring procPath, jint pid,
+                                    jintArray selectedThreadIdArray,
+                                    jlongArray processCpuTimesMillisArray,
                                     jlongArray threadCpuTimesMillisArray,
-                                    jlongArray selectedThreadCpuTimesMillisArray,
-                                    jobject cpuTimeInStateReaderObject) {
+                                    jlongArray selectedThreadCpuTimesMillisArray) {
+    ScopedUtfChars procPathChars(env, procPath);
+    ScopedIntArrayRO selectedThreadIds(env, selectedThreadIdArray);
+    ScopedLongArrayRW processCpuTimesMillis(env, processCpuTimesMillisArray);
     ScopedLongArrayRW threadCpuTimesMillis(env, threadCpuTimesMillisArray);
     ScopedLongArrayRW selectedThreadCpuTimesMillis(env, selectedThreadCpuTimesMillisArray);
-    std::unique_ptr<ICpuTimeInStateReader> cpuTimeInStateReader(
-            getCpuTimeInStateReader(env, cpuTimeInStateReaderObject));
 
-    const size_t frequencyCount = cpuTimeInStateReader->getCpuFrequencyCount();
+    std::string procPathStr(procPathChars.c_str());
+
+    // Get all thread IDs for the process.
+    std::vector<pid_t> threadIds;
+    if (!getThreadIds(procPathStr, pid, threadIds)) {
+        ALOGE("Could not obtain thread IDs from: %s", procPathStr.c_str());
+        return false;
+    }
+
+    size_t frequencyCount = processCpuTimesMillis.size();
 
     if (threadCpuTimesMillis.size() != frequencyCount) {
-        ALOGE("Invalid threadCpuTimesMillis array length: %zu frequencies; expected: %zu",
-              threadCpuTimesMillis.size(), frequencyCount);
+        ALOGE("Invalid array length: threadCpuTimesMillis");
         return false;
     }
-
     if (selectedThreadCpuTimesMillis.size() != frequencyCount) {
-        ALOGE("Invalid selectedThreadCpuTimesMillis array length: %zu frequencies; expected: %zu",
-              selectedThreadCpuTimesMillis.size(), frequencyCount);
+        ALOGE("Invalid array length: selectedThreadCpuTimesMillisArray");
         return false;
     }
 
-    for (size_t i = 0; i < frequencyCount; i++) {
-        threadCpuTimesMillis[i] = 0;
-        selectedThreadCpuTimesMillis[i] = 0;
-    }
+    aggregateThreadCpuTimes(procPathStr, pid, threadIds, frequencyCount, selectedThreadIds.get(),
+                            selectedThreadIds.size(),
+                            reinterpret_cast<uint64_t *>(threadCpuTimesMillis.get()),
+                            reinterpret_cast<uint64_t *>(selectedThreadCpuTimesMillis.get()));
 
-    std::optional<std::unordered_map<uint16_t, std::vector<std::vector<uint64_t>>>> data =
-            cpuTimeInStateReader->getAggregatedTaskCpuFreqTimes(pid,
-                                                                {DEFAULT_THREAD_AGGREGATION_KEY,
-                                                                 SELECTED_THREAD_AGGREGATION_KEY});
-    if (!data) {
-        ALOGE("Cannot read thread CPU times for PID %d", pid);
-        return false;
+    uint64_t processCpuTime;
+    bool ret = getProcessCpuTime(procPathStr, pid, processCpuTime);
+    if (ret) {
+        estimateProcessTimeInState(processCpuTime,
+                                   reinterpret_cast<uint64_t *>(threadCpuTimesMillis.get()),
+                                   frequencyCount,
+                                   reinterpret_cast<uint64_t *>(processCpuTimesMillis.get()));
     }
-
-    if (!flattenTimeInStateData(threadCpuTimesMillis, (*data)[DEFAULT_THREAD_AGGREGATION_KEY])) {
-        return false;
-    }
-
-    if (!flattenTimeInStateData(selectedThreadCpuTimesMillis,
-                                (*data)[SELECTED_THREAD_AGGREGATION_KEY])) {
-        return false;
-    }
-
-    // threadCpuTimesMillis returns CPU times for _all_ threads, including the selected ones
-    for (size_t i = 0; i < frequencyCount; i++) {
-        threadCpuTimesMillis[i] += selectedThreadCpuTimesMillis[i];
-    }
-
-    return true;
+    return ret;
 }
 
 static const JNINativeMethod g_single_methods[] = {
-        {"getCpuFrequencyCount",
-         "(Lcom/android/internal/os/KernelSingleProcessCpuThreadReader$CpuTimeInStateReader;)I",
-         (void *)getCpuFrequencyCount},
-        {"startTrackingProcessCpuTimes",
-         "(ILcom/android/internal/os/KernelSingleProcessCpuThreadReader$CpuTimeInStateReader;)Z",
-         (void *)startTrackingProcessCpuTimes},
-        {"startAggregatingThreadCpuTimes",
-         "([ILcom/android/internal/os/KernelSingleProcessCpuThreadReader$CpuTimeInStateReader;)Z",
-         (void *)startAggregatingThreadCpuTimes},
-        {"readProcessCpuUsage",
-         "(I[J[J"
-         "Lcom/android/internal/os/KernelSingleProcessCpuThreadReader$CpuTimeInStateReader;)Z",
-         (void *)readProcessCpuUsage},
+        {"readProcessCpuUsage", "(Ljava/lang/String;I[I[J[J[J)Z", (void *)readProcessCpuUsage},
 };
 
 int register_com_android_internal_os_KernelSingleProcessCpuThreadReader(JNIEnv *env) {
@@ -257,77 +266,4 @@
                                 g_single_methods, NELEM(g_single_methods));
 }
 
-size_t MockCpuTimeInStateReader::getCpuFrequencyCount() {
-    jclass cls = mEnv->GetObjectClass(mCpuTimeInStateReader);
-    jmethodID mid = mEnv->GetMethodID(cls, "getCpuFrequencyCount", "()I");
-    if (mid == 0) {
-        ALOGE("Couldn't find the method getCpuFrequencyCount");
-        return false;
-    }
-    return (size_t)mEnv->CallIntMethod(mCpuTimeInStateReader, mid);
-}
-
-bool MockCpuTimeInStateReader::startTrackingProcessCpuTimes(pid_t tgid) {
-    jclass cls = mEnv->GetObjectClass(mCpuTimeInStateReader);
-    jmethodID mid = mEnv->GetMethodID(cls, "startTrackingProcessCpuTimes", "(I)Z");
-    if (mid == 0) {
-        ALOGE("Couldn't find the method startTrackingProcessCpuTimes");
-        return false;
-    }
-    return mEnv->CallBooleanMethod(mCpuTimeInStateReader, mid, tgid);
-}
-
-bool MockCpuTimeInStateReader::startAggregatingTaskCpuTimes(pid_t pid, uint16_t aggregationKey) {
-    jclass cls = mEnv->GetObjectClass(mCpuTimeInStateReader);
-    jmethodID mid = mEnv->GetMethodID(cls, "startAggregatingTaskCpuTimes", "(II)Z");
-    if (mid == 0) {
-        ALOGE("Couldn't find the method startAggregatingTaskCpuTimes");
-        return false;
-    }
-    return mEnv->CallBooleanMethod(mCpuTimeInStateReader, mid, pid, aggregationKey);
-}
-
-std::optional<std::unordered_map<uint16_t, std::vector<std::vector<uint64_t>>>>
-MockCpuTimeInStateReader::getAggregatedTaskCpuFreqTimes(
-        pid_t pid, const std::vector<uint16_t> &aggregationKeys) {
-    jclass cls = mEnv->GetObjectClass(mCpuTimeInStateReader);
-    jmethodID mid =
-            mEnv->GetMethodID(cls, "getAggregatedTaskCpuFreqTimes", "(I)[Ljava/lang/String;");
-    if (mid == 0) {
-        ALOGE("Couldn't find the method getAggregatedTaskCpuFreqTimes");
-        return {};
-    }
-
-    std::unordered_map<uint16_t, std::vector<std::vector<uint64_t>>> map;
-
-    jobjectArray stringArray =
-            (jobjectArray)mEnv->CallObjectMethod(mCpuTimeInStateReader, mid, pid);
-    int size = mEnv->GetArrayLength(stringArray);
-    for (int i = 0; i < size; i++) {
-        ScopedUtfChars line(mEnv, (jstring)mEnv->GetObjectArrayElement(stringArray, i));
-        uint16_t aggregationKey;
-        std::vector<std::vector<uint64_t>> times;
-
-        // Each string is formatted like this: "aggKey:t0_0 t0_1...:t1_0 t1_1..."
-        auto fields = android::base::Split(line.c_str(), ":");
-        android::base::ParseUint(fields[0], &aggregationKey);
-
-        for (int j = 1; j < fields.size(); j++) {
-            auto numbers = android::base::Split(fields[j], " ");
-
-            std::vector<uint64_t> chunk;
-            for (int k = 0; k < numbers.size(); k++) {
-                uint64_t time;
-                android::base::ParseUint(numbers[k], &time);
-                chunk.emplace_back(time);
-            }
-            times.emplace_back(chunk);
-        }
-
-        map.emplace(aggregationKey, times);
-    }
-
-    return map;
-}
-
 } // namespace android
diff --git a/core/res/Android.bp b/core/res/Android.bp
index f94a2b0..9ee5e5e1 100644
--- a/core/res/Android.bp
+++ b/core/res/Android.bp
@@ -19,6 +19,13 @@
     sdk_version: "core_platform",
     certificate: "platform",
 
+    // Disable dexpreopt and verify_uses_libraries check as the app
+    // contains no Java code to be dexpreopted.
+    enforce_uses_libs: false,
+    dex_preopt: {
+        enabled: false,
+    },
+
     // Soong special-cases framework-res to install this alongside
     // the libraries at /system/framework/framework-res.apk.
 
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 62a8ae5..28f5e35 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -393,6 +393,7 @@
     <protected-broadcast android:name="android.net.wifi.action.PASSPOINT_OSU_PROVIDERS_LIST" />
     <protected-broadcast android:name="android.net.wifi.action.PASSPOINT_SUBSCRIPTION_REMEDIATION" />
     <protected-broadcast android:name="android.net.wifi.action.PASSPOINT_LAUNCH_OSU_VIEW" />
+    <protected-broadcast android:name="android.net.wifi.action.REFRESH_USER_PROVISIONING" />
     <protected-broadcast android:name="android.net.wifi.action.WIFI_NETWORK_SUGGESTION_POST_CONNECTION" />
     <protected-broadcast android:name="android.net.wifi.action.WIFI_SCAN_AVAILABILITY_CHANGED" />
     <protected-broadcast android:name="android.net.wifi.supplicant.CONNECTION_CHANGE" />
diff --git a/core/tests/coretests/src/android/hardware/input/InputDeviceSensorManagerTest.java b/core/tests/coretests/src/android/hardware/input/InputDeviceSensorManagerTest.java
new file mode 100644
index 0000000..b319886
--- /dev/null
+++ b/core/tests/coretests/src/android/hardware/input/InputDeviceSensorManagerTest.java
@@ -0,0 +1,251 @@
+/*
+ * 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 android.hardware.input;
+
+import static junit.framework.TestCase.assertEquals;
+import static junit.framework.TestCase.assertNotNull;
+import static junit.framework.TestCase.assertTrue;
+import static junit.framework.TestCase.fail;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.content.ContextWrapper;
+import android.hardware.Sensor;
+import android.hardware.SensorEvent;
+import android.hardware.SensorEventListener;
+import android.hardware.SensorManager;
+import android.os.test.TestLooper;
+import android.platform.test.annotations.Presubmit;
+import android.view.InputDevice;
+
+import androidx.test.InstrumentationRegistry;
+
+import com.android.internal.annotations.GuardedBy;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoJUnitRunner;
+import org.mockito.junit.MockitoRule;
+
+import java.util.List;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Tests for {@link InputDeviceSensorManager}.
+ *
+ * Build/Install/Run:
+ * atest FrameworksCoreTests:InputDeviceSensorManagerTest
+ */
+@Presubmit
+@RunWith(MockitoJUnitRunner.class)
+public class InputDeviceSensorManagerTest {
+    private static final String TAG = "InputDeviceSensorManagerTest";
+
+    private static final int DEVICE_ID = 1000;
+
+    @Rule public final MockitoRule mockito = MockitoJUnit.rule();
+
+    private TestLooper mTestLooper;
+    private ContextWrapper mContextSpy;
+    private InputManager mInputManager;
+    private InputDeviceSensorManager mSensorManager;
+    private IInputSensorEventListener mIInputSensorEventListener;
+    private final Object mLock = new Object();
+
+    @Mock private IInputManager mIInputManagerMock;
+
+    @Before
+    public void setUp() throws Exception {
+        mTestLooper = new TestLooper();
+        mContextSpy = spy(new ContextWrapper(InstrumentationRegistry.getContext()));
+        InputManager inputManager = InputManager.resetInstance(mIInputManagerMock);
+
+        when(mContextSpy.getSystemService(eq(Context.INPUT_SERVICE))).thenReturn(inputManager);
+
+        when(mIInputManagerMock.getInputDeviceIds()).thenReturn(new int[]{DEVICE_ID});
+
+        when(mIInputManagerMock.getInputDevice(eq(DEVICE_ID))).thenReturn(
+                createInputDeviceWithSensor(DEVICE_ID));
+
+        when(mIInputManagerMock.getSensorList(eq(DEVICE_ID))).thenReturn(new InputSensorInfo[] {
+                createInputSensorInfo(DEVICE_ID, Sensor.TYPE_ACCELEROMETER),
+                createInputSensorInfo(DEVICE_ID, Sensor.TYPE_GYROSCOPE)});
+
+        when(mIInputManagerMock.enableSensor(eq(DEVICE_ID), anyInt(), anyInt(), anyInt()))
+                .thenReturn(true);
+
+        when(mIInputManagerMock.registerSensorListener(any())).thenReturn(true);
+
+        mInputManager = mContextSpy.getSystemService(InputManager.class);
+    }
+
+    @After
+    public void tearDown() {
+        InputManager.clearInstance();
+    }
+
+    private class InputTestSensorEventListener implements SensorEventListener {
+        @GuardedBy("mLock")
+        private final BlockingQueue<SensorEvent> mEvents = new LinkedBlockingQueue<>();
+        InputTestSensorEventListener() {
+            super();
+        }
+
+        public SensorEvent waitForSensorEvent() {
+            try {
+                return mEvents.poll(5, TimeUnit.SECONDS);
+            } catch (InterruptedException e) {
+                fail("unexpectedly interrupted while waiting for SensorEvent");
+                return null;
+            }
+        }
+
+        @Override
+        public void onSensorChanged(SensorEvent event) {
+            synchronized (mLock) {
+                try {
+                    mEvents.put(event);
+                } catch (InterruptedException ex) {
+                    fail("interrupted while adding a SensorEvent to the queue");
+                }
+            }
+        }
+
+        @Override
+        public void onAccuracyChanged(Sensor sensor, int accuracy) {
+        }
+    }
+
+    private InputDevice createInputDeviceWithSensor(int id) {
+        InputDevice d = new InputDevice(id, 0 /* generation */, 0 /* controllerNumber */, "name",
+                0 /* vendorId */, 0 /* productId */, "descriptor", true /* isExternal */,
+                0 /* sources */, 0 /* keyboardType */, null /* keyCharacterMap */,
+                false /* hasVibrator */, false /* hasMicrophone */, false /* hasButtonUnderpad */,
+                true /* hasSensor */);
+        assertTrue(d.hasSensor());
+        return d;
+    }
+
+    private InputSensorInfo createInputSensorInfo(int id, int type) {
+        InputSensorInfo info = new InputSensorInfo("name", "vendor", 0 /* version */,
+                0 /* handle */, type, 100.0f /*maxRange */, 0.02f /* resolution */,
+                0.8f /* power */, 1000 /* minDelay */, 0 /* fifoReservedEventCount */,
+                0 /* fifoMaxEventCount */, "" /* stringType */, "" /* requiredPermission */,
+                0 /* maxDelay */, 0 /* flags */, id);
+        return info;
+    }
+
+    private InputDevice getSensorDevice(int[] deviceIds) {
+        for (int i = 0; i < deviceIds.length; i++) {
+            InputDevice device = mInputManager.getInputDevice(deviceIds[i]);
+            if (device.hasSensor()) {
+                return device;
+            }
+        }
+        return null;
+    }
+
+    @Test
+    public void getInputDeviceSensors_withExpectedType() throws Exception {
+        InputDevice device = getSensorDevice(mInputManager.getInputDeviceIds());
+        assertTrue(device != null);
+
+        SensorManager sensorManager = device.getSensorManager();
+        List<Sensor> accelList = sensorManager.getSensorList(Sensor.TYPE_ACCELEROMETER);
+        verify(mIInputManagerMock).getSensorList(eq(DEVICE_ID));
+        assertEquals(1, accelList.size());
+        assertEquals(DEVICE_ID, accelList.get(0).getId());
+        assertEquals(Sensor.TYPE_ACCELEROMETER, accelList.get(0).getType());
+
+        List<Sensor> gyroList = sensorManager.getSensorList(Sensor.TYPE_GYROSCOPE);
+        verify(mIInputManagerMock).getSensorList(eq(DEVICE_ID));
+        assertEquals(1, gyroList.size());
+        assertEquals(DEVICE_ID, gyroList.get(0).getId());
+        assertEquals(Sensor.TYPE_GYROSCOPE, gyroList.get(0).getType());
+
+    }
+
+    @Test
+    public void getInputDeviceSensors_withUnexpectedType() throws Exception {
+        InputDevice device = getSensorDevice(mInputManager.getInputDeviceIds());
+
+        assertTrue(device != null);
+        SensorManager sensorManager = device.getSensorManager();
+
+        List<Sensor> gameRotationList = sensorManager.getSensorList(
+                Sensor.TYPE_GAME_ROTATION_VECTOR);
+        verify(mIInputManagerMock).getSensorList(eq(DEVICE_ID));
+        assertEquals(0, gameRotationList.size());
+
+        List<Sensor> gravityList = sensorManager.getSensorList(Sensor.TYPE_GRAVITY);
+        verify(mIInputManagerMock).getSensorList(eq(DEVICE_ID));
+        assertEquals(0, gravityList.size());
+    }
+
+    @Test
+    public void testInputDeviceSensorListener() throws Exception {
+        InputDevice device = getSensorDevice(mInputManager.getInputDeviceIds());
+        assertTrue(device != null);
+
+        SensorManager sensorManager = device.getSensorManager();
+        Sensor sensor = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
+        assertEquals(Sensor.TYPE_ACCELEROMETER, sensor.getType());
+
+        doAnswer(invocation -> {
+            mIInputSensorEventListener = invocation.getArgument(0);
+            assertNotNull(mIInputSensorEventListener);
+            return true;
+        }).when(mIInputManagerMock).registerSensorListener(any());
+
+        InputTestSensorEventListener listener = new InputTestSensorEventListener();
+        assertTrue(sensorManager.registerListener(listener, sensor,
+                SensorManager.SENSOR_DELAY_NORMAL));
+        verify(mIInputManagerMock).registerSensorListener(any());
+        verify(mIInputManagerMock).enableSensor(eq(DEVICE_ID), eq(sensor.getType()),
+                anyInt(), anyInt());
+
+        float[] values = new float[] {0.12f, 9.8f, 0.2f};
+        mIInputSensorEventListener.onInputSensorChanged(DEVICE_ID, Sensor.TYPE_ACCELEROMETER,
+                SensorManager.SENSOR_STATUS_ACCURACY_HIGH,  /* timestamp */ 0x1234abcd, values);
+
+        SensorEvent event = listener.waitForSensorEvent();
+        assertNotNull(event);
+        assertEquals(0x1234abcd, event.timestamp);
+        assertEquals(values.length, event.values.length);
+        for (int i = 0; i < values.length; i++) {
+            assertEquals(values[i], event.values[i], 0.001f);
+        }
+
+        sensorManager.unregisterListener(listener);
+        verify(mIInputManagerMock).disableSensor(eq(DEVICE_ID), eq(sensor.getType()));
+    }
+
+}
diff --git a/core/tests/coretests/src/android/os/FileUtilsTest.java b/core/tests/coretests/src/android/os/FileUtilsTest.java
index 5bce227c..1a86678 100644
--- a/core/tests/coretests/src/android/os/FileUtilsTest.java
+++ b/core/tests/coretests/src/android/os/FileUtilsTest.java
@@ -16,6 +16,7 @@
 
 package android.os;
 
+import static android.os.FileUtils.convertToModernFd;
 import static android.os.FileUtils.roundStorageSize;
 import static android.os.FileUtils.translateModeAccessToPosix;
 import static android.os.FileUtils.translateModePfdToPosix;
@@ -45,6 +46,8 @@
 import static org.junit.Assert.assertArrayEquals;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 
@@ -67,6 +70,7 @@
 import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
 import java.io.File;
+import java.io.FileDescriptor;
 import java.io.FileInputStream;
 import java.io.FileOutputStream;
 import java.util.Arrays;
@@ -562,6 +566,55 @@
         assertEquals(O_RDWR, translateModeAccessToPosix(R_OK | W_OK | X_OK));
     }
 
+    @Test
+    public void testConvertToModernFd() throws Exception {
+        final String nonce = String.valueOf(System.nanoTime());
+
+        final File cameraDir = new File("/storage/emulated/0/DCIM/Camera");
+        final File nonCameraDir = new File("/storage/emulated/0/Pictures");
+        cameraDir.mkdirs();
+        nonCameraDir.mkdirs();
+
+        final File validVideoCameraDir = new File(cameraDir, "validVideo-" + nonce + ".mp4");
+        final File validImageCameraDir = new File(cameraDir, "validImage-" + nonce + ".jpg");
+        final File invalidVideoCameraDir = new File(cameraDir, ".invalidVideo-" + nonce + ".mp4");
+
+        final File validVideoNonCameraDir = new File(nonCameraDir, "validVideo-" + nonce + ".mp4");
+        final File validImageNonCameraDir = new File(nonCameraDir, "validImage-" + nonce + ".jpg");
+
+        try {
+            FileDescriptor pfdValidVideoCameraDir =
+                    ParcelFileDescriptor.open(validVideoCameraDir,
+                            MODE_CREATE | MODE_READ_WRITE).getFileDescriptor();
+            FileDescriptor pfdValidImageCameraDir =
+                    ParcelFileDescriptor.open(validImageCameraDir,
+                            MODE_CREATE | MODE_READ_WRITE).getFileDescriptor();
+            FileDescriptor pfdInvalidVideoCameraDir =
+                    ParcelFileDescriptor.open(invalidVideoCameraDir,
+                            MODE_CREATE | MODE_READ_WRITE).getFileDescriptor();
+
+            FileDescriptor pfdValidVideoNonCameraDir =
+                    ParcelFileDescriptor.open(validVideoNonCameraDir,
+                            MODE_CREATE | MODE_READ_WRITE).getFileDescriptor();
+            FileDescriptor pfdValidImageNonCameraDir =
+                    ParcelFileDescriptor.open(validImageNonCameraDir,
+                            MODE_CREATE | MODE_READ_WRITE).getFileDescriptor();
+
+            assertNotNull(convertToModernFd(pfdValidVideoCameraDir));
+
+            assertNull(convertToModernFd(pfdValidImageCameraDir));
+            assertNull(convertToModernFd(pfdInvalidVideoCameraDir));
+            assertNull(convertToModernFd(pfdValidVideoNonCameraDir));
+            assertNull(convertToModernFd(pfdValidImageNonCameraDir));
+        } finally {
+            validVideoCameraDir.delete();
+            validImageCameraDir.delete();
+            invalidVideoCameraDir.delete();
+            validVideoNonCameraDir.delete();
+            validImageNonCameraDir.delete();
+        }
+    }
+
     private static void assertTranslate(String string, int posix, int pfd) {
         assertEquals(posix, translateModeStringToPosix(string));
         assertEquals(string, translateModePosixToString(posix));
diff --git a/core/tests/coretests/src/android/util/BinaryXmlTest.java b/core/tests/coretests/src/android/util/BinaryXmlTest.java
index 6fa5a23..fd625dce 100644
--- a/core/tests/coretests/src/android/util/BinaryXmlTest.java
+++ b/core/tests/coretests/src/android/util/BinaryXmlTest.java
@@ -66,7 +66,7 @@
         final TypedXmlPullParser in = Xml.newBinaryPullParser();
         final ByteArrayInputStream is = new ByteArrayInputStream(os.toByteArray());
         in.setInput(is, StandardCharsets.UTF_8.name());
-        assertNext(in, START_TAG, "tag", 1);
+        assertNext(in, START_TAG, "tag");
         assertEquals(count, in.getAttributeCount());
     }
 
@@ -140,7 +140,12 @@
                 doVerifyWrite(xml);
                 data = os.toByteArray();
             }
-            try (InputStream is = new ByteArrayInputStream(data)) {
+            try (InputStream is = new ByteArrayInputStream(data) {
+                @Override
+                public boolean markSupported() {
+                    return false;
+                }
+            }) {
                 doVerifyRead(Xml.resolvePullParser(is));
             }
         }
@@ -152,7 +157,12 @@
                 doVerifyWrite(xml);
                 data = os.toByteArray();
             }
-            try (InputStream is = new ByteArrayInputStream(data)) {
+            try (InputStream is = new ByteArrayInputStream(data) {
+                @Override
+                public boolean markSupported() {
+                    return false;
+                }
+            }) {
                 doVerifyRead(Xml.resolvePullParser(is));
             }
         }
diff --git a/core/tests/coretests/src/android/util/XmlTest.java b/core/tests/coretests/src/android/util/XmlTest.java
index a8fc6f9..4e10ea9 100644
--- a/core/tests/coretests/src/android/util/XmlTest.java
+++ b/core/tests/coretests/src/android/util/XmlTest.java
@@ -53,6 +53,14 @@
     }
 
     @Test
+    public void testLargeValues_FastIndenting() throws Exception {
+        final TypedXmlSerializer out = Xml.newFastSerializer();
+        out.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true);
+        doLargeValues(out,
+                Xml.newFastPullParser());
+    }
+
+    @Test
     public void testLargeValues_Binary() throws Exception {
         doLargeValues(Xml.newBinarySerializer(),
                 Xml.newBinaryPullParser());
@@ -81,7 +89,7 @@
 
         final ByteArrayInputStream is = new ByteArrayInputStream(os.toByteArray());
         in.setInput(is, StandardCharsets.UTF_8.name());
-        assertNext(in, START_TAG, "tag", 1);
+        assertNext(in, START_TAG, "tag");
         assertEquals(2, in.getAttributeCount());
         assertEquals(string, in.getAttributeValue(null, "string"));
         assertArrayEquals(bytes, in.getAttributeBytesBase64(null, "bytes"));
@@ -100,6 +108,14 @@
     }
 
     @Test
+    public void testPersistableBundle_FastIndenting() throws Exception {
+        final TypedXmlSerializer out = Xml.newFastSerializer();
+        out.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true);
+        doPersistableBundle(out,
+                Xml.newFastPullParser());
+    }
+
+    @Test
     public void testPersistableBundle_Binary() throws Exception {
         doPersistableBundle(Xml.newBinarySerializer(),
                 Xml.newBinaryPullParser());
@@ -180,6 +196,14 @@
     }
 
     @Test
+    public void testVerify_FastIndenting() throws Exception {
+        final TypedXmlSerializer out = Xml.newFastSerializer();
+        out.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true);
+        doVerify(out,
+                Xml.newFastPullParser());
+    }
+
+    @Test
     public void testVerify_Binary() throws Exception {
         doVerify(Xml.newBinarySerializer(),
                 Xml.newBinaryPullParser());
@@ -246,9 +270,12 @@
 
     static void doVerifyRead(TypedXmlPullParser in) throws Exception {
         assertEquals(START_DOCUMENT, in.getEventType());
-        assertNext(in, START_TAG, "one", 1);
+        assertDepth(in, 0);
+        assertNext(in, START_TAG, "one");
+        assertDepth(in, 1);
         {
-            assertNext(in, START_TAG, "two", 2);
+            assertNext(in, START_TAG, "two");
+            assertDepth(in, 2);
             {
                 assertEquals(14, in.getAttributeCount());
                 assertEquals(TEST_STRING,
@@ -285,27 +312,36 @@
                 assertEquals("49", in.getAttributeValue(null, "stringNumber"));
                 assertEquals(49, in.getAttributeInt(null, "stringNumber"));
             }
-            assertNext(in, END_TAG, "two", 2);
+            assertNext(in, END_TAG, "two");
+            assertDepth(in, 2);
 
-            assertNext(in, START_TAG, "three", 2);
+            assertNext(in, START_TAG, "three");
+            assertDepth(in, 2);
             {
-                assertNext(in, TEXT);
+                assertNext(in, TEXT, null);
+                assertDepth(in, 2);
                 assertEquals("foo", in.getText().trim());
-                assertNext(in, START_TAG, "four", 3);
+                assertNext(in, START_TAG, "four");
+                assertDepth(in, 3);
                 {
                     assertEquals(0, in.getAttributeCount());
                 }
-                assertNext(in, END_TAG, "four", 3);
-                assertNext(in, TEXT);
+                assertNext(in, END_TAG, "four");
+                assertDepth(in, 3);
+                assertNext(in, TEXT, null);
+                assertDepth(in, 2);
                 assertEquals("barbaz", in.getText().trim());
             }
-            assertNext(in, END_TAG, "three", 2);
+            assertNext(in, END_TAG, "three");
+            assertDepth(in, 2);
         }
-        assertNext(in, END_TAG, "one", 1);
-        assertNext(in, END_DOCUMENT);
+        assertNext(in, END_TAG, "one");
+        assertDepth(in, 1);
+        assertNext(in, END_DOCUMENT, null);
+        assertDepth(in, 0);
     }
 
-    static void assertNext(TypedXmlPullParser in, int token) throws Exception {
+    static void assertNext(TypedXmlPullParser in, int token, String name) throws Exception {
         // We're willing to skip over empty text regions, which some
         // serializers emit transparently
         int event;
@@ -313,12 +349,10 @@
         }
         assertEquals("next", token, event);
         assertEquals("getEventType", token, in.getEventType());
+        assertEquals("getName", name, in.getName());
     }
 
-    static void assertNext(TypedXmlPullParser in, int token, String name, int depth)
-            throws Exception {
-        assertNext(in, token);
-        assertEquals("getName", name, in.getName());
+    static void assertDepth(TypedXmlPullParser in, int depth) throws Exception {
         assertEquals("getDepth", depth, in.getDepth());
     }
 }
diff --git a/core/tests/coretests/src/android/view/accessibility/AccessibilityInteractionClientTest.java b/core/tests/coretests/src/android/view/accessibility/AccessibilityInteractionClientTest.java
index 7e1e7f4..ab24f89 100644
--- a/core/tests/coretests/src/android/view/accessibility/AccessibilityInteractionClientTest.java
+++ b/core/tests/coretests/src/android/view/accessibility/AccessibilityInteractionClientTest.java
@@ -33,6 +33,9 @@
 import org.junit.runner.RunWith;
 import org.mockito.Mock;
 
+import java.util.Arrays;
+import java.util.List;
+
 /**
  * Tests for AccessibilityInteractionClient
  */
@@ -62,7 +65,7 @@
         final long accessibilityNodeId = 0x4321L;
         AccessibilityNodeInfo nodeFromConnection = AccessibilityNodeInfo.obtain();
         nodeFromConnection.setSourceNodeId(accessibilityNodeId, windowId);
-        mMockConnection.mInfoToReturn = nodeFromConnection;
+        mMockConnection.mInfosToReturn = Arrays.asList(nodeFromConnection);
         AccessibilityInteractionClient client = AccessibilityInteractionClient.getInstance();
         AccessibilityNodeInfo node = client.findAccessibilityNodeInfoByAccessibilityId(
                 MOCK_CONNECTION_ID, windowId, accessibilityNodeId, true, 0, null);
@@ -72,7 +75,7 @@
     }
 
     private static class MockConnection extends AccessibilityServiceConnectionImpl {
-        AccessibilityNodeInfo mInfoToReturn;
+        List<AccessibilityNodeInfo> mInfosToReturn;
 
         @Override
         public String[] findAccessibilityNodeInfoByAccessibilityId(int accessibilityWindowId,
@@ -80,7 +83,7 @@
                 IAccessibilityInteractionConnectionCallback callback, int flags, long threadId,
                 Bundle arguments) {
             try {
-                callback.setFindAccessibilityNodeInfoResult(mInfoToReturn, interactionId);
+                callback.setFindAccessibilityNodeInfosResult(mInfosToReturn, interactionId);
             } catch (RemoteException e) {
                 throw new RuntimeException(e);
             }
diff --git a/core/tests/coretests/src/android/widget/TextViewTest.java b/core/tests/coretests/src/android/widget/TextViewTest.java
index 40ecf9a..66fdfff 100644
--- a/core/tests/coretests/src/android/widget/TextViewTest.java
+++ b/core/tests/coretests/src/android/widget/TextViewTest.java
@@ -16,6 +16,9 @@
 
 package android.widget;
 
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
+
 import static junit.framework.Assert.assertEquals;
 import static junit.framework.Assert.assertFalse;
 import static junit.framework.Assert.assertNotNull;
@@ -30,6 +33,7 @@
 import android.text.Layout;
 import android.text.PrecomputedText;
 import android.view.View;
+import android.view.inputmethod.EditorInfo;
 import android.widget.TextView.BufferType;
 
 import androidx.test.InstrumentationRegistry;
@@ -254,6 +258,24 @@
         assertEquals("", mTextView.getTransformed().toString());
     }
 
+    @Test
+    @UiThreadTest
+    public void testPortraitDoesntSupportFullscreenIme() {
+        mActivity.setRequestedOrientation(SCREEN_ORIENTATION_PORTRAIT);
+        mTextView = new NullSetTextTextView(mActivity);
+        mTextView.requestFocus();
+        assertEquals("IME_FLAG_NO_FULLSCREEN should be set",
+                mTextView.getImeOptions(),
+                mTextView.getImeOptions() & EditorInfo.IME_FLAG_NO_FULLSCREEN);
+
+        mTextView.clearFocus();
+        mActivity.setRequestedOrientation(SCREEN_ORIENTATION_LANDSCAPE);
+        mTextView = new NullSetTextTextView(mActivity);
+        mTextView.requestFocus();
+        assertEquals("IME_FLAG_NO_FULLSCREEN should not be set",
+                0, mTextView.getImeOptions() & EditorInfo.IME_FLAG_NO_FULLSCREEN);
+    }
+
     private String createLongText() {
         int size = 600 * 1000;
         final StringBuilder builder = new StringBuilder(size);
diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryStatsTests.java b/core/tests/coretests/src/com/android/internal/os/BatteryStatsTests.java
index cfa8c4d..bd41542 100644
--- a/core/tests/coretests/src/com/android/internal/os/BatteryStatsTests.java
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryStatsTests.java
@@ -38,7 +38,9 @@
         BatteryStatsTimeBaseTest.class,
         BatteryStatsTimerTest.class,
         BatteryStatsUidTest.class,
+        BatteryUsageStatsTest.class,
         BatteryStatsUserLifecycleTests.class,
+        BluetoothPowerCalculatorTest.class,
         BstatsCpuTimesValidationTest.class,
         KernelCpuProcStringReaderTest.class,
         KernelCpuUidActiveTimeReaderTest.class,
diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryUsageStatsTest.java b/core/tests/coretests/src/com/android/internal/os/BatteryUsageStatsTest.java
new file mode 100644
index 0000000..96e9c4a
--- /dev/null
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryUsageStatsTest.java
@@ -0,0 +1,159 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.os;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.junit.Assert.fail;
+
+import android.os.BatteryConsumer;
+import android.os.BatteryUsageStats;
+import android.os.Parcel;
+import android.os.SystemBatteryConsumer;
+import android.os.UidBatteryConsumer;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.List;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class BatteryUsageStatsTest {
+
+    @Test
+    public void testBuilder() {
+        BatteryUsageStats batteryUsageStats = buildBatteryUsageStats();
+        validateBatteryUsageStats(batteryUsageStats);
+    }
+
+    @Test
+    public void testParcelability() {
+        final BatteryUsageStats outBatteryUsageStats = buildBatteryUsageStats();
+        final Parcel outParcel = Parcel.obtain();
+        outParcel.writeParcelable(outBatteryUsageStats, 0);
+        final byte[] bytes = outParcel.marshall();
+        outParcel.recycle();
+
+        final Parcel inParcel = Parcel.obtain();
+        inParcel.unmarshall(bytes, 0, bytes.length);
+        inParcel.setDataPosition(0);
+        final BatteryUsageStats inBatteryUsageStats =
+                inParcel.readParcelable(getClass().getClassLoader());
+        assertThat(inBatteryUsageStats).isNotNull();
+        validateBatteryUsageStats(inBatteryUsageStats);
+    }
+
+    private BatteryUsageStats buildBatteryUsageStats() {
+        final MockClocks clocks = new MockClocks();
+        final MockBatteryStatsImpl batteryStats = new MockBatteryStatsImpl(clocks);
+        final BatteryStatsImpl.Uid batteryStatsUid = batteryStats.getUidStatsLocked(2000);
+
+        final BatteryUsageStats.Builder builder = new BatteryUsageStats.Builder(1, 1, true);
+        builder.setConsumedPower(100);
+        builder.setDischargePercentage(20);
+
+        final UidBatteryConsumer.Builder uidBatteryConsumerBuilder =
+                builder.getOrCreateUidBatteryConsumerBuilder(batteryStatsUid);
+        uidBatteryConsumerBuilder.setPackageWithHighestDrain("foo");
+        uidBatteryConsumerBuilder.setConsumedPower(200);
+        uidBatteryConsumerBuilder.setConsumedPower(BatteryConsumer.POWER_COMPONENT_USAGE, 300);
+        uidBatteryConsumerBuilder.setConsumedPower(BatteryConsumer.POWER_COMPONENT_CPU, 400);
+        uidBatteryConsumerBuilder.setConsumedPowerForCustomComponent(
+                BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID, 500);
+        uidBatteryConsumerBuilder.setConsumedPowerForCustomComponent(
+                BatteryConsumer.FIRST_MODELED_POWER_COMPONENT_ID
+                        + BatteryConsumer.POWER_COMPONENT_CPU, 510);
+        uidBatteryConsumerBuilder.setUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_CPU, 600);
+        uidBatteryConsumerBuilder.setUsageDurationMillis(
+                BatteryConsumer.TIME_COMPONENT_CPU_FOREGROUND, 700);
+        uidBatteryConsumerBuilder.setUsageDurationForCustomComponentMillis(
+                BatteryConsumer.FIRST_CUSTOM_TIME_COMPONENT_ID, 800);
+
+        final SystemBatteryConsumer.Builder systemBatteryConsumerBuilder =
+                builder.getOrCreateSystemBatteryConsumerBuilder(
+                        SystemBatteryConsumer.DRAIN_TYPE_CAMERA);
+        systemBatteryConsumerBuilder.setConsumedPower(10000);
+        systemBatteryConsumerBuilder.setConsumedPower(BatteryConsumer.POWER_COMPONENT_CPU, 10100);
+        systemBatteryConsumerBuilder.setConsumedPowerForCustomComponent(
+                BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID, 10200);
+        systemBatteryConsumerBuilder.setConsumedPowerForCustomComponent(
+                BatteryConsumer.FIRST_MODELED_POWER_COMPONENT_ID
+                        + BatteryConsumer.POWER_COMPONENT_CPU, 10210);
+        systemBatteryConsumerBuilder.setUsageDurationMillis(
+                BatteryConsumer.TIME_COMPONENT_CPU, 10300);
+        systemBatteryConsumerBuilder.setUsageDurationForCustomComponentMillis(
+                BatteryConsumer.FIRST_CUSTOM_TIME_COMPONENT_ID, 10400);
+
+        return builder.build();
+    }
+
+    public void validateBatteryUsageStats(BatteryUsageStats batteryUsageStats) {
+        assertThat(batteryUsageStats.getConsumedPower()).isEqualTo(100);
+        assertThat(batteryUsageStats.getDischargePercentage()).isEqualTo(20);
+
+        final List<UidBatteryConsumer> uidBatteryConsumers =
+                batteryUsageStats.getUidBatteryConsumers();
+        for (UidBatteryConsumer uidBatteryConsumer : uidBatteryConsumers) {
+            if (uidBatteryConsumer.getUid() == 2000) {
+                assertThat(uidBatteryConsumer.getPackageWithHighestDrain()).isEqualTo("foo");
+                assertThat(uidBatteryConsumer.getConsumedPower()).isEqualTo(200);
+                assertThat(uidBatteryConsumer.getConsumedPower(
+                        BatteryConsumer.POWER_COMPONENT_USAGE)).isEqualTo(300);
+                assertThat(uidBatteryConsumer.getConsumedPower(
+                        BatteryConsumer.POWER_COMPONENT_CPU)).isEqualTo(400);
+                assertThat(uidBatteryConsumer.getConsumedPowerForCustomComponent(
+                        BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID)).isEqualTo(500);
+                assertThat(uidBatteryConsumer.getConsumedPowerForCustomComponent(
+                        BatteryConsumer.FIRST_MODELED_POWER_COMPONENT_ID
+                                + BatteryConsumer.POWER_COMPONENT_CPU)).isEqualTo(510);
+                assertThat(uidBatteryConsumer.getUsageDurationMillis(
+                        BatteryConsumer.TIME_COMPONENT_CPU)).isEqualTo(600);
+                assertThat(uidBatteryConsumer.getUsageDurationMillis(
+                        BatteryConsumer.TIME_COMPONENT_CPU_FOREGROUND)).isEqualTo(700);
+                assertThat(uidBatteryConsumer.getUsageDurationForCustomComponentMillis(
+                        BatteryConsumer.FIRST_CUSTOM_TIME_COMPONENT_ID)).isEqualTo(800);
+            } else {
+                fail("Unexpected UID " + uidBatteryConsumer.getUid());
+            }
+        }
+
+        final List<SystemBatteryConsumer> systemBatteryConsumers =
+                batteryUsageStats.getSystemBatteryConsumers();
+        for (SystemBatteryConsumer systemBatteryConsumer : systemBatteryConsumers) {
+            if (systemBatteryConsumer.getDrainType() == SystemBatteryConsumer.DRAIN_TYPE_CAMERA) {
+                assertThat(systemBatteryConsumer.getConsumedPower()).isEqualTo(10000);
+                assertThat(systemBatteryConsumer.getConsumedPower(
+                        BatteryConsumer.POWER_COMPONENT_CPU)).isEqualTo(10100);
+                assertThat(systemBatteryConsumer.getConsumedPowerForCustomComponent(
+                        BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID)).isEqualTo(10200);
+                assertThat(systemBatteryConsumer.getConsumedPowerForCustomComponent(
+                        BatteryConsumer.FIRST_MODELED_POWER_COMPONENT_ID
+                                + BatteryConsumer.POWER_COMPONENT_CPU)).isEqualTo(10210);
+                assertThat(systemBatteryConsumer.getUsageDurationMillis(
+                        BatteryConsumer.TIME_COMPONENT_CPU)).isEqualTo(10300);
+                assertThat(systemBatteryConsumer.getUsageDurationForCustomComponentMillis(
+                        BatteryConsumer.FIRST_CUSTOM_TIME_COMPONENT_ID)).isEqualTo(10400);
+            } else {
+                fail("Unexpected drain type " + systemBatteryConsumer.getDrainType());
+            }
+        }
+    }
+}
diff --git a/core/tests/coretests/src/com/android/internal/os/BluetoothPowerCalculatorTest.java b/core/tests/coretests/src/com/android/internal/os/BluetoothPowerCalculatorTest.java
new file mode 100644
index 0000000..96eb8da
--- /dev/null
+++ b/core/tests/coretests/src/com/android/internal/os/BluetoothPowerCalculatorTest.java
@@ -0,0 +1,180 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.os;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.when;
+
+import android.annotation.Nullable;
+import android.os.BatteryConsumer;
+import android.os.BatteryUsageStats;
+import android.os.BatteryUsageStatsQuery;
+import android.os.Process;
+import android.os.SystemBatteryConsumer;
+import android.os.UidBatteryConsumer;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class BluetoothPowerCalculatorTest {
+    private static final double PRECISION = 0.00001;
+    private static final int APP_UID = Process.FIRST_APPLICATION_UID + 42;
+
+    @Mock
+    private PowerProfile mMockPowerProfile;
+    private MockBatteryStatsImpl mMockBatteryStats;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+        mMockBatteryStats = new MockBatteryStatsImpl(new MockClocks()) {
+            @Override
+            public boolean hasBluetoothActivityReporting() {
+                return true;
+            }
+        };
+        mMockBatteryStats.getOnBatteryTimeBase().setRunning(true, 100_000, 100_000);
+        when(mMockPowerProfile.getAveragePower(
+                PowerProfile.POWER_BLUETOOTH_CONTROLLER_IDLE)).thenReturn(10.0);
+        when(mMockPowerProfile.getAveragePower(
+                PowerProfile.POWER_BLUETOOTH_CONTROLLER_RX)).thenReturn(50.0);
+        when(mMockPowerProfile.getAveragePower(
+                PowerProfile.POWER_BLUETOOTH_CONTROLLER_TX)).thenReturn(100.0);
+    }
+
+    @Test
+    public void testTimerBasedModel() {
+        setDurationsAndPower(
+                mMockBatteryStats.getUidStatsLocked(Process.BLUETOOTH_UID)
+                        .getOrCreateBluetoothControllerActivityLocked(),
+                1000, 2000, 3000, 0);
+
+        setDurationsAndPower(mMockBatteryStats.getUidStatsLocked(APP_UID)
+                        .getOrCreateBluetoothControllerActivityLocked(),
+                4000, 5000, 6000, 0);
+
+        setDurationsAndPower((BatteryStatsImpl.ControllerActivityCounterImpl)
+                        mMockBatteryStats.getBluetoothControllerActivity(),
+                6000, 8000, 10000, 0);
+
+        BatteryUsageStats batteryUsageStats = buildBatteryUsageStats();
+
+        assertBluetoothPowerAndDuration(
+                getUidBatteryConsumer(batteryUsageStats, Process.BLUETOOTH_UID),
+                0.11388, 6000);
+        assertBluetoothPowerAndDuration(
+                getUidBatteryConsumer(batteryUsageStats, APP_UID),
+                0.24722, 15000);
+        assertBluetoothPowerAndDuration(
+                getBluetoothSystemBatteryConsumer(batteryUsageStats,
+                        SystemBatteryConsumer.DRAIN_TYPE_BLUETOOTH),
+                0.15833, 9000);
+    }
+
+    @Test
+    public void testReportedPowerBasedModel() {
+        setDurationsAndPower(
+                mMockBatteryStats.getUidStatsLocked(Process.BLUETOOTH_UID)
+                        .getOrCreateBluetoothControllerActivityLocked(),
+                1000, 2000, 3000, 360000);
+
+        setDurationsAndPower(mMockBatteryStats.getUidStatsLocked(APP_UID)
+                        .getOrCreateBluetoothControllerActivityLocked(),
+                4000, 5000, 6000, 720000);
+
+        setDurationsAndPower((BatteryStatsImpl.ControllerActivityCounterImpl)
+                        mMockBatteryStats.getBluetoothControllerActivity(),
+                6000, 8000, 10000, 1260000);
+
+        BatteryUsageStats batteryUsageStats = buildBatteryUsageStats();
+
+        assertBluetoothPowerAndDuration(
+                getUidBatteryConsumer(batteryUsageStats, Process.BLUETOOTH_UID),
+                0.1, 6000);
+        assertBluetoothPowerAndDuration(
+                getUidBatteryConsumer(batteryUsageStats, APP_UID),
+                0.2, 15000);
+        assertBluetoothPowerAndDuration(
+                getBluetoothSystemBatteryConsumer(batteryUsageStats,
+                        SystemBatteryConsumer.DRAIN_TYPE_BLUETOOTH),
+                0.15, 9000);
+    }
+
+    private void setDurationsAndPower(
+            BatteryStatsImpl.ControllerActivityCounterImpl controllerActivity, int idleDurationMs,
+            int rxDurationMs, int txDurationMs, long powerMaMs) {
+        controllerActivity.getIdleTimeCounter().addCountLocked(idleDurationMs);
+        controllerActivity.getRxTimeCounter().addCountLocked(rxDurationMs);
+        controllerActivity.getTxTimeCounters()[0].addCountLocked(txDurationMs);
+        controllerActivity.getPowerCounter().addCountLocked(powerMaMs);
+    }
+
+    private BatteryUsageStats buildBatteryUsageStats() {
+        BatteryUsageStats.Builder builder = new BatteryUsageStats.Builder(0, 0, false);
+        builder.getOrCreateUidBatteryConsumerBuilder(
+                mMockBatteryStats.getUidStatsLocked(Process.BLUETOOTH_UID));
+        builder.getOrCreateUidBatteryConsumerBuilder(
+                mMockBatteryStats.getUidStatsLocked(APP_UID));
+
+        BluetoothPowerCalculator bpc = new BluetoothPowerCalculator(mMockPowerProfile);
+        bpc.calculate(builder, mMockBatteryStats, 200_000, 200_000, BatteryUsageStatsQuery.DEFAULT,
+                null);
+        return builder.build();
+    }
+
+    private UidBatteryConsumer getUidBatteryConsumer(BatteryUsageStats batteryUsageStats, int uid) {
+        for (UidBatteryConsumer ubc : batteryUsageStats.getUidBatteryConsumers()) {
+            if (ubc.getUid() == uid) {
+                return ubc;
+            }
+        }
+        return null;
+    }
+
+    private SystemBatteryConsumer getBluetoothSystemBatteryConsumer(
+            BatteryUsageStats batteryUsageStats, int drainType) {
+        for (SystemBatteryConsumer sbc : batteryUsageStats.getSystemBatteryConsumers()) {
+            if (sbc.getDrainType() == drainType) {
+                return sbc;
+            }
+        }
+        return null;
+    }
+
+    private void assertBluetoothPowerAndDuration(@Nullable BatteryConsumer batteryConsumer,
+            double powerMah, int durationMs) {
+        assertThat(batteryConsumer).isNotNull();
+
+        double consumedPower = batteryConsumer.getConsumedPower(
+                BatteryConsumer.POWER_COMPONENT_BLUETOOTH);
+        assertThat(consumedPower).isWithin(PRECISION).of(powerMah);
+
+        long usageDurationMillis = batteryConsumer.getUsageDurationMillis(
+                BatteryConsumer.TIME_COMPONENT_BLUETOOTH);
+
+        assertThat(usageDurationMillis).isEqualTo(durationMs);
+    }
+}
diff --git a/core/tests/coretests/src/com/android/internal/os/KernelSingleProcessCpuThreadReaderTest.java b/core/tests/coretests/src/com/android/internal/os/KernelSingleProcessCpuThreadReaderTest.java
index 2de800b..b5720a2 100644
--- a/core/tests/coretests/src/com/android/internal/os/KernelSingleProcessCpuThreadReaderTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/KernelSingleProcessCpuThreadReaderTest.java
@@ -19,87 +19,122 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
+import static org.junit.Assert.assertTrue;
+
+import android.content.Context;
+import android.os.FileUtils;
+
+import androidx.test.InstrumentationRegistry;
 import androidx.test.filters.SmallTest;
 import androidx.test.runner.AndroidJUnit4;
 
+import org.junit.After;
+import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
+import java.io.File;
 import java.io.IOException;
-import java.util.ArrayList;
-import java.util.List;
+import java.io.OutputStream;
+import java.nio.file.Files;
+import java.nio.file.Path;
 
 @SmallTest
 @RunWith(AndroidJUnit4.class)
 public class KernelSingleProcessCpuThreadReaderTest {
 
+    private File mProcDirectory;
+
+    @Before
+    public void setUp() {
+        Context context = InstrumentationRegistry.getContext();
+        mProcDirectory = context.getDir("proc", Context.MODE_PRIVATE);
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        FileUtils.deleteContents(mProcDirectory);
+    }
+
     @Test
     public void getProcessCpuUsage() throws IOException {
-        // Units are nanoseconds
-        MockCpuTimeInStateReader mockReader = new MockCpuTimeInStateReader(4, new String[] {
-                "0:1000000000 2000000000 3000000000:4000000000",
-                "1:100000000 200000000 300000000:400000000",
-        });
+        setupDirectory(42,
+                new int[] {42, 1, 2, 3},
+                new int[] {1000, 2000},
+                // Units are 10ms aka 10000Us
+                new int[][] {{100, 200}, {0, 200}, {100, 300}, {0, 600}},
+                new int[] {4500, 500});
 
         KernelSingleProcessCpuThreadReader reader = new KernelSingleProcessCpuThreadReader(42,
-                mockReader);
-        reader.setSelectedThreadIds(new int[] {2, 3});
-        reader.startTrackingThreadCpuTimes();
+                mProcDirectory.toPath());
         KernelSingleProcessCpuThreadReader.ProcessCpuUsage processCpuUsage =
-                reader.getProcessCpuUsage();
-        assertThat(mockReader.mTrackedTgid).isEqualTo(42);
-        // The strings are formatted as <TID TGID AGG_KEY>, where AGG_KEY is 1 for binder
-        // threads and 0 for all other threads.
-        assertThat(mockReader.mTrackedTasks).containsExactly(
-                "2 1",
-                "3 1");
-        assertThat(processCpuUsage.threadCpuTimesMillis).isEqualTo(
-                new long[] {1100, 2200, 3300, 4400});
-        assertThat(processCpuUsage.selectedThreadCpuTimesMillis).isEqualTo(
-                new long[] {100, 200, 300, 400});
+                reader.getProcessCpuUsage(new int[] {2, 3});
+        assertThat(processCpuUsage.threadCpuTimesMillis).isEqualTo(new long[] {2000, 13000});
+        assertThat(processCpuUsage.selectedThreadCpuTimesMillis).isEqualTo(new long[] {1000, 9000});
+        assertThat(processCpuUsage.processCpuTimesMillis).isEqualTo(new long[] {6666, 43333});
     }
 
     @Test
     public void getCpuFrequencyCount() throws IOException {
-        MockCpuTimeInStateReader mockReader = new MockCpuTimeInStateReader(3, new String[0]);
+        setupDirectory(13,
+                new int[] {13},
+                new int[] {1000, 2000, 3000},
+                new int[][] {{100, 200, 300}},
+                new int[] {14, 15});
 
         KernelSingleProcessCpuThreadReader reader = new KernelSingleProcessCpuThreadReader(13,
-                mockReader);
+                mProcDirectory.toPath());
         int cpuFrequencyCount = reader.getCpuFrequencyCount();
         assertThat(cpuFrequencyCount).isEqualTo(3);
     }
 
-    public static class MockCpuTimeInStateReader implements
-            KernelSingleProcessCpuThreadReader.CpuTimeInStateReader {
-        private final int mCpuFrequencyCount;
-        private final String[] mAggregatedTaskCpuFreqTimes;
-        public int mTrackedTgid;
-        public List<String> mTrackedTasks = new ArrayList<>();
+    private void setupDirectory(int pid, int[] threadIds, int[] cpuFrequencies,
+            int[][] threadCpuTimes, int[] processCpuTimes)
+            throws IOException {
 
-        public MockCpuTimeInStateReader(int cpuFrequencyCount,
-                String[] aggregatedTaskCpuFreqTimes) {
-            mCpuFrequencyCount = cpuFrequencyCount;
-            mAggregatedTaskCpuFreqTimes = aggregatedTaskCpuFreqTimes;
+        assertTrue(mProcDirectory.toPath().resolve("self").toFile().mkdirs());
+
+        try (OutputStream timeInStateStream =
+                     Files.newOutputStream(
+                             mProcDirectory.toPath().resolve("self").resolve("time_in_state"))) {
+            for (int i = 0; i < cpuFrequencies.length; i++) {
+                final String line = cpuFrequencies[i] + " 0\n";
+                timeInStateStream.write(line.getBytes());
+            }
         }
 
-        @Override
-        public int getCpuFrequencyCount() {
-            return mCpuFrequencyCount;
+        Path processPath = mProcDirectory.toPath().resolve(String.valueOf(pid));
+
+        // Make /proc/$PID
+        assertTrue(processPath.toFile().mkdirs());
+
+        // Write /proc/$PID/stat. Only the fields 14-17 matter.
+        try (OutputStream timeInStateStream = Files.newOutputStream(processPath.resolve("stat"))) {
+            timeInStateStream.write(
+                    (pid + " (test) S 4 5 6 7 8 9 10 11 12 13 "
+                            + processCpuTimes[0] + " "
+                            + processCpuTimes[1] + " "
+                            + "16 17 18 19 20 ...").getBytes());
         }
 
-        @Override
-        public boolean startTrackingProcessCpuTimes(int tgid) {
-            mTrackedTgid = tgid;
-            return true;
-        }
+        // Make /proc/$PID/task
+        final Path selfThreadsPath = processPath.resolve("task");
+        assertTrue(selfThreadsPath.toFile().mkdirs());
 
-        public boolean startAggregatingTaskCpuTimes(int pid, int aggregationKey) {
-            mTrackedTasks.add(pid + " " + aggregationKey);
-            return true;
-        }
+        // Make thread directories
+        for (int i = 0; i < threadIds.length; i++) {
+            // Make /proc/$PID/task/$TID
+            final Path threadPath = selfThreadsPath.resolve(String.valueOf(threadIds[i]));
+            assertTrue(threadPath.toFile().mkdirs());
 
-        public String[] getAggregatedTaskCpuFreqTimes(int pid) {
-            return mAggregatedTaskCpuFreqTimes;
+            // Make /proc/$PID/task/$TID/time_in_state
+            try (OutputStream timeInStateStream =
+                         Files.newOutputStream(threadPath.resolve("time_in_state"))) {
+                for (int j = 0; j < cpuFrequencies.length; j++) {
+                    final String line = cpuFrequencies[j] + " " + threadCpuTimes[i][j] + "\n";
+                    timeInStateStream.write(line.getBytes());
+                }
+            }
         }
     }
 }
diff --git a/core/tests/coretests/src/com/android/internal/os/MockBatteryStatsImpl.java b/core/tests/coretests/src/com/android/internal/os/MockBatteryStatsImpl.java
index 1b1590a..c775137 100644
--- a/core/tests/coretests/src/com/android/internal/os/MockBatteryStatsImpl.java
+++ b/core/tests/coretests/src/com/android/internal/os/MockBatteryStatsImpl.java
@@ -47,6 +47,7 @@
         mScreenDozeTimer = new BatteryStatsImpl.StopwatchTimer(clocks, null, -1, null,
                 mOnBatteryTimeBase);
         mBluetoothScanTimer = new StopwatchTimer(mClocks, null, -14, null, mOnBatteryTimeBase);
+        mBluetoothActivity = new ControllerActivityCounterImpl(mOnBatteryTimeBase, 1);
         setExternalStatsSyncLocked(new DummyExternalStatsSync());
 
         for (int i = 0; i < GnssSignalQuality.NUM_GNSS_SIGNAL_QUALITY_LEVELS; i++) {
diff --git a/core/tests/coretests/src/com/android/internal/os/SystemServerCpuThreadReaderTest.java b/core/tests/coretests/src/com/android/internal/os/SystemServerCpuThreadReaderTest.java
index d116d4d..121c637 100644
--- a/core/tests/coretests/src/com/android/internal/os/SystemServerCpuThreadReaderTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/SystemServerCpuThreadReaderTest.java
@@ -16,86 +16,146 @@
 
 package com.android.internal.os;
 
-import static com.google.common.truth.Truth.assertThat;
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertTrue;
 
+import android.content.Context;
+import android.os.FileUtils;
+
+import androidx.test.InstrumentationRegistry;
 import androidx.test.filters.SmallTest;
 import androidx.test.runner.AndroidJUnit4;
 
+import org.junit.After;
+import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
+import java.io.File;
 import java.io.IOException;
+import java.io.OutputStream;
+import java.nio.file.Files;
+import java.nio.file.Path;
 
 @SmallTest
 @RunWith(AndroidJUnit4.class)
 public class SystemServerCpuThreadReaderTest {
+    private File mProcDirectory;
+
+    @Before
+    public void setUp() {
+        Context context = InstrumentationRegistry.getContext();
+        mProcDirectory = context.getDir("proc", Context.MODE_PRIVATE);
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        FileUtils.deleteContents(mProcDirectory);
+    }
 
     @Test
-    public void testReadDelta() throws IOException {
+    public void testReaderDelta_firstTime() throws IOException {
         int pid = 42;
+        setupDirectory(
+                pid,
+                new int[] {42, 1, 2, 3},
+                new int[] {1000, 2000},
+                // Units are 10ms aka 10000Us
+                new int[][] {{100, 200}, {0, 200}, {0, 300}, {0, 400}},
+                new int[] {1400, 1500});
 
-        MockCpuTimeInStateReader mockReader = new MockCpuTimeInStateReader(4);
-        // Units are nanoseconds
-        mockReader.setAggregatedTaskCpuFreqTimes(new String[] {
-                "0:1000000000 2000000000 3000000000:4000000000",
-                "1:100000000 200000000 300000000:400000000",
-        });
+        SystemServerCpuThreadReader reader = new SystemServerCpuThreadReader(
+                mProcDirectory.toPath(), pid);
+        reader.setBinderThreadNativeTids(new int[] {1, 3});
+        SystemServerCpuThreadReader.SystemServiceCpuThreadTimes systemServiceCpuThreadTimes =
+                reader.readDelta();
+        assertArrayEquals(new long[] {100 * 10000, 1100 * 10000},
+                systemServiceCpuThreadTimes.threadCpuTimesUs);
+        assertArrayEquals(new long[] {0, 600 * 10000},
+                systemServiceCpuThreadTimes.binderThreadCpuTimesUs);
+    }
 
-        SystemServerCpuThreadReader reader = new SystemServerCpuThreadReader(pid, mockReader);
+    @Test
+    public void testReaderDelta_nextTime() throws IOException {
+        int pid = 42;
+        setupDirectory(
+                pid,
+                new int[] {42, 1, 2, 3},
+                new int[] {1000, 2000},
+                new int[][] {{100, 200}, {0, 200}, {0, 300}, {0, 400}},
+                new int[] {1400, 1500});
+
+        SystemServerCpuThreadReader reader = new SystemServerCpuThreadReader(
+                mProcDirectory.toPath(), pid);
         reader.setBinderThreadNativeTids(new int[] {1, 3});
 
-        // The first invocation of readDelta populates the "last" snapshot
+        // First time, populate "last" snapshot
+        reader.readDelta();
+
+        FileUtils.deleteContents(mProcDirectory);
+        setupDirectory(
+                pid,
+                new int[] {42, 1, 2, 3},
+                new int[] {1000, 2000},
+                new int[][] {{500, 600}, {700, 800}, {900, 1000}, {1100, 1200}},
+                new int[] {2400, 2500});
+
+        // Second time, get the actual delta
         SystemServerCpuThreadReader.SystemServiceCpuThreadTimes systemServiceCpuThreadTimes =
                 reader.readDelta();
 
-        assertThat(systemServiceCpuThreadTimes.threadCpuTimesUs)
-                .isEqualTo(new long[] {1100000, 2200000, 3300000, 4400000});
-        assertThat(systemServiceCpuThreadTimes.binderThreadCpuTimesUs)
-                .isEqualTo(new long[] {100000, 200000, 300000, 400000});
-
-        mockReader.setAggregatedTaskCpuFreqTimes(new String[] {
-                "0:1010000000 2020000000 3030000000:4040000000",
-                "1:101000000 202000000 303000000:404000000",
-        });
-
-        // The second invocation gets the actual delta
-        systemServiceCpuThreadTimes = reader.readDelta();
-
-        assertThat(systemServiceCpuThreadTimes.threadCpuTimesUs)
-                .isEqualTo(new long[] {11000, 22000, 33000, 44000});
-        assertThat(systemServiceCpuThreadTimes.binderThreadCpuTimesUs)
-                .isEqualTo(new long[] {1000, 2000, 3000, 4000});
+        assertArrayEquals(new long[] {3100 * 10000, 2500 * 10000},
+                systemServiceCpuThreadTimes.threadCpuTimesUs);
+        assertArrayEquals(new long[] {1800 * 10000, 1400 * 10000},
+                systemServiceCpuThreadTimes.binderThreadCpuTimesUs);
     }
 
-    public static class MockCpuTimeInStateReader implements
-            KernelSingleProcessCpuThreadReader.CpuTimeInStateReader {
-        private final int mCpuFrequencyCount;
-        private String[] mAggregatedTaskCpuFreqTimes;
+    private void setupDirectory(int pid, int[] threadIds, int[] cpuFrequencies, int[][] cpuTimes,
+            int[] processCpuTimes)
+            throws IOException {
 
-        MockCpuTimeInStateReader(int frequencyCount) {
-            mCpuFrequencyCount = frequencyCount;
+        assertTrue(mProcDirectory.toPath().resolve("self").toFile().mkdirs());
+
+        try (OutputStream timeInStateStream =
+                     Files.newOutputStream(
+                             mProcDirectory.toPath().resolve("self").resolve("time_in_state"))) {
+            for (int i = 0; i < cpuFrequencies.length; i++) {
+                final String line = cpuFrequencies[i] + " 0\n";
+                timeInStateStream.write(line.getBytes());
+            }
         }
 
-        @Override
-        public int getCpuFrequencyCount() {
-            return mCpuFrequencyCount;
+        Path processPath = mProcDirectory.toPath().resolve(String.valueOf(pid));
+        // Make /proc/$PID
+        assertTrue(processPath.toFile().mkdirs());
+
+        // Write /proc/$PID/stat. Only the fields 14-17 matter.
+        try (OutputStream timeInStateStream = Files.newOutputStream(processPath.resolve("stat"))) {
+            timeInStateStream.write(
+                    (pid + " (test) S 4 5 6 7 8 9 10 11 12 13 "
+                            + processCpuTimes[0] + " "
+                            + processCpuTimes[1] + " "
+                            + "16 17 18 19 20 ...").getBytes());
         }
 
-        @Override
-        public boolean startTrackingProcessCpuTimes(int tgid) {
-            return true;
-        }
+        // Make /proc/$PID/task
+        final Path selfThreadsPath = processPath.resolve("task");
+        assertTrue(selfThreadsPath.toFile().mkdirs());
 
-        public boolean startAggregatingTaskCpuTimes(int pid, int aggregationKey) {
-            return true;
-        }
+        // Make thread directories
+        for (int i = 0; i < threadIds.length; i++) {
+            // Make /proc/$PID/task/$TID
+            final Path threadPath = selfThreadsPath.resolve(String.valueOf(threadIds[i]));
+            assertTrue(threadPath.toFile().mkdirs());
 
-        public void setAggregatedTaskCpuFreqTimes(String[] mAggregatedTaskCpuFreqTimes) {
-            this.mAggregatedTaskCpuFreqTimes = mAggregatedTaskCpuFreqTimes;
-        }
-
-        public String[] getAggregatedTaskCpuFreqTimes(int pid) {
-            return mAggregatedTaskCpuFreqTimes;
+            // Make /proc/$PID/task/$TID/time_in_state
+            try (OutputStream timeInStateStream =
+                         Files.newOutputStream(threadPath.resolve("time_in_state"))) {
+                for (int j = 0; j < cpuFrequencies.length; j++) {
+                    final String line = cpuFrequencies[j] + " " + cpuTimes[i][j] + "\n";
+                    timeInStateStream.write(line.getBytes());
+                }
+            }
         }
     }
 }
diff --git a/core/tests/coretests/src/com/android/internal/os/SystemServicePowerCalculatorTest.java b/core/tests/coretests/src/com/android/internal/os/SystemServicePowerCalculatorTest.java
index c8e8585..dbb36fb 100644
--- a/core/tests/coretests/src/com/android/internal/os/SystemServicePowerCalculatorTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/SystemServicePowerCalculatorTest.java
@@ -66,6 +66,7 @@
     public void testCalculateApp() {
         // Test Power Profile has two CPU clusters with 3 and 4 speeds, thus 7 freq times total
         mMockSystemServerCpuThreadReader.setCpuTimes(
+                new long[] {10000, 15000, 20000, 25000, 30000, 35000, 40000},
                 new long[] {30000, 40000, 50000, 60000, 70000, 80000, 90000},
                 new long[] {20000, 30000, 40000, 50000, 60000, 70000, 80000});
 
@@ -145,7 +146,9 @@
             super(null);
         }
 
-        public void setCpuTimes(long[] threadCpuTimesUs, long[] binderThreadCpuTimesUs) {
+        public void setCpuTimes(long[] processCpuTimesUs, long[] threadCpuTimesUs,
+                long[] binderThreadCpuTimesUs) {
+            mThreadTimes.processCpuTimesUs = processCpuTimesUs;
             mThreadTimes.threadCpuTimesUs = threadCpuTimesUs;
             mThreadTimes.binderThreadCpuTimesUs = binderThreadCpuTimesUs;
         }
diff --git a/core/tests/hdmitests/src/android/hardware/hdmi/HdmiAudioSystemClientTest.java b/core/tests/hdmitests/src/android/hardware/hdmi/HdmiAudioSystemClientTest.java
index 306388f..9531181d 100644
--- a/core/tests/hdmitests/src/android/hardware/hdmi/HdmiAudioSystemClientTest.java
+++ b/core/tests/hdmitests/src/android/hardware/hdmi/HdmiAudioSystemClientTest.java
@@ -195,6 +195,11 @@
         }
 
         @Override
+        public boolean shouldHandleTvPowerKey() {
+            return false;
+        }
+
+        @Override
         public void queryDisplayStatus(final IHdmiControlCallback callback) {
         }
 
diff --git a/data/etc/services.core.protolog.json b/data/etc/services.core.protolog.json
index d8a735c..faf4973 100644
--- a/data/etc/services.core.protolog.json
+++ b/data/etc/services.core.protolog.json
@@ -901,6 +901,12 @@
       "group": "WM_DEBUG_ORIENTATION",
       "at": "com\/android\/server\/wm\/WindowManagerService.java"
     },
+    "-1069336896": {
+      "message": "onRootTaskOrderChanged(): rootTask=%s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_RECENTS_ANIMATIONS",
+      "at": "com\/android\/server\/wm\/RecentsAnimation.java"
+    },
     "-1066383762": {
       "message": "Sleep still waiting to pause %s",
       "level": "VERBOSE",
@@ -1303,6 +1309,12 @@
       "group": "WM_DEBUG_CONFIGURATION",
       "at": "com\/android\/server\/am\/ActivityManagerService.java"
     },
+    "-592371899": {
+      "message": "Skipping rootTask: (mismatch activity\/rootTask) %s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_TASKS",
+      "at": "com\/android\/server\/wm\/TaskDisplayArea.java"
+    },
     "-583031528": {
       "message": "%s",
       "level": "INFO",
@@ -2119,12 +2131,6 @@
       "group": "WM_DEBUG_APP_TRANSITIONS",
       "at": "com\/android\/server\/wm\/AppTransition.java"
     },
-    "349443311": {
-      "message": "pauseBackStacks: task=%s mResumedActivity=%s",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_STATES",
-      "at": "com\/android\/server\/wm\/TaskDisplayArea.java"
-    },
     "355720268": {
       "message": "stopFreezingDisplayLocked: Unfreezing now",
       "level": "DEBUG",
@@ -2161,6 +2167,12 @@
       "group": "WM_DEBUG_BOOT",
       "at": "com\/android\/server\/wm\/WindowManagerService.java"
     },
+    "391189028": {
+      "message": "pauseBackTasks: task=%s mResumedActivity=%s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_STATES",
+      "at": "com\/android\/server\/wm\/TaskDisplayArea.java"
+    },
     "397105698": {
       "message": "grantEmbeddedWindowFocus remove request for win=%s dropped since no candidate was found",
       "level": "VERBOSE",
@@ -2245,12 +2257,6 @@
       "group": "WM_DEBUG_WINDOW_ORGANIZER",
       "at": "com\/android\/server\/wm\/DisplayAreaOrganizerController.java"
     },
-    "490877640": {
-      "message": "onStackOrderChanged(): stack=%s",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_RECENTS_ANIMATIONS",
-      "at": "com\/android\/server\/wm\/RecentsAnimation.java"
-    },
     "495032901": {
       "message": "Expected target stack=%s to restored behind stack=%s but it is behind stack=%s",
       "level": "WARN",
@@ -2575,12 +2581,6 @@
       "group": "WM_DEBUG_REMOTE_ANIMATIONS",
       "at": "com\/android\/server\/wm\/RemoteAnimationController.java"
     },
-    "875196661": {
-      "message": "Skipping stack: (mismatch activity\/stack) %s",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_TASKS",
-      "at": "com\/android\/server\/wm\/TaskDisplayArea.java"
-    },
     "883475718": {
       "message": "Report configuration: %s %s %s",
       "level": "VERBOSE",
diff --git a/data/keyboards/Generic.kl b/data/keyboards/Generic.kl
index 6ac73b1..bd0e56a 100644
--- a/data/keyboards/Generic.kl
+++ b/data/keyboards/Generic.kl
@@ -445,3 +445,11 @@
 led 0x08 MISC
 led 0x09 MAIL
 led 0x0a CHARGING
+
+# SENSORs
+sensor 0x00 ACCELEROMETER X
+sensor 0x01 ACCELEROMETER Y
+sensor 0x02 ACCELEROMETER Z
+sensor 0x03 GYROSCOPE X
+sensor 0x04 GYROSCOPE Y
+sensor 0x05 GYROSCOPE Z
diff --git a/data/keyboards/Vendor_054c_Product_05c4.idc b/data/keyboards/Vendor_054c_Product_05c4.idc
new file mode 100644
index 0000000..2cb3f7b
--- /dev/null
+++ b/data/keyboards/Vendor_054c_Product_05c4.idc
@@ -0,0 +1,35 @@
+# 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.
+
+#
+# Sony DS4 motion sensor configuration file.
+#
+
+# reporting mode 0 - continuous
+sensor.accelerometer.reportingMode = 0
+# The delay between sensor events corresponding to the lowest frequency in microsecond
+sensor.accelerometer.maxDelay = 100000
+# The minimum delay allowed between two events in microsecond
+sensor.accelerometer.minDelay = 5000
+# The power in mA used by this sensor while in use
+sensor.accelerometer.power = 1.5
+
+# reporting mode 0 - continuous
+sensor.gyroscope.reportingMode = 0
+# The delay between sensor events corresponding to the lowest frequency in microsecond
+sensor.gyroscope.maxDelay = 100000
+# The minimum delay allowed between two events in microsecond
+sensor.gyroscope.minDelay = 5000
+# The power in mA used by this sensor while in use
+sensor.gyroscope.power = 0.8
diff --git a/data/keyboards/Vendor_054c_Product_05c4.kl b/data/keyboards/Vendor_054c_Product_05c4.kl
index cd7ab1f..c8b4fc3 100644
--- a/data/keyboards/Vendor_054c_Product_05c4.kl
+++ b/data/keyboards/Vendor_054c_Product_05c4.kl
@@ -68,3 +68,11 @@
 # and this button will be equivalent to left mouse button
 # Therefore, map it to KEYCODE_BUTTON_1 here to allow apps to still handle this on earlier versions
 key 0x13d   BUTTON_1
+
+# SENSORs
+sensor 0x00 ACCELEROMETER X
+sensor 0x01 ACCELEROMETER Y
+sensor 0x02 ACCELEROMETER Z
+sensor 0x03 GYROSCOPE X
+sensor 0x04 GYROSCOPE Y
+sensor 0x05 GYROSCOPE Z
diff --git a/data/keyboards/Vendor_054c_Product_05c4_Version_8000.kl b/data/keyboards/Vendor_054c_Product_05c4_Version_8000.kl
index 19fcb86..a877c4c 100644
--- a/data/keyboards/Vendor_054c_Product_05c4_Version_8000.kl
+++ b/data/keyboards/Vendor_054c_Product_05c4_Version_8000.kl
@@ -66,3 +66,11 @@
 
 # In kernel versions >= 4.10, the touchpad is a separate input device,
 # so the touchpad button click will not be covered by this layout.
+
+# SENSORs
+sensor 0x00 ACCELEROMETER X
+sensor 0x01 ACCELEROMETER Y
+sensor 0x02 ACCELEROMETER Z
+sensor 0x03 GYROSCOPE X
+sensor 0x04 GYROSCOPE Y
+sensor 0x05 GYROSCOPE Z
diff --git a/data/keyboards/Vendor_054c_Product_05c4_Version_8100.kl b/data/keyboards/Vendor_054c_Product_05c4_Version_8100.kl
index 19fcb86..a877c4c 100644
--- a/data/keyboards/Vendor_054c_Product_05c4_Version_8100.kl
+++ b/data/keyboards/Vendor_054c_Product_05c4_Version_8100.kl
@@ -66,3 +66,11 @@
 
 # In kernel versions >= 4.10, the touchpad is a separate input device,
 # so the touchpad button click will not be covered by this layout.
+
+# SENSORs
+sensor 0x00 ACCELEROMETER X
+sensor 0x01 ACCELEROMETER Y
+sensor 0x02 ACCELEROMETER Z
+sensor 0x03 GYROSCOPE X
+sensor 0x04 GYROSCOPE Y
+sensor 0x05 GYROSCOPE Z
diff --git a/data/keyboards/Vendor_054c_Product_05c4_Version_8111.kl b/data/keyboards/Vendor_054c_Product_05c4_Version_8111.kl
index d38bdec..1473c4e 100644
--- a/data/keyboards/Vendor_054c_Product_05c4_Version_8111.kl
+++ b/data/keyboards/Vendor_054c_Product_05c4_Version_8111.kl
@@ -66,3 +66,11 @@
 
 # In kernel versions >= 4.10, the touchpad is a separate input device,
 # so the touchpad button click will not be covered by this layout.
+
+# SENSORs
+sensor 0x00 ACCELEROMETER X
+sensor 0x01 ACCELEROMETER Y
+sensor 0x02 ACCELEROMETER Z
+sensor 0x03 GYROSCOPE X
+sensor 0x04 GYROSCOPE Y
+sensor 0x05 GYROSCOPE Z
diff --git a/data/keyboards/Vendor_054c_Product_09cc.idc b/data/keyboards/Vendor_054c_Product_09cc.idc
new file mode 100644
index 0000000..2cb3f7b
--- /dev/null
+++ b/data/keyboards/Vendor_054c_Product_09cc.idc
@@ -0,0 +1,35 @@
+# 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.
+
+#
+# Sony DS4 motion sensor configuration file.
+#
+
+# reporting mode 0 - continuous
+sensor.accelerometer.reportingMode = 0
+# The delay between sensor events corresponding to the lowest frequency in microsecond
+sensor.accelerometer.maxDelay = 100000
+# The minimum delay allowed between two events in microsecond
+sensor.accelerometer.minDelay = 5000
+# The power in mA used by this sensor while in use
+sensor.accelerometer.power = 1.5
+
+# reporting mode 0 - continuous
+sensor.gyroscope.reportingMode = 0
+# The delay between sensor events corresponding to the lowest frequency in microsecond
+sensor.gyroscope.maxDelay = 100000
+# The minimum delay allowed between two events in microsecond
+sensor.gyroscope.minDelay = 5000
+# The power in mA used by this sensor while in use
+sensor.gyroscope.power = 0.8
diff --git a/data/keyboards/Vendor_054c_Product_09cc.kl b/data/keyboards/Vendor_054c_Product_09cc.kl
index cd7ab1f..c8b4fc3 100644
--- a/data/keyboards/Vendor_054c_Product_09cc.kl
+++ b/data/keyboards/Vendor_054c_Product_09cc.kl
@@ -68,3 +68,11 @@
 # and this button will be equivalent to left mouse button
 # Therefore, map it to KEYCODE_BUTTON_1 here to allow apps to still handle this on earlier versions
 key 0x13d   BUTTON_1
+
+# SENSORs
+sensor 0x00 ACCELEROMETER X
+sensor 0x01 ACCELEROMETER Y
+sensor 0x02 ACCELEROMETER Z
+sensor 0x03 GYROSCOPE X
+sensor 0x04 GYROSCOPE Y
+sensor 0x05 GYROSCOPE Z
diff --git a/data/keyboards/Vendor_054c_Product_09cc_Version_8000.kl b/data/keyboards/Vendor_054c_Product_09cc_Version_8000.kl
index 19fcb86..a877c4c 100644
--- a/data/keyboards/Vendor_054c_Product_09cc_Version_8000.kl
+++ b/data/keyboards/Vendor_054c_Product_09cc_Version_8000.kl
@@ -66,3 +66,11 @@
 
 # In kernel versions >= 4.10, the touchpad is a separate input device,
 # so the touchpad button click will not be covered by this layout.
+
+# SENSORs
+sensor 0x00 ACCELEROMETER X
+sensor 0x01 ACCELEROMETER Y
+sensor 0x02 ACCELEROMETER Z
+sensor 0x03 GYROSCOPE X
+sensor 0x04 GYROSCOPE Y
+sensor 0x05 GYROSCOPE Z
diff --git a/data/keyboards/Vendor_054c_Product_09cc_Version_8100.kl b/data/keyboards/Vendor_054c_Product_09cc_Version_8100.kl
index 19fcb86..a877c4c 100644
--- a/data/keyboards/Vendor_054c_Product_09cc_Version_8100.kl
+++ b/data/keyboards/Vendor_054c_Product_09cc_Version_8100.kl
@@ -66,3 +66,11 @@
 
 # In kernel versions >= 4.10, the touchpad is a separate input device,
 # so the touchpad button click will not be covered by this layout.
+
+# SENSORs
+sensor 0x00 ACCELEROMETER X
+sensor 0x01 ACCELEROMETER Y
+sensor 0x02 ACCELEROMETER Z
+sensor 0x03 GYROSCOPE X
+sensor 0x04 GYROSCOPE Y
+sensor 0x05 GYROSCOPE Z
diff --git a/data/keyboards/Vendor_054c_Product_09cc_Version_8111.kl b/data/keyboards/Vendor_054c_Product_09cc_Version_8111.kl
index d38bdec..1473c4e 100644
--- a/data/keyboards/Vendor_054c_Product_09cc_Version_8111.kl
+++ b/data/keyboards/Vendor_054c_Product_09cc_Version_8111.kl
@@ -66,3 +66,11 @@
 
 # In kernel versions >= 4.10, the touchpad is a separate input device,
 # so the touchpad button click will not be covered by this layout.
+
+# SENSORs
+sensor 0x00 ACCELEROMETER X
+sensor 0x01 ACCELEROMETER Y
+sensor 0x02 ACCELEROMETER Z
+sensor 0x03 GYROSCOPE X
+sensor 0x04 GYROSCOPE Y
+sensor 0x05 GYROSCOPE Z
diff --git a/data/keyboards/keyboards.mk b/data/keyboards/keyboards.mk
index 68cbd29..c7ce8cd 100644
--- a/data/keyboards/keyboards.mk
+++ b/data/keyboards/keyboards.mk
@@ -14,13 +14,9 @@
 
 # Warning: this is actually a product definition, to be inherited from
 
-include $(LOCAL_PATH)/common.mk
+PRODUCT_COPY_FILES := \
+  $(call find-copy-subdir-files,*.kl,$(LOCAL_PATH),system/usr/keylayout) \
+  $(call find-copy-subdir-files,*.kcm,$(LOCAL_PATH),system/usr/keychars) \
+  $(call find-copy-subdir-files,*.idc,$(LOCAL_PATH),system/usr/idc)
 
-PRODUCT_COPY_FILES := $(foreach file,$(framework_keylayouts),\
-    $(file):system/usr/keylayout/$(notdir $(file)))
 
-PRODUCT_COPY_FILES += $(foreach file,$(framework_keycharmaps),\
-    $(file):system/usr/keychars/$(notdir $(file)))
-
-PRODUCT_COPY_FILES += $(foreach file,$(framework_keyconfigs),\
-    $(file):system/usr/idc/$(notdir $(file)))
diff --git a/keystore/java/android/security/keystore2/AndroidKeyStore3DESCipherSpi.java b/keystore/java/android/security/keystore2/AndroidKeyStore3DESCipherSpi.java
index 0775a1a..56f7ea8 100644
--- a/keystore/java/android/security/keystore2/AndroidKeyStore3DESCipherSpi.java
+++ b/keystore/java/android/security/keystore2/AndroidKeyStore3DESCipherSpi.java
@@ -41,7 +41,7 @@
  *
  * @hide
  */
-public class AndroidKeyStore3DESCipherSpi extends AndroidKeyStoreCipherSpiBase {
+public abstract class AndroidKeyStore3DESCipherSpi extends AndroidKeyStoreCipherSpiBase {
 
     private static final int BLOCK_SIZE_BYTES = 8;
 
@@ -73,12 +73,22 @@
             public NoPadding() {
                 super(KeymasterDefs.KM_PAD_NONE);
             }
+
+            @Override
+            protected final String getTransform() {
+                return "DESede/ECB/NoPadding";
+            }
         }
 
         public static class PKCS7Padding extends ECB {
             public PKCS7Padding() {
                 super(KeymasterDefs.KM_PAD_PKCS7);
             }
+
+            @Override
+            protected final String getTransform() {
+                return "DESede/ECB/PKCS7Padding";
+            }
         }
     }
 
@@ -91,12 +101,23 @@
             public NoPadding() {
                 super(KeymasterDefs.KM_PAD_NONE);
             }
+
+            @Override
+            protected final String getTransform() {
+                return "DESede/CBC/NoPadding";
+            }
+
         }
 
         public static class PKCS7Padding extends CBC {
             public PKCS7Padding() {
                 super(KeymasterDefs.KM_PAD_PKCS7);
             }
+
+            @Override
+            protected final String getTransform() {
+                return "DESede/CBC/PKCS7Padding";
+            }
         }
     }
 
@@ -288,7 +309,7 @@
         if (parameters != null) {
             for (KeyParameter p : parameters) {
                 if (p.tag == KeymasterDefs.KM_TAG_NONCE) {
-                    returnedIv = p.blob;
+                    returnedIv = p.value.getBlob();
                     break;
                 }
             }
diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreAuthenticatedAESCipherSpi.java b/keystore/java/android/security/keystore2/AndroidKeyStoreAuthenticatedAESCipherSpi.java
index bc56f01..64da837 100644
--- a/keystore/java/android/security/keystore2/AndroidKeyStoreAuthenticatedAESCipherSpi.java
+++ b/keystore/java/android/security/keystore2/AndroidKeyStoreAuthenticatedAESCipherSpi.java
@@ -64,6 +64,11 @@
         }
 
         @Override
+        protected final String getTransform() {
+            return "AES/GCM/NoPadding";
+        }
+
+        @Override
         protected final void resetAll() {
             mTagLengthBits = DEFAULT_TAG_LENGTH_BITS;
             super.resetAll();
@@ -325,7 +330,7 @@
         if (parameters != null) {
             for (KeyParameter p : parameters) {
                 if (p.tag == KeymasterDefs.KM_TAG_NONCE) {
-                    returnedIv = p.blob;
+                    returnedIv = p.value.getBlob();
                     break;
                 }
             }
diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreBCWorkaroundProvider.java b/keystore/java/android/security/keystore2/AndroidKeyStoreBCWorkaroundProvider.java
index dd943d4..9ad6f3a 100644
--- a/keystore/java/android/security/keystore2/AndroidKeyStoreBCWorkaroundProvider.java
+++ b/keystore/java/android/security/keystore2/AndroidKeyStoreBCWorkaroundProvider.java
@@ -254,13 +254,13 @@
     private void putAsymmetricCipherImpl(String transformation, String implClass) {
         put("Cipher." + transformation, implClass);
         put("Cipher." + transformation + " SupportedKeyClasses",
-                KEYSTORE_PRIVATE_KEY_CLASS_NAME + "|" + KEYSTORE_PUBLIC_KEY_CLASS_NAME);
+                KEYSTORE_PRIVATE_KEY_CLASS_NAME);
     }
 
     private void putSignatureImpl(String algorithm, String implClass) {
         put("Signature." + algorithm, implClass);
         put("Signature." + algorithm + " SupportedKeyClasses",
-                KEYSTORE_PRIVATE_KEY_CLASS_NAME + "|" + KEYSTORE_PUBLIC_KEY_CLASS_NAME);
+                KEYSTORE_PRIVATE_KEY_CLASS_NAME);
     }
 
     public static String[] getSupportedEcdsaSignatureDigests() {
diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreCipherSpiBase.java b/keystore/java/android/security/keystore2/AndroidKeyStoreCipherSpiBase.java
index a3b04ab..2ee952c 100644
--- a/keystore/java/android/security/keystore2/AndroidKeyStoreCipherSpiBase.java
+++ b/keystore/java/android/security/keystore2/AndroidKeyStoreCipherSpiBase.java
@@ -43,6 +43,7 @@
 import java.security.SecureRandom;
 import java.security.spec.AlgorithmParameterSpec;
 import java.security.spec.InvalidKeySpecException;
+import java.security.spec.MGF1ParameterSpec;
 import java.security.spec.PKCS8EncodedKeySpec;
 import java.security.spec.X509EncodedKeySpec;
 import java.util.ArrayList;
@@ -57,6 +58,8 @@
 import javax.crypto.SecretKey;
 import javax.crypto.SecretKeyFactory;
 import javax.crypto.ShortBufferException;
+import javax.crypto.spec.OAEPParameterSpec;
+import javax.crypto.spec.PSource;
 import javax.crypto.spec.SecretKeySpec;
 
 /**
@@ -99,6 +102,8 @@
      */
     private Exception mCachedException;
 
+    private Cipher mCipher;
+
     AndroidKeyStoreCipherSpiBase() {
         mOperation = null;
         mEncrypting = false;
@@ -110,6 +115,7 @@
         mAdditionalAuthenticationDataStreamer = null;
         mAdditionalAuthenticationDataStreamerClosed = false;
         mCachedException = null;
+        mCipher = null;
     }
 
     @Override
@@ -117,6 +123,45 @@
             throws InvalidKeyException {
         resetAll();
 
+        if (!(key instanceof AndroidKeyStorePrivateKey
+                || key instanceof AndroidKeyStoreSecretKey)) {
+            try {
+                mCipher = Cipher.getInstance(getTransform());
+                String transform = getTransform();
+
+                if ("RSA/ECB/OAEPWithSHA-224AndMGF1Padding".equals(transform)) {
+                    OAEPParameterSpec spec =
+                            new OAEPParameterSpec("SHA-224", "MGF1",
+                                    new MGF1ParameterSpec("SHA1"), PSource.PSpecified.DEFAULT);
+                    mCipher.init(opmode, key, spec, random);
+                } else if ("RSA/ECB/OAEPWithSHA-256AndMGF1Padding".equals(transform)) {
+                    OAEPParameterSpec spec =
+                            new OAEPParameterSpec("SHA-256", "MGF1",
+                                    new MGF1ParameterSpec("SHA1"), PSource.PSpecified.DEFAULT);
+                    mCipher.init(opmode, key, spec, random);
+
+                } else if ("RSA/ECB/OAEPWithSHA-384AndMGF1Padding".equals(transform)) {
+                    OAEPParameterSpec spec =
+                            new OAEPParameterSpec("SHA-384", "MGF1",
+                                    new MGF1ParameterSpec("SHA1"), PSource.PSpecified.DEFAULT);
+                    mCipher.init(opmode, key, spec, random);
+
+                } else if ("RSA/ECB/OAEPWithSHA-512AndMGF1Padding".equals(transform)) {
+                    OAEPParameterSpec spec =
+                            new OAEPParameterSpec("SHA-512", "MGF1",
+                                    new MGF1ParameterSpec("SHA1"), PSource.PSpecified.DEFAULT);
+                    mCipher.init(opmode, key, spec, random);
+                } else {
+                    mCipher.init(opmode, key, random);
+                }
+                return;
+            } catch (NoSuchAlgorithmException
+                    | NoSuchPaddingException
+                    | InvalidAlgorithmParameterException e) {
+                throw new InvalidKeyException(e);
+            }
+        }
+
         boolean success = false;
         try {
             init(opmode, key, random);
@@ -139,6 +184,17 @@
             SecureRandom random) throws InvalidKeyException, InvalidAlgorithmParameterException {
         resetAll();
 
+        if (!(key instanceof AndroidKeyStorePrivateKey
+                || key instanceof AndroidKeyStoreSecretKey)) {
+            try {
+                mCipher = Cipher.getInstance(getTransform());
+                mCipher.init(opmode, key, params, random);
+                return;
+            } catch (NoSuchAlgorithmException | NoSuchPaddingException e) {
+                throw new InvalidKeyException(e);
+            }
+        }
+
         boolean success = false;
         try {
             init(opmode, key, random);
@@ -157,6 +213,17 @@
             SecureRandom random) throws InvalidKeyException, InvalidAlgorithmParameterException {
         resetAll();
 
+        if (!(key instanceof AndroidKeyStorePrivateKey
+                || key instanceof AndroidKeyStoreSecretKey)) {
+            try {
+                mCipher = Cipher.getInstance(getTransform());
+                mCipher.init(opmode, key, params, random);
+                return;
+            } catch (NoSuchAlgorithmException | NoSuchPaddingException e) {
+                throw new InvalidKeyException(e);
+            }
+        }
+
         boolean success = false;
         try {
             init(opmode, key, random);
@@ -214,6 +281,7 @@
         mAdditionalAuthenticationDataStreamer = null;
         mAdditionalAuthenticationDataStreamerClosed = false;
         mCachedException = null;
+        mCipher = null;
     }
 
     /**
@@ -320,6 +388,10 @@
 
     @Override
     protected final byte[] engineUpdate(byte[] input, int inputOffset, int inputLen) {
+        if (mCipher != null) {
+            return mCipher.update(input, inputOffset, inputLen);
+        }
+
         if (mCachedException != null) {
             return null;
         }
@@ -371,6 +443,9 @@
     @Override
     protected final int engineUpdate(byte[] input, int inputOffset, int inputLen, byte[] output,
             int outputOffset) throws ShortBufferException {
+        if (mCipher != null) {
+            return mCipher.update(input, inputOffset, inputLen, output);
+        }
         byte[] outputCopy = engineUpdate(input, inputOffset, inputLen);
         if (outputCopy == null) {
             return 0;
@@ -387,6 +462,10 @@
     @Override
     protected final int engineUpdate(ByteBuffer input, ByteBuffer output)
             throws ShortBufferException {
+        if (mCipher != null) {
+            return mCipher.update(input, output);
+        }
+
         if (input == null) {
             throw new NullPointerException("input == null");
         }
@@ -423,6 +502,11 @@
 
     @Override
     protected final void engineUpdateAAD(byte[] input, int inputOffset, int inputLen) {
+        if (mCipher != null) {
+            mCipher.updateAAD(input, inputOffset, inputLen);
+            return;
+        }
+
         if (mCachedException != null) {
             return;
         }
@@ -459,6 +543,11 @@
 
     @Override
     protected final void engineUpdateAAD(ByteBuffer src) {
+        if (mCipher != null) {
+            mCipher.updateAAD(src);
+            return;
+        }
+
         if (src == null) {
             throw new IllegalArgumentException("src == null");
         }
@@ -486,6 +575,10 @@
     @Override
     protected final byte[] engineDoFinal(byte[] input, int inputOffset, int inputLen)
             throws IllegalBlockSizeException, BadPaddingException {
+        if (mCipher != null) {
+            return mCipher.doFinal(input, inputOffset, inputLen);
+        }
+
         if (mCachedException != null) {
             throw (IllegalBlockSizeException)
                     new IllegalBlockSizeException().initCause(mCachedException);
@@ -522,6 +615,10 @@
     protected final int engineDoFinal(byte[] input, int inputOffset, int inputLen, byte[] output,
             int outputOffset) throws ShortBufferException, IllegalBlockSizeException,
             BadPaddingException {
+        if (mCipher != null) {
+            return mCipher.doFinal(input, inputOffset, inputLen, output);
+        }
+
         byte[] outputCopy = engineDoFinal(input, inputOffset, inputLen);
         if (outputCopy == null) {
             return 0;
@@ -538,6 +635,10 @@
     @Override
     protected final int engineDoFinal(ByteBuffer input, ByteBuffer output)
             throws ShortBufferException, IllegalBlockSizeException, BadPaddingException {
+        if (mCipher != null) {
+            return mCipher.doFinal(input, output);
+        }
+
         if (input == null) {
             throw new NullPointerException("input == null");
         }
@@ -575,6 +676,10 @@
     @Override
     protected final byte[] engineWrap(Key key)
             throws IllegalBlockSizeException, InvalidKeyException {
+        if (mCipher != null) {
+            return mCipher.wrap(key);
+        }
+
         if (mKey == null) {
             throw new IllegalStateException("Not initilized");
         }
@@ -656,6 +761,10 @@
     @Override
     protected final Key engineUnwrap(byte[] wrappedKey, String wrappedKeyAlgorithm,
             int wrappedKeyType) throws InvalidKeyException, NoSuchAlgorithmException {
+        if (mCipher != null) {
+            return mCipher.unwrap(wrappedKey, wrappedKeyAlgorithm, wrappedKeyType);
+        }
+
         if (mKey == null) {
             throw new IllegalStateException("Not initilized");
         }
@@ -902,4 +1011,6 @@
      */
     protected abstract void loadAlgorithmSpecificParametersFromBeginResult(
             KeyParameter[] parameters);
+
+    protected abstract String getTransform();
 }
diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreECDSASignatureSpi.java b/keystore/java/android/security/keystore2/AndroidKeyStoreECDSASignatureSpi.java
index d1ef1df..8289671 100644
--- a/keystore/java/android/security/keystore2/AndroidKeyStoreECDSASignatureSpi.java
+++ b/keystore/java/android/security/keystore2/AndroidKeyStoreECDSASignatureSpi.java
@@ -44,6 +44,11 @@
         }
 
         @Override
+        protected String getAlgorithm() {
+            return "NONEwithECDSA";
+        }
+
+        @Override
         protected KeyStoreCryptoOperationStreamer createMainDataStreamer(
                 KeyStoreOperation operation) {
             return new TruncateToFieldSizeMessageStreamer(
@@ -113,30 +118,50 @@
         public SHA1() {
             super(KeymasterDefs.KM_DIGEST_SHA1);
         }
+        @Override
+        protected String getAlgorithm() {
+            return "SHA1withECDSA";
+        }
     }
 
     public final static class SHA224 extends AndroidKeyStoreECDSASignatureSpi {
         public SHA224() {
             super(KeymasterDefs.KM_DIGEST_SHA_2_224);
         }
+        @Override
+        protected String getAlgorithm() {
+            return "SHA224withECDSA";
+        }
     }
 
     public final static class SHA256 extends AndroidKeyStoreECDSASignatureSpi {
         public SHA256() {
             super(KeymasterDefs.KM_DIGEST_SHA_2_256);
         }
+        @Override
+        protected String getAlgorithm() {
+            return "SHA256withECDSA";
+        }
     }
 
     public final static class SHA384 extends AndroidKeyStoreECDSASignatureSpi {
         public SHA384() {
             super(KeymasterDefs.KM_DIGEST_SHA_2_384);
         }
+        @Override
+        protected String getAlgorithm() {
+            return "SHA384withECDSA";
+        }
     }
 
     public final static class SHA512 extends AndroidKeyStoreECDSASignatureSpi {
         public SHA512() {
             super(KeymasterDefs.KM_DIGEST_SHA_2_512);
         }
+        @Override
+        protected String getAlgorithm() {
+            return "SHA512withECDSA";
+        }
     }
 
     private final int mKeymasterDigest;
diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreProvider.java b/keystore/java/android/security/keystore2/AndroidKeyStoreProvider.java
index b2e32a3..403da18 100644
--- a/keystore/java/android/security/keystore2/AndroidKeyStoreProvider.java
+++ b/keystore/java/android/security/keystore2/AndroidKeyStoreProvider.java
@@ -31,9 +31,7 @@
 import android.system.keystore2.KeyMetadata;
 import android.system.keystore2.ResponseCode;
 
-import java.security.KeyFactory;
 import java.security.KeyPair;
-import java.security.NoSuchAlgorithmException;
 import java.security.Provider;
 import java.security.ProviderException;
 import java.security.PublicKey;
@@ -42,8 +40,6 @@
 import java.security.UnrecoverableKeyException;
 import java.security.interfaces.ECPublicKey;
 import java.security.interfaces.RSAPublicKey;
-import java.security.spec.InvalidKeySpecException;
-import java.security.spec.X509EncodedKeySpec;
 
 import javax.crypto.Cipher;
 import javax.crypto.Mac;
@@ -237,28 +233,11 @@
             throw new UnrecoverableKeyException("Failed to obtain X.509 form of public key."
                     + " Keystore has no public certificate stored.");
         }
-        final byte[] x509EncodedPublicKey = metadata.certificate;
+        final byte[] x509PublicCert = metadata.certificate;
 
-        String jcaKeyAlgorithm;
-        try {
-            jcaKeyAlgorithm = KeyProperties.KeyAlgorithm.fromKeymasterAsymmetricKeyAlgorithm(
-                    algorithm);
-        } catch (IllegalArgumentException e) {
-            throw (UnrecoverableKeyException)
-                    new UnrecoverableKeyException("Failed to load private key")
-                            .initCause(e);
-        }
+        PublicKey publicKey = AndroidKeyStoreSpi.toCertificate(x509PublicCert).getPublicKey();
 
-        PublicKey publicKey;
-        try {
-            KeyFactory keyFactory = KeyFactory.getInstance(jcaKeyAlgorithm);
-            publicKey = keyFactory.generatePublic(new X509EncodedKeySpec(x509EncodedPublicKey));
-        } catch (NoSuchAlgorithmException e) {
-            throw new ProviderException(
-                    "Failed to obtain " + jcaKeyAlgorithm + " KeyFactory", e);
-        } catch (InvalidKeySpecException e) {
-            throw new ProviderException("Invalid X.509 encoding of public key", e);
-        }
+        String jcaKeyAlgorithm = publicKey.getAlgorithm();
 
         KeyStoreSecurityLevel securityLevel = iSecurityLevel;
         if (KeyProperties.KEY_ALGORITHM_EC.equalsIgnoreCase(jcaKeyAlgorithm)) {
@@ -358,7 +337,7 @@
 
         KeyDescriptor descriptor = new KeyDescriptor();
         if (namespace == KeyProperties.NAMESPACE_APPLICATION) {
-            descriptor.nspace = 0; // ignored;
+            descriptor.nspace = KeyProperties.NAMESPACE_APPLICATION; // ignored;
             descriptor.domain = Domain.APP;
         } else {
             descriptor.nspace = namespace;
@@ -387,10 +366,10 @@
         for (Authorization a : response.metadata.authorizations) {
             switch (a.keyParameter.tag) {
                 case KeymasterDefs.KM_TAG_ALGORITHM:
-                    keymasterAlgorithm = a.keyParameter.integer;
+                    keymasterAlgorithm = a.keyParameter.value.getAlgorithm();
                     break;
                 case KeymasterDefs.KM_TAG_DIGEST:
-                    if (keymasterDigest == -1) keymasterDigest = a.keyParameter.integer;
+                    if (keymasterDigest == -1) keymasterDigest = a.keyParameter.value.getDigest();
                     break;
             }
         }
@@ -407,7 +386,7 @@
                 keymasterAlgorithm == KeymasterDefs.KM_ALGORITHM_EC) {
             return makeAndroidKeyStorePublicKeyFromKeyEntryResponse(descriptor, response.metadata,
                     new KeyStoreSecurityLevel(response.iSecurityLevel),
-                    keymasterAlgorithm);
+                    keymasterAlgorithm).getPrivateKey();
         } else {
             throw new UnrecoverableKeyException("Key algorithm unknown");
         }
diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreRSACipherSpi.java b/keystore/java/android/security/keystore2/AndroidKeyStoreRSACipherSpi.java
index 951f918..6ff9432 100644
--- a/keystore/java/android/security/keystore2/AndroidKeyStoreRSACipherSpi.java
+++ b/keystore/java/android/security/keystore2/AndroidKeyStoreRSACipherSpi.java
@@ -158,7 +158,7 @@
     }
 
     /**
-     * RSA cipher with OAEP encryption padding. Only SHA-1 based MGF1 is supported as MGF.
+     * RSA cipher with OAEP encryption padding.
      */
     abstract static class OAEPWithMGF1Padding extends AndroidKeyStoreRSACipherSpi {
 
@@ -316,6 +316,25 @@
         protected final int getAdditionalEntropyAmountForFinish() {
             return (isEncrypting()) ? mDigestOutputSizeBytes : 0;
         }
+
+        @Override
+        protected final String getTransform() {
+            switch (mKeymasterDigest) {
+                case KeymasterDefs.KM_DIGEST_SHA1:
+                    return "RSA/ECB/OAEPWithSHA-1AndMGF1Padding";
+                case KeymasterDefs.KM_DIGEST_SHA_2_224:
+                    return "RSA/ECB/OAEPWithSHA-224AndMGF1Padding";
+                case KeymasterDefs.KM_DIGEST_SHA_2_256:
+                    return "RSA/ECB/OAEPWithSHA-256AndMGF1Padding";
+                case KeymasterDefs.KM_DIGEST_SHA_2_384:
+                    return "RSA/ECB/OAEPWithSHA-384AndMGF1Padding";
+                case KeymasterDefs.KM_DIGEST_SHA_2_512:
+                    return "RSA/ECB/OAEPWithSHA-512AndMGF1Padding";
+                default:
+                    return "RSA/ECB/OAEPPadding";
+            }
+        }
+
     }
 
     public static class OAEPWithSHA1AndMGF1Padding extends OAEPWithMGF1Padding {
@@ -358,6 +377,11 @@
     }
 
     @Override
+    protected String getTransform() {
+        return "RSA/ECB/" + KeyProperties.EncryptionPadding.fromKeymaster(mKeymasterPadding);
+    }
+
+    @Override
     protected final void initKey(int opmode, Key key) throws InvalidKeyException {
         if (key == null) {
             throw new InvalidKeyException("Unsupported key: null");
diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreRSASignatureSpi.java b/keystore/java/android/security/keystore2/AndroidKeyStoreRSASignatureSpi.java
index ab75591..931c2f8 100644
--- a/keystore/java/android/security/keystore2/AndroidKeyStoreRSASignatureSpi.java
+++ b/keystore/java/android/security/keystore2/AndroidKeyStoreRSASignatureSpi.java
@@ -48,42 +48,70 @@
         public NONEWithPKCS1Padding() {
             super(KeymasterDefs.KM_DIGEST_NONE);
         }
+        @Override
+        protected String getAlgorithm() {
+            return "NONEwithRSA";
+        }
     }
 
     public static final class MD5WithPKCS1Padding extends PKCS1Padding {
         public MD5WithPKCS1Padding() {
             super(KeymasterDefs.KM_DIGEST_MD5);
         }
+        @Override
+        protected String getAlgorithm() {
+            return "MD5withRSA";
+        }
     }
 
     public static final class SHA1WithPKCS1Padding extends PKCS1Padding {
         public SHA1WithPKCS1Padding() {
             super(KeymasterDefs.KM_DIGEST_SHA1);
         }
+        @Override
+        protected String getAlgorithm() {
+            return "SHA1withRSA";
+        }
     }
 
     public static final class SHA224WithPKCS1Padding extends PKCS1Padding {
         public SHA224WithPKCS1Padding() {
             super(KeymasterDefs.KM_DIGEST_SHA_2_224);
         }
+        @Override
+        protected String getAlgorithm() {
+            return "SHA224withRSA";
+        }
     }
 
     public static final class SHA256WithPKCS1Padding extends PKCS1Padding {
         public SHA256WithPKCS1Padding() {
             super(KeymasterDefs.KM_DIGEST_SHA_2_256);
         }
+        @Override
+        protected String getAlgorithm() {
+            return "SHA256withRSA";
+        }
     }
 
     public static final class SHA384WithPKCS1Padding extends PKCS1Padding {
         public SHA384WithPKCS1Padding() {
             super(KeymasterDefs.KM_DIGEST_SHA_2_384);
         }
+        @Override
+        protected String getAlgorithm() {
+            return "SHA384withRSA";
+        }
     }
 
     public static final class SHA512WithPKCS1Padding extends PKCS1Padding {
         public SHA512WithPKCS1Padding() {
             super(KeymasterDefs.KM_DIGEST_SHA_2_512);
         }
+        @Override
+        protected String getAlgorithm() {
+            return "SHA512withRSA";
+        }
     }
 
     abstract static class PSSPadding extends AndroidKeyStoreRSASignatureSpi {
@@ -103,30 +131,50 @@
         public SHA1WithPSSPadding() {
             super(KeymasterDefs.KM_DIGEST_SHA1);
         }
+        @Override
+        protected String getAlgorithm() {
+            return "SHA1withRSA/PSS";
+        }
     }
 
     public static final class SHA224WithPSSPadding extends PSSPadding {
         public SHA224WithPSSPadding() {
             super(KeymasterDefs.KM_DIGEST_SHA_2_224);
         }
+        @Override
+        protected String getAlgorithm() {
+            return "SHA224withRSA/PSS";
+        }
     }
 
     public static final class SHA256WithPSSPadding extends PSSPadding {
         public SHA256WithPSSPadding() {
             super(KeymasterDefs.KM_DIGEST_SHA_2_256);
         }
+        @Override
+        protected String getAlgorithm() {
+            return "SHA256withRSA/PSS";
+        }
     }
 
     public static final class SHA384WithPSSPadding extends PSSPadding {
         public SHA384WithPSSPadding() {
             super(KeymasterDefs.KM_DIGEST_SHA_2_384);
         }
+        @Override
+        protected String getAlgorithm() {
+            return "SHA384withRSA/PSS";
+        }
     }
 
     public static final class SHA512WithPSSPadding extends PSSPadding {
         public SHA512WithPSSPadding() {
             super(KeymasterDefs.KM_DIGEST_SHA_2_512);
         }
+        @Override
+        protected String getAlgorithm() {
+            return "SHA512withRSA/PSS";
+        }
     }
 
     private final int mKeymasterDigest;
diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreSecretKeyFactorySpi.java b/keystore/java/android/security/keystore2/AndroidKeyStoreSecretKeyFactorySpi.java
index 9d3b970..74503e1 100644
--- a/keystore/java/android/security/keystore2/AndroidKeyStoreSecretKeyFactorySpi.java
+++ b/keystore/java/android/security/keystore2/AndroidKeyStoreSecretKeyFactorySpi.java
@@ -102,7 +102,8 @@
                         insideSecureHardware =
                                 KeyStore2ParameterUtils.isSecureHardware(a.securityLevel);
                         securityLevel = a.securityLevel;
-                        origin = KeyProperties.Origin.fromKeymaster(a.keyParameter.integer);
+                        origin = KeyProperties.Origin.fromKeymaster(
+                                a.keyParameter.value.getOrigin());
                         break;
                     case KeymasterDefs.KM_TAG_KEY_SIZE:
                         long keySizeUnsigned = KeyStore2ParameterUtils.getUnsignedInt(a);
@@ -113,45 +114,51 @@
                         keySize = (int) keySizeUnsigned;
                         break;
                     case KeymasterDefs.KM_TAG_PURPOSE:
-                        purposes |= KeyProperties.Purpose.fromKeymaster(a.keyParameter.integer);
+                        purposes |= KeyProperties.Purpose.fromKeymaster(
+                                a.keyParameter.value.getKeyPurpose());
                         break;
                     case KeymasterDefs.KM_TAG_PADDING:
+                        int paddingMode = a.keyParameter.value.getPaddingMode();
                         try {
-                            if (a.keyParameter.integer == KeymasterDefs.KM_PAD_RSA_PKCS1_1_5_SIGN
-                                    || a.keyParameter.integer == KeymasterDefs.KM_PAD_RSA_PSS) {
+                            if (paddingMode == KeymasterDefs.KM_PAD_RSA_PKCS1_1_5_SIGN
+                                    || paddingMode == KeymasterDefs.KM_PAD_RSA_PSS) {
                                 @KeyProperties.SignaturePaddingEnum String padding =
                                         KeyProperties.SignaturePadding.fromKeymaster(
-                                                a.keyParameter.integer);
+                                                paddingMode);
                                 signaturePaddingsList.add(padding);
                             } else {
                                 @KeyProperties.EncryptionPaddingEnum String jcaPadding =
                                         KeyProperties.EncryptionPadding.fromKeymaster(
-                                                a.keyParameter.integer);
+                                                paddingMode);
                                 encryptionPaddingsList.add(jcaPadding);
                             }
                         } catch (IllegalArgumentException e) {
                             throw new ProviderException("Unsupported padding: "
-                                                + a.keyParameter.integer);
+                                                + paddingMode);
                         }
                         break;
                     case KeymasterDefs.KM_TAG_DIGEST:
-                        digestsList.add(KeyProperties.Digest.fromKeymaster(a.keyParameter.integer));
+                        digestsList.add(KeyProperties.Digest.fromKeymaster(
+                                a.keyParameter.value.getDigest()));
                         break;
                     case KeymasterDefs.KM_TAG_BLOCK_MODE:
                         blockModesList.add(
-                                KeyProperties.BlockMode.fromKeymaster(a.keyParameter.integer)
+                                KeyProperties.BlockMode.fromKeymaster(
+                                        a.keyParameter.value.getBlockMode())
                         );
                         break;
                     case KeymasterDefs.KM_TAG_USER_AUTH_TYPE:
+                        int authenticatorType = a.keyParameter.value.getHardwareAuthenticatorType();
                         if (KeyStore2ParameterUtils.isSecureHardware(a.securityLevel)) {
-                            keymasterHwEnforcedUserAuthenticators = a.keyParameter.integer;
+                            keymasterHwEnforcedUserAuthenticators = authenticatorType;
                         } else {
-                            keymasterSwEnforcedUserAuthenticators = a.keyParameter.integer;
+                            keymasterSwEnforcedUserAuthenticators = authenticatorType;
                         }
                         break;
                     case KeymasterDefs.KM_TAG_USER_SECURE_ID:
                         keymasterSecureUserIds.add(
-                                KeymasterArguments.toUint64(a.keyParameter.longInteger));
+                                KeymasterArguments.toUint64(
+                                        a.keyParameter.value.getLongInteger()));
                         break;
                     case KeymasterDefs.KM_TAG_ACTIVE_DATETIME:
                         keyValidityStart = KeyStore2ParameterUtils.getDate(a);
diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreSignatureSpiBase.java b/keystore/java/android/security/keystore2/AndroidKeyStoreSignatureSpiBase.java
index 9b4f01e..96da1e0 100644
--- a/keystore/java/android/security/keystore2/AndroidKeyStoreSignatureSpiBase.java
+++ b/keystore/java/android/security/keystore2/AndroidKeyStoreSignatureSpiBase.java
@@ -30,10 +30,12 @@
 import java.nio.ByteBuffer;
 import java.security.InvalidKeyException;
 import java.security.InvalidParameterException;
+import java.security.NoSuchAlgorithmException;
 import java.security.PrivateKey;
 import java.security.ProviderException;
 import java.security.PublicKey;
 import java.security.SecureRandom;
+import java.security.Signature;
 import java.security.SignatureException;
 import java.security.SignatureSpi;
 import java.util.ArrayList;
@@ -76,6 +78,13 @@
      */
     private Exception mCachedException;
 
+    /**
+     * This signature object is used for public key operations, i.e, signatrue verification.
+     * The Android Keystore backend does not perform public key operations and defers to the
+     * Highest priority provider.
+     */
+    private Signature mSignature;
+
     AndroidKeyStoreSignatureSpiBase() {
         mOperation = null;
         mOperationChallenge = 0;
@@ -84,6 +93,7 @@
         appRandom = null;
         mMessageStreamer = null;
         mCachedException = null;
+        mSignature = null;
     }
 
     @Override
@@ -123,27 +133,13 @@
     protected final void engineInitVerify(PublicKey publicKey) throws InvalidKeyException {
         resetAll();
 
-        boolean success = false;
         try {
-            if (publicKey == null) {
-                throw new InvalidKeyException("Unsupported key: null");
-            }
-            AndroidKeyStoreKey keystoreKey;
-            if (publicKey instanceof AndroidKeyStorePublicKey) {
-                keystoreKey = (AndroidKeyStorePublicKey) publicKey;
-            } else {
-                throw new InvalidKeyException("Unsupported public key type: " + publicKey);
-            }
-            mSigning = false;
-            initKey(keystoreKey);
-            appRandom = null;
-            ensureKeystoreOperationInitialized();
-            success = true;
-        } finally {
-            if (!success) {
-                resetAll();
-            }
+            mSignature = Signature.getInstance(getAlgorithm());
+        } catch (NoSuchAlgorithmException e) {
+            throw new InvalidKeyException(e);
         }
+
+        mSignature.initVerify(publicKey);
     }
 
     /**
@@ -251,6 +247,11 @@
 
     @Override
     protected final void engineUpdate(byte[] b, int off, int len) throws SignatureException {
+        if (mSignature != null) {
+            mSignature.update(b, off, len);
+            return;
+        }
+
         if (mCachedException != null) {
             throw new SignatureException(mCachedException);
         }
@@ -337,39 +338,10 @@
 
     @Override
     protected final boolean engineVerify(byte[] signature) throws SignatureException {
-        if (mCachedException != null) {
-            throw new SignatureException(mCachedException);
+        if (mSignature != null) {
+            return mSignature.verify(signature);
         }
-
-        try {
-            ensureKeystoreOperationInitialized();
-        } catch (InvalidKeyException e) {
-            throw new SignatureException(e);
-        }
-
-        boolean verified;
-        try {
-            byte[] output = mMessageStreamer.doFinal(
-                    EmptyArray.BYTE, 0, 0,
-                    signature);
-            if (output.length != 0) {
-                throw new ProviderException(
-                        "Signature verification unexpected produced output: " + output.length
-                        + " bytes");
-            }
-            verified = true;
-        } catch (KeyStoreException e) {
-            switch (e.getErrorCode()) {
-                case KeymasterDefs.KM_ERROR_VERIFICATION_FAILED:
-                    verified = false;
-                    break;
-                default:
-                    throw new SignatureException(e);
-            }
-        }
-
-        resetWhilePreservingInitState();
-        return verified;
+        throw new IllegalStateException("Not initialised.");
     }
 
     @Override
@@ -392,6 +364,13 @@
     }
 
     /**
+     * Implementations need to report the algorithm they implement so that we can delegate to the
+     * highest priority provider.
+     * @return Algorithm string.
+     */
+    protected abstract String getAlgorithm();
+
+    /**
      * Returns {@code true} if this signature is initialized for signing, {@code false} if this
      * signature is initialized for verification.
      */
diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreSpi.java b/keystore/java/android/security/keystore2/AndroidKeyStoreSpi.java
index c42c7b2..5e7f648 100644
--- a/keystore/java/android/security/keystore2/AndroidKeyStoreSpi.java
+++ b/keystore/java/android/security/keystore2/AndroidKeyStoreSpi.java
@@ -219,7 +219,7 @@
         return null;
     }
 
-    private static X509Certificate toCertificate(byte[] bytes) {
+    static X509Certificate toCertificate(byte[] bytes) {
         try {
             final CertificateFactory certFactory = CertificateFactory.getInstance("X.509");
             return (X509Certificate) certFactory.generateCertificate(
diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreUnauthenticatedAESCipherSpi.java b/keystore/java/android/security/keystore2/AndroidKeyStoreUnauthenticatedAESCipherSpi.java
index 4d4b0d8..5c048a1 100644
--- a/keystore/java/android/security/keystore2/AndroidKeyStoreUnauthenticatedAESCipherSpi.java
+++ b/keystore/java/android/security/keystore2/AndroidKeyStoreUnauthenticatedAESCipherSpi.java
@@ -42,7 +42,7 @@
  *
  * @hide
  */
-class AndroidKeyStoreUnauthenticatedAESCipherSpi extends AndroidKeyStoreCipherSpiBase {
+abstract class AndroidKeyStoreUnauthenticatedAESCipherSpi extends AndroidKeyStoreCipherSpiBase {
 
     abstract static class ECB extends AndroidKeyStoreUnauthenticatedAESCipherSpi {
         protected ECB(int keymasterPadding) {
@@ -53,12 +53,22 @@
             public NoPadding() {
                 super(KeymasterDefs.KM_PAD_NONE);
             }
+
+            @Override
+            protected final String getTransform() {
+                return "AES/ECB/NoPadding";
+            }
         }
 
         public static class PKCS7Padding extends ECB {
             public PKCS7Padding() {
                 super(KeymasterDefs.KM_PAD_PKCS7);
             }
+
+            @Override
+            protected final String getTransform() {
+                return "AES/ECB/PKCS7Padding";
+            }
         }
     }
 
@@ -71,12 +81,22 @@
             public NoPadding() {
                 super(KeymasterDefs.KM_PAD_NONE);
             }
+
+            @Override
+            protected final String getTransform() {
+                return "AES/CBC/NoPadding";
+            }
         }
 
         public static class PKCS7Padding extends CBC {
             public PKCS7Padding() {
                 super(KeymasterDefs.KM_PAD_PKCS7);
             }
+
+            @Override
+            protected final String getTransform() {
+                return "AES/CBC/PKCS7Padding";
+            }
         }
     }
 
@@ -89,6 +109,11 @@
             public NoPadding() {
                 super(KeymasterDefs.KM_PAD_NONE);
             }
+
+            @Override
+            protected final String getTransform() {
+                return "AES/CTR/NoPadding";
+            }
         }
     }
 
@@ -275,7 +300,7 @@
         if (parameters != null) {
             for (KeyParameter p : parameters) {
                 if (p.tag == KeymasterDefs.KM_TAG_NONCE) {
-                    returnedIv = p.blob;
+                    returnedIv = p.value.getBlob();
                     break;
                 }
             }
diff --git a/keystore/java/android/security/keystore2/KeyStore2ParameterUtils.java b/keystore/java/android/security/keystore2/KeyStore2ParameterUtils.java
index 18c786a..4c8ab8d 100644
--- a/keystore/java/android/security/keystore2/KeyStore2ParameterUtils.java
+++ b/keystore/java/android/security/keystore2/KeyStore2ParameterUtils.java
@@ -19,7 +19,9 @@
 import android.annotation.NonNull;
 import android.hardware.biometrics.BiometricManager;
 import android.hardware.security.keymint.KeyParameter;
+import android.hardware.security.keymint.KeyParameterValue;
 import android.hardware.security.keymint.SecurityLevel;
+import android.hardware.security.keymint.Tag;
 import android.security.GateKeeper;
 import android.security.keymaster.KeymasterDefs;
 import android.security.keystore.KeyProperties;
@@ -50,7 +52,7 @@
         }
         KeyParameter p = new KeyParameter();
         p.tag = tag;
-        p.boolValue = true;
+        p.value = KeyParameterValue.boolValue(true);
         return p;
     }
 
@@ -62,14 +64,40 @@
      * @hide
      */
     static @NonNull KeyParameter makeEnum(int tag, int v) {
-        int type = KeymasterDefs.getTagType(tag);
-        if (type != KeymasterDefs.KM_ENUM && type != KeymasterDefs.KM_ENUM_REP) {
-            throw new IllegalArgumentException("Not an enum or repeatable enum tag: " + tag);
+        KeyParameter kp = new KeyParameter();
+        kp.tag = tag;
+        switch (tag) {
+            case Tag.PURPOSE:
+                kp.value = KeyParameterValue.keyPurpose(v);
+                break;
+            case Tag.ALGORITHM:
+                kp.value = KeyParameterValue.algorithm(v);
+                break;
+            case Tag.BLOCK_MODE:
+                kp.value = KeyParameterValue.blockMode(v);
+                break;
+            case Tag.DIGEST:
+                kp.value = KeyParameterValue.digest(v);
+                break;
+            case Tag.EC_CURVE:
+                kp.value = KeyParameterValue.ecCurve(v);
+                break;
+            case Tag.ORIGIN:
+                kp.value = KeyParameterValue.origin(v);
+                break;
+            case Tag.PADDING:
+                kp.value = KeyParameterValue.paddingMode(v);
+                break;
+            case Tag.USER_AUTH_TYPE:
+                kp.value = KeyParameterValue.hardwareAuthenticatorType(v);
+                break;
+            case Tag.HARDWARE_TYPE:
+                kp.value = KeyParameterValue.securityLevel(v);
+                break;
+            default:
+                throw new IllegalArgumentException("Not an enum or repeatable enum tag: " + tag);
         }
-        KeyParameter p = new KeyParameter();
-        p.tag = tag;
-        p.integer = v;
-        return p;
+        return kp;
     }
 
     /**
@@ -86,7 +114,7 @@
         }
         KeyParameter p = new KeyParameter();
         p.tag = tag;
-        p.integer = v;
+        p.value = KeyParameterValue.integer(v);
         return p;
     }
 
@@ -104,7 +132,7 @@
         }
         KeyParameter p = new KeyParameter();
         p.tag = tag;
-        p.longInteger = v;
+        p.value = KeyParameterValue.longInteger(v);
         return p;
     }
 
@@ -121,7 +149,7 @@
         }
         KeyParameter p = new KeyParameter();
         p.tag = tag;
-        p.blob = b;
+        p.value = KeyParameterValue.blob(b);
         return p;
     }
 
@@ -138,9 +166,10 @@
         }
         KeyParameter p = new KeyParameter();
         p.tag = tag;
-        p.longInteger = date.getTime();
-        if (p.longInteger < 0) {
-            throw new IllegalArgumentException("Date tag value out of range: " + p.longInteger);
+        p.value = KeyParameterValue.dateTime(date.getTime());
+        if (p.value.getDateTime() < 0) {
+            throw new IllegalArgumentException("Date tag value out of range: "
+                    + p.value.getDateTime());
         }
         return p;
     }
@@ -160,24 +189,24 @@
             throw new IllegalArgumentException("Not an int tag: " + param.keyParameter.tag);
         }
         // KM_UINT is 32 bits wide so we must suppress sign extension.
-        return ((long) param.keyParameter.integer) & 0xffffffffL;
+        return ((long) param.keyParameter.value.getInteger()) & 0xffffffffL;
     }
 
     static @NonNull Date getDate(@NonNull Authorization param) {
         if (KeymasterDefs.getTagType(param.keyParameter.tag) != KeymasterDefs.KM_DATE) {
             throw new IllegalArgumentException("Not a date tag: " + param.keyParameter.tag);
         }
-        if (param.keyParameter.longInteger < 0) {
+        if (param.keyParameter.value.getDateTime() < 0) {
             throw new IllegalArgumentException("Date Value too large: "
-                    + param.keyParameter.longInteger);
+                    + param.keyParameter.value.getDateTime());
         }
-        return new Date(param.keyParameter.longInteger);
+        return new Date(param.keyParameter.value.getDateTime());
     }
 
     static void forEachSetFlag(int flags, Consumer<Integer> consumer) {
         int offset = 0;
         while (flags != 0) {
-            if ((flags & 1) == 0) {
+            if ((flags & 1) == 1) {
                 consumer.accept(1 << offset);
             }
             offset += 1;
diff --git a/keystore/java/android/security/keystore2/KeyStoreCryptoOperationUtils.java b/keystore/java/android/security/keystore2/KeyStoreCryptoOperationUtils.java
index 3b11854..f87a3d2 100644
--- a/keystore/java/android/security/keystore2/KeyStoreCryptoOperationUtils.java
+++ b/keystore/java/android/security/keystore2/KeyStoreCryptoOperationUtils.java
@@ -57,7 +57,7 @@
         for (Authorization p : key.getAuthorizations()) {
             switch(p.keyParameter.tag) {
                 case KeymasterDefs.KM_TAG_USER_SECURE_ID:
-                    keySids.add(p.keyParameter.longInteger);
+                    keySids.add(p.keyParameter.value.getLongInteger());
                     break;
                 default:
                     break;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java
index 8d15080..faa4a0e 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java
@@ -34,6 +34,7 @@
 import android.util.SparseArray;
 import android.view.SurfaceControl;
 import android.window.ITaskOrganizerController;
+import android.window.StartingWindowInfo;
 import android.window.TaskAppearedInfo;
 import android.window.TaskOrganizer;
 
@@ -112,7 +113,7 @@
         // TODO(b/131727939) temporarily live here, the starting surface drawer should be controlled
         //  by a controller, that class should be create while porting
         //  ActivityRecord#addStartingWindow to WMShell.
-        mStartingSurfaceDrawer = new StartingSurfaceDrawer(context);
+        mStartingSurfaceDrawer = new StartingSurfaceDrawer(context, mainExecutor);
     }
 
     @Override
@@ -229,13 +230,13 @@
     }
 
     @Override
-    public void addStartingWindow(RunningTaskInfo taskInfo, IBinder appToken) {
-        mStartingSurfaceDrawer.addStartingWindow(taskInfo, appToken);
+    public void addStartingWindow(StartingWindowInfo info, IBinder appToken) {
+        mStartingSurfaceDrawer.addStartingWindow(info, appToken);
     }
 
     @Override
-    public void removeStartingWindow(RunningTaskInfo taskInfo) {
-        mStartingSurfaceDrawer.removeStartingWindow(taskInfo);
+    public void removeStartingWindow(int taskId) {
+        mStartingSurfaceDrawer.removeStartingWindow(taskId);
     }
 
     @Override
@@ -261,6 +262,12 @@
         synchronized (mLock) {
             ProtoLog.v(WM_SHELL_TASK_ORG, "Task info changed taskId=%d", taskInfo.taskId);
             final TaskAppearedInfo data = mTasks.get(taskInfo.taskId);
+            if (data == null) {
+                // TODO(b/171749427): It means onTaskInfoChanged send before onTaskAppeared or
+                //  after onTaskVanished, it should be fixed in controller side.
+                return;
+            }
+
             final TaskListener oldListener = getTaskListener(data.getTaskInfo());
             final TaskListener newListener = getTaskListener(taskInfo);
             mTasks.put(taskInfo.taskId, new TaskAppearedInfo(taskInfo, data.getLeash()));
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/SystemWindows.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/SystemWindows.java
index 4c06a2c..616f24a 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/SystemWindows.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/SystemWindows.java
@@ -339,9 +339,6 @@
         public void requestAppKeyboardShortcuts(IResultReceiver receiver, int deviceId) {}
 
         @Override
-        public void dispatchPointerCaptureChanged(boolean hasCapture) {}
-
-        @Override
         public void requestScrollCapture(IScrollCaptureCallbacks callbacks) {
             try {
                 callbacks.onUnavailable();
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedController.java
index d5db0cc..69d8db2 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedController.java
@@ -32,6 +32,7 @@
 import android.os.SystemProperties;
 import android.provider.Settings;
 import android.util.Slog;
+import android.view.accessibility.AccessibilityManager;
 
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
@@ -75,6 +76,7 @@
     private final Handler mMainHandler = new Handler(Looper.getMainLooper());
 
     private OneHandedDisplayAreaOrganizer mDisplayAreaOrganizer;
+    private final AccessibilityManager mAccessibilityManager;
 
     /**
      * Handle rotation based on OnDisplayChangingListener callback
@@ -164,6 +166,26 @@
                 }
             };
 
+    private AccessibilityManager.AccessibilityStateChangeListener
+            mAccessibilityStateChangeListener =
+            new AccessibilityManager.AccessibilityStateChangeListener() {
+                @Override
+                public void onAccessibilityStateChanged(boolean enabled) {
+                    if (enabled) {
+                        final int mOneHandedTimeout = OneHandedSettingsUtil
+                                .getSettingsOneHandedModeTimeout(mContext.getContentResolver());
+                        final int timeout = mAccessibilityManager
+                                .getRecommendedTimeoutMillis(mOneHandedTimeout * 1000
+                                        /* align with A11y timeout millis */,
+                                        AccessibilityManager.FLAG_CONTENT_CONTROLS);
+                        mTimeoutHandler.setTimeout(timeout / 1000);
+                    } else {
+                        mTimeoutHandler.setTimeout(OneHandedSettingsUtil
+                                .getSettingsOneHandedModeTimeout(mContext.getContentResolver()));
+                    }
+                }
+            };
+
     /**
      * Creates {@link OneHandedController}, returns {@code null} if the feature is not supported.
      */
@@ -239,6 +261,11 @@
                         stopOneHanded(OneHandedEvents.EVENT_ONE_HANDED_TRIGGER_APP_TAPS_OUT);
                     }
                 });
+
+        mAccessibilityManager = (AccessibilityManager)
+                context.getSystemService(Context.ACCESSIBILITY_SERVICE);
+        mAccessibilityManager.addAccessibilityStateChangeListener(
+                mAccessibilityStateChangeListener);
     }
 
     /**
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedSettingsUtil.java b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedSettingsUtil.java
index 4d66f29..f8217c6 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedSettingsUtil.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedSettingsUtil.java
@@ -126,7 +126,7 @@
      */
     public static boolean getSettingsSwipeToNotificationEnabled(ContentResolver resolver) {
         return Settings.Secure.getInt(resolver,
-                Settings.Secure.SWIPE_BOTTOM_TO_NOTIFICATION_ENABLED, 0) == 1;
+                Settings.Secure.SWIPE_BOTTOM_TO_NOTIFICATION_ENABLED, 1) == 1;
     }
 
     protected static void dump(PrintWriter pw, String prefix, ContentResolver resolver) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipAnimationController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipAnimationController.java
index fe01811..3362d2a 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipAnimationController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipAnimationController.java
@@ -22,6 +22,7 @@
 import android.animation.ValueAnimator;
 import android.annotation.IntDef;
 import android.graphics.Rect;
+import android.view.Choreographer;
 import android.view.SurfaceControl;
 
 import com.android.internal.annotations.VisibleForTesting;
@@ -327,8 +328,14 @@
             mEndValue = endValue;
         }
 
-        SurfaceControl.Transaction newSurfaceControlTransaction() {
-            return mSurfaceControlTransactionFactory.getTransaction();
+        /**
+         * @return {@link SurfaceControl.Transaction} instance with vsync-id.
+         */
+        protected SurfaceControl.Transaction newSurfaceControlTransaction() {
+            final SurfaceControl.Transaction tx =
+                    mSurfaceControlTransactionFactory.getTransaction();
+            tx.setFrameTimelineVsync(Choreographer.getSfInstance().getVsyncId());
+            return tx;
         }
 
         @VisibleForTesting
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipBoundsAlgorithm.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipBoundsAlgorithm.java
index 484592e..f839727 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipBoundsAlgorithm.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipBoundsAlgorithm.java
@@ -129,10 +129,9 @@
                 : getDefaultBounds();
 
         final boolean useCurrentSize = reentryState != null && reentryState.getSize() != null;
-        final Rect r = transformBoundsToAspectRatioIfValid(destinationBounds,
+        return transformBoundsToAspectRatioIfValid(destinationBounds,
                 mPipBoundsState.getAspectRatio(), false /* useCurrentMinEdgeSize */,
                 useCurrentSize);
-        return r;
     }
 
     /** Returns the current bounds adjusted to the new aspect ratio, if valid. */
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipBoundsState.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipBoundsState.java
index 4493d38..d0d9b26 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipBoundsState.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipBoundsState.java
@@ -26,6 +26,7 @@
 import android.view.DisplayInfo;
 
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.function.TriConsumer;
 import com.android.wm.shell.R;
 import com.android.wm.shell.common.DisplayLayout;
 
@@ -33,7 +34,6 @@
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.util.Objects;
-import java.util.function.BiConsumer;
 
 /**
  * Singleton source of truth for the current state of PIP bounds.
@@ -80,7 +80,7 @@
     private boolean mHasUserResizedPip;
 
     private @Nullable Runnable mOnMinimalSizeChangeCallback;
-    private @Nullable BiConsumer<Boolean, Integer> mOnShelfVisibilityChangeCallback;
+    private @Nullable TriConsumer<Boolean, Integer, Boolean> mOnShelfVisibilityChangeCallback;
 
     public PipBoundsState(@NonNull Context context) {
         mContext = context;
@@ -310,6 +310,11 @@
 
     /** Set whether the shelf is showing and its height. */
     public void setShelfVisibility(boolean showing, int height) {
+        setShelfVisibility(showing, height, true);
+    }
+
+    /** Set whether the shelf is showing and its height. */
+    public void setShelfVisibility(boolean showing, int height, boolean updateMovementBounds) {
         final boolean shelfShowing = showing && height > 0;
         if (shelfShowing == mIsShelfShowing && height == mShelfHeight) {
             return;
@@ -318,7 +323,8 @@
         mIsShelfShowing = showing;
         mShelfHeight = height;
         if (mOnShelfVisibilityChangeCallback != null) {
-            mOnShelfVisibilityChangeCallback.accept(mIsShelfShowing, mShelfHeight);
+            mOnShelfVisibilityChangeCallback.accept(mIsShelfShowing, mShelfHeight,
+                    updateMovementBounds);
         }
     }
 
@@ -351,7 +357,7 @@
 
     /** Set a callback to be notified when the shelf visibility changes. */
     public void setOnShelfVisibilityChangeCallback(
-            @Nullable BiConsumer<Boolean, Integer> onShelfVisibilityChangeCallback) {
+            @Nullable TriConsumer<Boolean, Integer, Boolean> onShelfVisibilityChangeCallback) {
         mOnShelfVisibilityChangeCallback = onShelfVisibilityChangeCallback;
     }
 
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
index f8b4dd9..de3bb29 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipUiEventLogger.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipUiEventLogger.java
@@ -41,12 +41,12 @@
     }
 
     public void setTaskInfo(TaskInfo taskInfo) {
-        if (taskInfo != null && taskInfo.topActivity != null) {
-            mPackageName = taskInfo.topActivity.getPackageName();
-            mPackageUid = getUid(mPackageName, taskInfo.userId);
-        } else {
+        if (taskInfo == null) {
             mPackageName = null;
             mPackageUid = INVALID_PACKAGE_UID;
+        } else {
+            mPackageName = taskInfo.topActivity.getPackageName();
+            mPackageUid = getUid(mPackageName, taskInfo.userId);
         }
     }
 
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 4d27602..fa88084 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
@@ -114,14 +114,14 @@
         // the bounds for the next orientation using the destination bounds of the animation
         // TODO: Technically this should account for movement animation bounds as well
         Rect currentBounds = mPipTaskOrganizer.getCurrentOrAnimatingBounds();
-        final boolean changed = onDisplayRotationChanged(mContext,
-                mPipBoundsState.getNormalBounds(), currentBounds, mTmpInsetBounds, displayId,
-                fromRotation, toRotation, t);
+        final Rect outBounds = new Rect();
+        final boolean changed = onDisplayRotationChanged(mContext, outBounds, currentBounds,
+                mTmpInsetBounds, displayId, fromRotation, toRotation, t);
         if (changed) {
             // If the pip was in the offset zone earlier, adjust the new bounds to the bottom of the
             // movement bounds
-            mTouchHandler.adjustBoundsForRotation(mPipBoundsState.getNormalBounds(),
-                    mPipBoundsState.getBounds(), mTmpInsetBounds);
+            mTouchHandler.adjustBoundsForRotation(outBounds, mPipBoundsState.getBounds(),
+                    mTmpInsetBounds);
 
             // The bounds are being applied to a specific snap fraction, so reset any known offsets
             // for the previous orientation before updating the movement bounds.
@@ -129,14 +129,18 @@
             // not during the fixed rotation. In fixed rotation case, app is about to enter PiP
             // and we need the offsets preserved to calculate the destination bounds.
             if (!mIsInFixedRotation) {
-                mPipBoundsState.setShelfVisibility(false /* showing */, 0 /* height */);
+                // Update the shelf visibility without updating the movement bounds. We're already
+                // updating them below with the |fromRotation| flag set, which is more accurate
+                // than using the |fromShelfAdjustment|.
+                mPipBoundsState.setShelfVisibility(false /* showing */, 0 /* height */,
+                        false /* updateMovementBounds */);
                 mPipBoundsState.setImeVisibility(false /* showing */, 0 /* height */);
                 mTouchHandler.onShelfVisibilityChanged(false, 0);
                 mTouchHandler.onImeVisibilityChanged(false, 0);
             }
 
-            updateMovementBounds(mPipBoundsState.getNormalBounds(), true /* fromRotation */,
-                    false /* fromImeAdjustment */, false /* fromShelfAdjustment */, t);
+            updateMovementBounds(outBounds, true /* fromRotation */, false /* fromImeAdjustment */,
+                    false /* fromShelfAdjustment */, t);
         }
     };
 
@@ -248,12 +252,16 @@
                             false /* fromImeAdjustment */, false /* fromShelfAdjustment */,
                             null /* wct */);
                 });
-        mPipBoundsState.setOnShelfVisibilityChangeCallback((isShowing, height) -> {
-            mTouchHandler.onShelfVisibilityChanged(isShowing, height);
-            updateMovementBounds(mPipBoundsState.getBounds(),
-                    false /* fromRotation */, false /* fromImeAdjustment */,
-                    true /* fromShelfAdjustment */, null /* windowContainerTransaction */);
-        });
+        mPipBoundsState.setOnShelfVisibilityChangeCallback(
+                (isShowing, height, updateMovementBounds) -> {
+                    mTouchHandler.onShelfVisibilityChanged(isShowing, height);
+                    if (updateMovementBounds) {
+                        updateMovementBounds(mPipBoundsState.getBounds(),
+                                false /* fromRotation */, false /* fromImeAdjustment */,
+                                true /* fromShelfAdjustment */,
+                                null /* windowContainerTransaction */);
+                    }
+                });
         if (mTouchHandler != null) {
             // Register the listener for input consumer touch events. Only for Phone
             mPipInputConsumer.setInputListener(mTouchHandler::handleTouchEvent);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawer.java
index ee79824..e144ca3 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawer.java
@@ -16,11 +16,18 @@
 
 package com.android.wm.shell.startingsurface;
 
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
 import static android.content.Context.CONTEXT_RESTRICTED;
 import static android.content.res.Configuration.EMPTY;
 import static android.view.Display.DEFAULT_DISPLAY;
+import static android.window.StartingWindowInfo.TYPE_PARAMETER_ACTIVITY_CREATED;
+import static android.window.StartingWindowInfo.TYPE_PARAMETER_ALLOW_TASK_SNAPSHOT;
+import static android.window.StartingWindowInfo.TYPE_PARAMETER_NEW_TASK;
+import static android.window.StartingWindowInfo.TYPE_PARAMETER_PROCESS_RUNNING;
+import static android.window.StartingWindowInfo.TYPE_PARAMETER_TASK_SWITCH;
 
-import android.app.ActivityManager;
+import android.app.ActivityManager.RunningTaskInfo;
+import android.app.ActivityTaskManager;
 import android.content.Context;
 import android.content.pm.ActivityInfo;
 import android.content.pm.ApplicationInfo;
@@ -30,18 +37,20 @@
 import android.content.res.TypedArray;
 import android.graphics.drawable.Drawable;
 import android.hardware.display.DisplayManager;
-import android.os.Handler;
 import android.os.IBinder;
-import android.os.Looper;
+import android.os.RemoteException;
 import android.util.Slog;
 import android.util.SparseArray;
 import android.view.Display;
 import android.view.View;
 import android.view.WindowManager;
+import android.window.StartingWindowInfo;
 import android.window.TaskOrganizer;
+import android.window.TaskSnapshot;
 
 import com.android.internal.R;
 import com.android.internal.policy.PhoneWindow;
+import com.android.wm.shell.common.ShellExecutor;
 
 import java.util.function.Consumer;
 
@@ -56,22 +65,24 @@
  * @hide
  */
 public class StartingSurfaceDrawer {
-    private static final String TAG = StartingSurfaceDrawer.class.getSimpleName();
-    private static final boolean DEBUG_SPLASH_SCREEN = false;
+    static final String TAG = StartingSurfaceDrawer.class.getSimpleName();
+    static final boolean DEBUG_SPLASH_SCREEN = false;
+    static final boolean DEBUG_TASK_SNAPSHOT = false;
 
     private final Context mContext;
     private final DisplayManager mDisplayManager;
+    final ShellExecutor mMainExecutor;
 
     // TODO(b/131727939) remove this when clearing ActivityRecord
     private static final int REMOVE_WHEN_TIMEOUT = 2000;
 
-    public StartingSurfaceDrawer(Context context) {
+    public StartingSurfaceDrawer(Context context, ShellExecutor mainExecutor) {
         mContext = context;
         mDisplayManager = mContext.getSystemService(DisplayManager.class);
+        mMainExecutor = mainExecutor;
     }
 
-    private final Handler mHandler = new Handler(Looper.getMainLooper());
-    private final SparseArray<TaskScreenView> mTaskScreenViews = new SparseArray<>();
+    private final SparseArray<StartingWindowRecord> mStartingWindowRecords = new SparseArray<>();
 
     /** Obtain proper context for showing splash screen on the provided display. */
     private Context getDisplayContext(Context context, int displayId) {
@@ -90,12 +101,111 @@
         return context.createDisplayContext(targetDisplay);
     }
 
+    private static class PreferredStartingTypeHelper {
+        private static final int STARTING_TYPE_NO = 0;
+        private static final int STARTING_TYPE_SPLASH_SCREEN = 1;
+        private static final int STARTING_TYPE_SNAPSHOT = 2;
+
+        TaskSnapshot mSnapshot;
+        int mPreferredType;
+
+        PreferredStartingTypeHelper(StartingWindowInfo taskInfo) {
+            final int parameter = taskInfo.startingWindowTypeParameter;
+            final boolean newTask = (parameter & TYPE_PARAMETER_NEW_TASK) != 0;
+            final boolean taskSwitch = (parameter & TYPE_PARAMETER_TASK_SWITCH) != 0;
+            final boolean processRunning = (parameter & TYPE_PARAMETER_PROCESS_RUNNING) != 0;
+            final boolean allowTaskSnapshot = (parameter & TYPE_PARAMETER_ALLOW_TASK_SNAPSHOT) != 0;
+            final boolean activityCreated = (parameter & TYPE_PARAMETER_ACTIVITY_CREATED) != 0;
+            mPreferredType = preferredStartingWindowType(taskInfo, newTask, taskSwitch,
+                    processRunning, allowTaskSnapshot, activityCreated);
+        }
+
+        // reference from ActivityRecord#getStartingWindowType
+        private int preferredStartingWindowType(StartingWindowInfo windowInfo,
+                boolean newTask, boolean taskSwitch, boolean processRunning,
+                boolean allowTaskSnapshot, boolean activityCreated) {
+            if (DEBUG_SPLASH_SCREEN || DEBUG_TASK_SNAPSHOT) {
+                Slog.d(TAG, "preferredStartingWindowType newTask " + newTask
+                        + " taskSwitch " + taskSwitch
+                        + " processRunning " + processRunning
+                        + " allowTaskSnapshot " + allowTaskSnapshot
+                        + " activityCreated " + activityCreated);
+            }
+
+            if (newTask || !processRunning || (taskSwitch && !activityCreated)) {
+                return STARTING_TYPE_SPLASH_SCREEN;
+            } else if (taskSwitch && allowTaskSnapshot) {
+                final TaskSnapshot snapshot = getTaskSnapshot(windowInfo.taskInfo.taskId);
+                if (isSnapshotCompatible(windowInfo, snapshot)) {
+                    return STARTING_TYPE_SNAPSHOT;
+                }
+                if (windowInfo.taskInfo.topActivityType != ACTIVITY_TYPE_HOME) {
+                    return STARTING_TYPE_SPLASH_SCREEN;
+                }
+                return STARTING_TYPE_NO;
+            } else {
+                return STARTING_TYPE_NO;
+            }
+        }
+
+        /**
+         * Returns {@code true} if the task snapshot is compatible with this activity (at least the
+         * rotation must be the same).
+         */
+        private boolean isSnapshotCompatible(StartingWindowInfo windowInfo, TaskSnapshot snapshot) {
+            if (snapshot == null) {
+                if (DEBUG_SPLASH_SCREEN || DEBUG_TASK_SNAPSHOT) {
+                    Slog.d(TAG, "isSnapshotCompatible no snapshot " + windowInfo.taskInfo.taskId);
+                }
+                return false;
+            }
+
+            final int taskRotation = windowInfo.taskInfo.configuration
+                    .windowConfiguration.getRotation();
+            final int snapshotRotation = snapshot.getRotation();
+            if (DEBUG_SPLASH_SCREEN || DEBUG_TASK_SNAPSHOT) {
+                Slog.d(TAG, "isSnapshotCompatible rotation " + taskRotation
+                        + " snapshot " + snapshotRotation);
+            }
+            return taskRotation == snapshotRotation;
+        }
+
+        private TaskSnapshot getTaskSnapshot(int taskId) {
+            if (mSnapshot != null) {
+                return mSnapshot;
+            }
+            try {
+                mSnapshot = ActivityTaskManager.getService().getTaskSnapshot(taskId,
+                        false/* isLowResolution */);
+            } catch (RemoteException e) {
+                Slog.e(TAG, "Unable to get snapshot for task: " + taskId + ", from: " + e);
+                return null;
+            }
+            return mSnapshot;
+        }
+    }
+
     /**
      * Called when a task need a starting window.
      */
-    public void addStartingWindow(ActivityManager.RunningTaskInfo taskInfo, IBinder appToken) {
+    public void addStartingWindow(StartingWindowInfo windowInfo, IBinder appToken) {
+        final PreferredStartingTypeHelper helper =
+                new PreferredStartingTypeHelper(windowInfo);
+        final RunningTaskInfo runningTaskInfo = windowInfo.taskInfo;
+        if (helper.mPreferredType == PreferredStartingTypeHelper.STARTING_TYPE_SPLASH_SCREEN) {
+            addSplashScreenStartingWindow(runningTaskInfo, appToken);
+        } else if (helper.mPreferredType == PreferredStartingTypeHelper.STARTING_TYPE_SNAPSHOT) {
+            final TaskSnapshot snapshot = helper.mSnapshot;
+            makeTaskSnapshotWindow(windowInfo, appToken, snapshot);
+        }
+        // If prefer don't show, then don't show!
+    }
 
+    private void addSplashScreenStartingWindow(RunningTaskInfo taskInfo, IBinder appToken) {
         final ActivityInfo activityInfo = taskInfo.topActivityInfo;
+        if (activityInfo == null) {
+            return;
+        }
         final int displayId = taskInfo.displayId;
         if (activityInfo.packageName == null) {
             return;
@@ -250,18 +360,34 @@
     }
 
     /**
+     * Called when a task need a snapshot starting window.
+     */
+    private void makeTaskSnapshotWindow(StartingWindowInfo startingWindowInfo,
+            IBinder appToken, TaskSnapshot snapshot) {
+        final int taskId = startingWindowInfo.taskInfo.taskId;
+        final TaskSnapshotWindow surface = TaskSnapshotWindow.create(startingWindowInfo, appToken,
+                snapshot, mMainExecutor, () -> removeWindowSynced(taskId) /* clearWindow */);
+        mMainExecutor.execute(() -> {
+            mMainExecutor.executeDelayed(() -> removeWindowSynced(taskId), REMOVE_WHEN_TIMEOUT);
+            final StartingWindowRecord tView =
+                    new StartingWindowRecord(null/* decorView */, surface);
+            mStartingWindowRecords.put(taskId, tView);
+        });
+    }
+
+    /**
      * Called when the content of a task is ready to show, starting window can be removed.
      */
-    public void removeStartingWindow(ActivityManager.RunningTaskInfo taskInfo) {
-        if (DEBUG_SPLASH_SCREEN) {
-            Slog.d(TAG, "Task start finish, remove starting surface for task " + taskInfo.taskId);
+    public void removeStartingWindow(int taskId) {
+        if (DEBUG_SPLASH_SCREEN || DEBUG_TASK_SNAPSHOT) {
+            Slog.d(TAG, "Task start finish, remove starting surface for task " + taskId);
         }
-        mHandler.post(() -> removeWindowSynced(taskInfo.taskId));
+        mMainExecutor.execute(() -> removeWindowSynced(taskId));
     }
 
     protected void postAddWindow(int taskId, IBinder appToken,
             View view, WindowManager wm, WindowManager.LayoutParams params) {
-        mHandler.post(() -> {
+        mMainExecutor.execute(() -> {
             boolean shouldSaveView = true;
             try {
                 wm.addView(view, params);
@@ -286,25 +412,32 @@
 
             if (shouldSaveView) {
                 removeWindowSynced(taskId);
-                mHandler.postDelayed(() -> removeWindowSynced(taskId), REMOVE_WHEN_TIMEOUT);
-                final TaskScreenView tView = new TaskScreenView(view);
-                mTaskScreenViews.put(taskId, tView);
+                mMainExecutor.executeDelayed(() -> removeWindowSynced(taskId), REMOVE_WHEN_TIMEOUT);
+                final StartingWindowRecord tView =
+                        new StartingWindowRecord(view, null /* TaskSnapshotWindow */);
+                mStartingWindowRecords.put(taskId, tView);
             }
         });
     }
 
     protected void removeWindowSynced(int taskId) {
-        final TaskScreenView preView = mTaskScreenViews.get(taskId);
-        if (preView != null) {
-            if (preView.mDecorView != null) {
+        final StartingWindowRecord record = mStartingWindowRecords.get(taskId);
+        if (record != null) {
+            if (record.mDecorView != null) {
                 if (DEBUG_SPLASH_SCREEN) {
                     Slog.v(TAG, "Removing splash screen window for task: " + taskId);
                 }
-                final WindowManager wm = preView.mDecorView.getContext()
+                final WindowManager wm = record.mDecorView.getContext()
                         .getSystemService(WindowManager.class);
-                wm.removeView(preView.mDecorView);
+                wm.removeView(record.mDecorView);
             }
-            mTaskScreenViews.remove(taskId);
+            if (record.mTaskSnapshotWindow != null) {
+                if (DEBUG_TASK_SNAPSHOT) {
+                    Slog.v(TAG, "Removing task snapshot window for " + taskId);
+                }
+                record.mTaskSnapshotWindow.remove(mMainExecutor);
+            }
+            mStartingWindowRecords.remove(taskId);
         }
     }
 
@@ -315,13 +448,15 @@
     }
 
     /**
-     * Record the views in a starting window.
+     * Record the view or surface for a starting window.
      */
-    private static class TaskScreenView {
+    private static class StartingWindowRecord {
         private final View mDecorView;
+        private final TaskSnapshotWindow mTaskSnapshotWindow;
 
-        TaskScreenView(View decorView) {
+        StartingWindowRecord(View decorView, TaskSnapshotWindow taskSnapshotWindow) {
             mDecorView = decorView;
+            mTaskSnapshotWindow = taskSnapshotWindow;
         }
     }
 
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/TaskSnapshotWindow.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/TaskSnapshotWindow.java
new file mode 100644
index 0000000..e66d85f
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/TaskSnapshotWindow.java
@@ -0,0 +1,622 @@
+/*
+ * 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.startingsurface;
+
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
+import static android.graphics.Color.WHITE;
+import static android.graphics.Color.alpha;
+import static android.view.WindowInsetsController.APPEARANCE_LIGHT_NAVIGATION_BARS;
+import static android.view.WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS;
+import static android.view.WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
+import static android.view.WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
+import static android.view.WindowManager.LayoutParams.FLAG_IGNORE_CHEEK_PRESSES;
+import static android.view.WindowManager.LayoutParams.FLAG_LOCAL_FOCUS_MODE;
+import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
+import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
+import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
+import static android.view.WindowManager.LayoutParams.FLAG_SCALED;
+import static android.view.WindowManager.LayoutParams.FLAG_SECURE;
+import static android.view.WindowManager.LayoutParams.FLAG_SLIPPERY;
+import static android.view.WindowManager.LayoutParams.FLAG_SPLIT_TOUCH;
+import static android.view.WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION;
+import static android.view.WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS;
+import static android.view.WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH;
+import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_DRAW_BAR_BACKGROUNDS;
+import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_TRUSTED_OVERLAY;
+import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
+
+import static com.android.internal.policy.DecorView.NAVIGATION_BAR_COLOR_VIEW_ATTRIBUTES;
+import static com.android.internal.policy.DecorView.STATUS_BAR_COLOR_VIEW_ATTRIBUTES;
+import static com.android.internal.policy.DecorView.getNavigationBarRect;
+
+import android.annotation.Nullable;
+import android.app.ActivityManager;
+import android.app.ActivityManager.TaskDescription;
+import android.app.ActivityThread;
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Matrix;
+import android.graphics.Paint;
+import android.graphics.Point;
+import android.graphics.Rect;
+import android.graphics.RectF;
+import android.hardware.HardwareBuffer;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.os.SystemClock;
+import android.util.MergedConfiguration;
+import android.util.Slog;
+import android.view.IWindowSession;
+import android.view.InputChannel;
+import android.view.InsetsSourceControl;
+import android.view.InsetsState;
+import android.view.Surface;
+import android.view.SurfaceControl;
+import android.view.SurfaceSession;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.WindowInsets;
+import android.view.WindowManager;
+import android.view.WindowManagerGlobal;
+import android.window.ClientWindowFrames;
+import android.window.StartingWindowInfo;
+import android.window.TaskSnapshot;
+
+import com.android.internal.R;
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.policy.DecorView;
+import com.android.internal.view.BaseIWindow;
+import com.android.wm.shell.common.ShellExecutor;
+
+/**
+ * This class represents a starting window that shows a snapshot.
+ *
+ * @hide
+ */
+public class TaskSnapshotWindow {
+
+    private static final long SIZE_MISMATCH_MINIMUM_TIME_MS = 450;
+
+    /**
+     * When creating the starting window, we use the exact same layout flags such that we end up
+     * with a window with the exact same dimensions etc. However, these flags are not used in layout
+     * and might cause other side effects so we exclude them.
+     */
+    static final int FLAG_INHERIT_EXCLUDES = FLAG_NOT_FOCUSABLE
+            | FLAG_NOT_TOUCHABLE
+            | FLAG_NOT_TOUCH_MODAL
+            | FLAG_ALT_FOCUSABLE_IM
+            | FLAG_NOT_FOCUSABLE
+            | FLAG_HARDWARE_ACCELERATED
+            | FLAG_IGNORE_CHEEK_PRESSES
+            | FLAG_LOCAL_FOCUS_MODE
+            | FLAG_SLIPPERY
+            | FLAG_WATCH_OUTSIDE_TOUCH
+            | FLAG_SPLIT_TOUCH
+            | FLAG_SCALED
+            | FLAG_SECURE;
+
+    private static final String TAG = StartingSurfaceDrawer.TAG;
+    private static final boolean DEBUG = StartingSurfaceDrawer.DEBUG_TASK_SNAPSHOT;
+    private static final String TITLE_FORMAT = "SnapshotStartingWindow for taskId=%s";
+
+    //tmp vars for unused relayout params
+    private static final Point TMP_SURFACE_SIZE = new Point();
+
+    private final Window mWindow;
+    private final Surface mSurface;
+    private final Runnable mClearWindowHandler;
+    private SurfaceControl mSurfaceControl;
+    private SurfaceControl mChildSurfaceControl;
+    private final IWindowSession mSession;
+    private final Rect mTaskBounds;
+    private final Rect mFrame = new Rect();
+    private final Rect mSystemBarInsets = new Rect();
+    private TaskSnapshot mSnapshot;
+    private final RectF mTmpSnapshotSize = new RectF();
+    private final RectF mTmpDstFrame = new RectF();
+    private final CharSequence mTitle;
+    private boolean mHasDrawn;
+    private long mShownTime;
+    private boolean mSizeMismatch;
+    private final Paint mBackgroundPaint = new Paint();
+    private final int mActivityType;
+    private final int mStatusBarColor;
+    private final SystemBarBackgroundPainter mSystemBarBackgroundPainter;
+    private final int mOrientationOnCreation;
+    private final SurfaceControl.Transaction mTransaction;
+    private final Matrix mSnapshotMatrix = new Matrix();
+    private final float[] mTmpFloat9 = new float[9];
+
+    static TaskSnapshotWindow create(StartingWindowInfo info, IBinder appToken,
+            TaskSnapshot snapshot, ShellExecutor mainExecutor, Runnable clearWindowHandler) {
+        final ActivityManager.RunningTaskInfo runningTaskInfo = info.taskInfo;
+        final int taskId = runningTaskInfo.taskId;
+        if (DEBUG) {
+            Slog.d(TAG, "create taskSnapshot surface for task: " + taskId);
+        }
+
+        final WindowManager.LayoutParams attrs = info.topOpaqueWindowLayoutParams;
+        final WindowManager.LayoutParams mainWindowParams = info.mainWindowLayoutParams;
+        final InsetsState topWindowInsetsState = info.topOpaqueWindowInsetsState;
+        if (attrs == null || mainWindowParams == null || topWindowInsetsState == null) {
+            Slog.w(TAG, "unable to create taskSnapshot surface for task: " + taskId);
+            return null;
+        }
+        final WindowManager.LayoutParams layoutParams = new WindowManager.LayoutParams();
+
+        final int appearance = attrs.insetsFlags.appearance;
+        final int windowFlags = attrs.flags;
+        final int windowPrivateFlags = attrs.privateFlags;
+
+        layoutParams.packageName = mainWindowParams.packageName;
+        layoutParams.windowAnimations = mainWindowParams.windowAnimations;
+        layoutParams.dimAmount = mainWindowParams.dimAmount;
+        layoutParams.type = TYPE_APPLICATION_STARTING;
+        layoutParams.format = snapshot.getHardwareBuffer().getFormat();
+        layoutParams.flags = (windowFlags & ~FLAG_INHERIT_EXCLUDES)
+                | FLAG_NOT_FOCUSABLE
+                | FLAG_NOT_TOUCHABLE;
+        // Setting as trusted overlay to let touches pass through. This is safe because this
+        // window is controlled by the system.
+        layoutParams.privateFlags = (windowPrivateFlags & PRIVATE_FLAG_FORCE_DRAW_BAR_BACKGROUNDS)
+                | PRIVATE_FLAG_TRUSTED_OVERLAY;
+        layoutParams.token = appToken;
+        layoutParams.width = ViewGroup.LayoutParams.MATCH_PARENT;
+        layoutParams.height = ViewGroup.LayoutParams.MATCH_PARENT;
+        layoutParams.insetsFlags.appearance = appearance;
+        layoutParams.insetsFlags.behavior = attrs.insetsFlags.behavior;
+        layoutParams.layoutInDisplayCutoutMode = attrs.layoutInDisplayCutoutMode;
+        layoutParams.setFitInsetsTypes(attrs.getFitInsetsTypes());
+        layoutParams.setFitInsetsSides(attrs.getFitInsetsSides());
+        layoutParams.setFitInsetsIgnoringVisibility(attrs.isFitInsetsIgnoringVisibility());
+
+        layoutParams.setTitle(String.format(TITLE_FORMAT, taskId));
+
+        final Point taskSize = snapshot.getTaskSize();
+        final Rect taskBounds = new Rect(0, 0, taskSize.x, taskSize.y);
+        final int orientation = snapshot.getOrientation();
+
+        final int activityType = runningTaskInfo.topActivityType;
+        final int displayId = runningTaskInfo.displayId;
+
+        final IWindowSession session = WindowManagerGlobal.getWindowSession();
+        final SurfaceControl surfaceControl = new SurfaceControl();
+        final ClientWindowFrames tmpFrames = new ClientWindowFrames();
+
+        final InsetsSourceControl[] mTempControls = new InsetsSourceControl[0];
+        final MergedConfiguration tmpMergedConfiguration = new MergedConfiguration();
+
+        final TaskDescription taskDescription;
+        if (runningTaskInfo.taskDescription != null) {
+            taskDescription = runningTaskInfo.taskDescription;
+        } else {
+            taskDescription = new TaskDescription();
+            taskDescription.setBackgroundColor(WHITE);
+        }
+
+        final TaskSnapshotWindow snapshotSurface = new TaskSnapshotWindow(
+                surfaceControl, snapshot, layoutParams.getTitle(), taskDescription, appearance,
+                windowFlags, windowPrivateFlags, taskBounds, orientation, activityType,
+                topWindowInsetsState, clearWindowHandler);
+        final Window window = snapshotSurface.mWindow;
+
+        final InsetsState mTmpInsetsState = new InsetsState();
+        final InputChannel tmpInputChannel = new InputChannel();
+        mainExecutor.execute(() -> {
+            try {
+                final int res = session.addToDisplay(window, layoutParams, View.GONE,
+                        displayId, mTmpInsetsState, tmpFrames.frame,
+                        tmpFrames.displayCutout, tmpInputChannel/* outInputChannel */,
+                        mTmpInsetsState, mTempControls);
+                if (res < 0) {
+                    Slog.w(TAG, "Failed to add snapshot starting window res=" + res);
+                    return;
+                }
+            } catch (RemoteException e) {
+                snapshotSurface.clearWindowSynced();
+            }
+            window.setOuter(snapshotSurface, mainExecutor);
+            try {
+                session.relayout(window, layoutParams, -1, -1, View.VISIBLE, 0, -1,
+                        tmpFrames, tmpMergedConfiguration, surfaceControl, mTmpInsetsState,
+                        mTempControls, TMP_SURFACE_SIZE);
+            } catch (RemoteException e) {
+                snapshotSurface.clearWindowSynced();
+            }
+
+            final Rect systemBarInsets = getSystemBarInsets(tmpFrames.frame, topWindowInsetsState);
+            snapshotSurface.setFrames(tmpFrames.frame, systemBarInsets);
+            snapshotSurface.drawSnapshot();
+        });
+        return snapshotSurface;
+    }
+
+    public TaskSnapshotWindow(SurfaceControl surfaceControl,
+            TaskSnapshot snapshot, CharSequence title, TaskDescription taskDescription,
+            int appearance, int windowFlags, int windowPrivateFlags, Rect taskBounds,
+            int currentOrientation, int activityType, InsetsState topWindowInsetsState,
+            Runnable clearWindowHandler) {
+        mSurface = new Surface();
+        mSession = WindowManagerGlobal.getWindowSession();
+        mWindow = new Window();
+        mWindow.setSession(mSession);
+        mSurfaceControl = surfaceControl;
+        mSnapshot = snapshot;
+        mTitle = title;
+        int backgroundColor = taskDescription.getBackgroundColor();
+        mBackgroundPaint.setColor(backgroundColor != 0 ? backgroundColor : WHITE);
+        mTaskBounds = taskBounds;
+        mSystemBarBackgroundPainter = new SystemBarBackgroundPainter(windowFlags,
+                windowPrivateFlags, appearance, taskDescription, 1f, topWindowInsetsState);
+        mStatusBarColor = taskDescription.getStatusBarColor();
+        mOrientationOnCreation = currentOrientation;
+        mActivityType = activityType;
+        mTransaction = new SurfaceControl.Transaction();
+        mClearWindowHandler = clearWindowHandler;
+    }
+
+    /**
+     * Ask system bar background painter to draw status bar background.
+     * @hide
+     */
+    public void drawStatusBarBackground(Canvas c, @Nullable Rect alreadyDrawnFrame) {
+        mSystemBarBackgroundPainter.drawStatusBarBackground(c, alreadyDrawnFrame,
+                mSystemBarBackgroundPainter.getStatusBarColorViewHeight());
+    }
+
+    /**
+     * Ask system bar background painter to draw navigation bar background.
+     * @hide
+     */
+    public void drawNavigationBarBackground(Canvas c) {
+        mSystemBarBackgroundPainter.drawNavigationBarBackground(c);
+    }
+
+    void remove(ShellExecutor mainExecutor) {
+        final long now = SystemClock.uptimeMillis();
+        if (mSizeMismatch && now - mShownTime < SIZE_MISMATCH_MINIMUM_TIME_MS
+                // Show the latest content as soon as possible for unlocking to home.
+                && mActivityType != ACTIVITY_TYPE_HOME) {
+            final long delayTime = mShownTime + SIZE_MISMATCH_MINIMUM_TIME_MS - now;
+            mainExecutor.executeDelayed(() -> remove(mainExecutor), delayTime);
+            if (DEBUG) {
+                Slog.d(TAG, "Defer removing snapshot surface in " + delayTime);
+            }
+            return;
+        }
+        mainExecutor.execute(() -> {
+            try {
+                if (DEBUG) {
+                    Slog.d(TAG, "Removing snapshot surface, mHasDrawn: " + mHasDrawn);
+                }
+                mSession.remove(mWindow);
+            } catch (RemoteException e) {
+                // nothing
+            }
+        });
+    }
+
+    /**
+     * Set frame size.
+     * @hide
+     */
+    public void setFrames(Rect frame, Rect systemBarInsets) {
+        mFrame.set(frame);
+        mSystemBarInsets.set(systemBarInsets);
+        final HardwareBuffer snapshot = mSnapshot.getHardwareBuffer();
+        mSizeMismatch = (mFrame.width() != snapshot.getWidth()
+                || mFrame.height() != snapshot.getHeight());
+        mSystemBarBackgroundPainter.setInsets(systemBarInsets);
+    }
+
+    static Rect getSystemBarInsets(Rect frame, InsetsState state) {
+        return state.calculateInsets(frame, WindowInsets.Type.systemBars(),
+                false /* ignoreVisibility */);
+    }
+
+    private void drawSnapshot() {
+        mSurface.copyFrom(mSurfaceControl);
+        if (DEBUG) {
+            Slog.d(TAG, "Drawing snapshot surface sizeMismatch= " + mSizeMismatch);
+        }
+        if (mSizeMismatch) {
+            // The dimensions of the buffer and the window don't match, so attaching the buffer
+            // will fail. Better create a child window with the exact dimensions and fill the parent
+            // window with the background color!
+            drawSizeMismatchSnapshot();
+        } else {
+            drawSizeMatchSnapshot();
+        }
+        mShownTime = SystemClock.uptimeMillis();
+        mHasDrawn = true;
+        reportDrawn();
+
+        // In case window manager leaks us, make sure we don't retain the snapshot.
+        mSnapshot = null;
+    }
+
+    private void drawSizeMatchSnapshot() {
+        mSurface.attachAndQueueBufferWithColorSpace(mSnapshot.getHardwareBuffer(),
+                mSnapshot.getColorSpace());
+        mSurface.release();
+    }
+
+    private void drawSizeMismatchSnapshot() {
+        if (!mSurface.isValid()) {
+            throw new IllegalStateException("mSurface does not hold a valid surface.");
+        }
+        final HardwareBuffer buffer = mSnapshot.getHardwareBuffer();
+        final SurfaceSession session = new SurfaceSession();
+
+        // We consider nearly matched dimensions as there can be rounding errors and the user won't
+        // notice very minute differences from scaling one dimension more than the other
+        final boolean aspectRatioMismatch = Math.abs(
+                ((float) buffer.getWidth() / buffer.getHeight())
+                - ((float) mFrame.width() / mFrame.height())) > 0.01f;
+
+        // Keep a reference to it such that it doesn't get destroyed when finalized.
+        mChildSurfaceControl = new SurfaceControl.Builder(session)
+                .setName(mTitle + " - task-snapshot-surface")
+                .setBufferSize(buffer.getWidth(), buffer.getHeight())
+                .setFormat(buffer.getFormat())
+                .setParent(mSurfaceControl)
+                .setCallsite("TaskSnapshotWindow.drawSizeMismatchSnapshot")
+                .build();
+        Surface surface = new Surface();
+        surface.copyFrom(mChildSurfaceControl);
+
+        final Rect frame;
+        // We can just show the surface here as it will still be hidden as the parent is
+        // still hidden.
+        mTransaction.show(mChildSurfaceControl);
+        if (aspectRatioMismatch) {
+            // Clip off ugly navigation bar.
+            final Rect crop = calculateSnapshotCrop();
+            frame = calculateSnapshotFrame(crop);
+            mTransaction.setWindowCrop(mChildSurfaceControl, crop);
+            mTransaction.setPosition(mChildSurfaceControl, frame.left, frame.top);
+            mTmpSnapshotSize.set(crop);
+            mTmpDstFrame.set(frame);
+        } else {
+            frame = null;
+            mTmpSnapshotSize.set(0, 0, buffer.getWidth(), buffer.getHeight());
+            mTmpDstFrame.set(mFrame);
+            mTmpDstFrame.offsetTo(0, 0);
+        }
+
+        // Scale the mismatch dimensions to fill the task bounds
+        mSnapshotMatrix.setRectToRect(mTmpSnapshotSize, mTmpDstFrame, Matrix.ScaleToFit.FILL);
+        mTransaction.setMatrix(mChildSurfaceControl, mSnapshotMatrix, mTmpFloat9);
+
+        mTransaction.apply();
+        surface.attachAndQueueBufferWithColorSpace(buffer, mSnapshot.getColorSpace());
+        surface.release();
+
+        if (aspectRatioMismatch) {
+            final Canvas c = mSurface.lockCanvas(null);
+            drawBackgroundAndBars(c, frame);
+            mSurface.unlockCanvasAndPost(c);
+            mSurface.release();
+        }
+    }
+
+    /**
+     * Calculates the snapshot crop in snapshot coordinate space.
+     *
+     * @return crop rect in snapshot coordinate space.
+     */
+    public Rect calculateSnapshotCrop() {
+        final Rect rect = new Rect();
+        final HardwareBuffer snapshot = mSnapshot.getHardwareBuffer();
+        rect.set(0, 0, snapshot.getWidth(), snapshot.getHeight());
+        final Rect insets = mSnapshot.getContentInsets();
+
+        final float scaleX = (float) snapshot.getWidth() / mSnapshot.getTaskSize().x;
+        final float scaleY = (float) snapshot.getHeight() / mSnapshot.getTaskSize().y;
+
+        // Let's remove all system decorations except the status bar, but only if the task is at the
+        // very top of the screen.
+        final boolean isTop = mTaskBounds.top == 0 && mFrame.top == 0;
+        rect.inset((int) (insets.left * scaleX),
+                isTop ? 0 : (int) (insets.top * scaleY),
+                (int) (insets.right * scaleX),
+                (int) (insets.bottom * scaleY));
+        return rect;
+    }
+
+    /**
+     * Calculates the snapshot frame in window coordinate space from crop.
+     *
+     * @param crop rect that is in snapshot coordinate space.
+     */
+    public Rect calculateSnapshotFrame(Rect crop) {
+        final HardwareBuffer snapshot = mSnapshot.getHardwareBuffer();
+        final float scaleX = (float) snapshot.getWidth() / mSnapshot.getTaskSize().x;
+        final float scaleY = (float) snapshot.getHeight() / mSnapshot.getTaskSize().y;
+
+        // Rescale the frame from snapshot to window coordinate space
+        final Rect frame = new Rect(0, 0,
+                (int) (crop.width() / scaleX + 0.5f),
+                (int) (crop.height() / scaleY + 0.5f)
+        );
+
+        // However, we also need to make space for the navigation bar on the left side.
+        frame.offset(mSystemBarInsets.left, 0);
+        return frame;
+    }
+
+    /**
+     * Draw status bar and navigation bar background.
+     * @hide
+     */
+    public void drawBackgroundAndBars(Canvas c, Rect frame) {
+        final int statusBarHeight = mSystemBarBackgroundPainter.getStatusBarColorViewHeight();
+        final boolean fillHorizontally = c.getWidth() > frame.right;
+        final boolean fillVertically = c.getHeight() > frame.bottom;
+        if (fillHorizontally) {
+            c.drawRect(frame.right, alpha(mStatusBarColor) == 0xFF ? statusBarHeight : 0,
+                    c.getWidth(), fillVertically
+                            ? frame.bottom
+                            : c.getHeight(),
+                    mBackgroundPaint);
+        }
+        if (fillVertically) {
+            c.drawRect(0, frame.bottom, c.getWidth(), c.getHeight(), mBackgroundPaint);
+        }
+        mSystemBarBackgroundPainter.drawDecors(c, frame);
+    }
+
+    /**
+     * Clear window from drawer, must be post on main executor.
+     */
+    private void clearWindowSynced() {
+        if (mClearWindowHandler != null) {
+            mClearWindowHandler.run();
+        }
+    }
+
+    private void reportDrawn() {
+        try {
+            mSession.finishDrawing(mWindow, null /* postDrawTransaction */);
+        } catch (RemoteException e) {
+            clearWindowSynced();
+        }
+    }
+
+    static class Window extends BaseIWindow {
+        private TaskSnapshotWindow mOuter;
+        private ShellExecutor mMainExecutor;
+
+        public void setOuter(TaskSnapshotWindow outer, ShellExecutor mainExecutor) {
+            mOuter = outer;
+            mMainExecutor = mainExecutor;
+        }
+
+        @Override
+        public void resized(ClientWindowFrames frames, boolean reportDraw,
+                MergedConfiguration mergedConfiguration, boolean forceLayout,
+                boolean alwaysConsumeSystemBars, int displayId) {
+            if (mOuter != null) {
+                if (mergedConfiguration != null
+                        && mOuter.mOrientationOnCreation
+                        != mergedConfiguration.getMergedConfiguration().orientation) {
+                    // The orientation of the screen is changing. We better remove the snapshot ASAP
+                    // as we are going to wait on the new window in any case to unfreeze the screen,
+                    // and the starting window is not needed anymore.
+                    mMainExecutor.execute(() -> {
+                        mOuter.clearWindowSynced();
+                    });
+                } else if (reportDraw) {
+                    mMainExecutor.execute(() -> {
+                        if (mOuter.mHasDrawn) {
+                            mOuter.reportDrawn();
+                        }
+                    });
+                }
+            }
+        }
+    }
+
+    /**
+     * Helper class to draw the background of the system bars in regions the task snapshot isn't
+     * filling the window.
+     */
+    static class SystemBarBackgroundPainter {
+        private final Paint mStatusBarPaint = new Paint();
+        private final Paint mNavigationBarPaint = new Paint();
+        private final int mStatusBarColor;
+        private final int mNavigationBarColor;
+        private final int mWindowFlags;
+        private final int mWindowPrivateFlags;
+        private final float mScale;
+        private final InsetsState mInsetsState;
+        private final Rect mSystemBarInsets = new Rect();
+
+        SystemBarBackgroundPainter(int windowFlags, int windowPrivateFlags, int appearance,
+                TaskDescription taskDescription, float scale, InsetsState insetsState) {
+            mWindowFlags = windowFlags;
+            mWindowPrivateFlags = windowPrivateFlags;
+            mScale = scale;
+            final Context context = ActivityThread.currentActivityThread().getSystemUiContext();
+            final int semiTransparent = context.getColor(
+                    R.color.system_bar_background_semi_transparent);
+            mStatusBarColor = DecorView.calculateBarColor(windowFlags, FLAG_TRANSLUCENT_STATUS,
+                    semiTransparent, taskDescription.getStatusBarColor(), appearance,
+                    APPEARANCE_LIGHT_STATUS_BARS,
+                    taskDescription.getEnsureStatusBarContrastWhenTransparent());
+            mNavigationBarColor = DecorView.calculateBarColor(windowFlags,
+                    FLAG_TRANSLUCENT_NAVIGATION, semiTransparent,
+                    taskDescription.getNavigationBarColor(), appearance,
+                    APPEARANCE_LIGHT_NAVIGATION_BARS,
+                    taskDescription.getEnsureNavigationBarContrastWhenTransparent()
+                            && context.getResources().getBoolean(R.bool.config_navBarNeedsScrim));
+            mStatusBarPaint.setColor(mStatusBarColor);
+            mNavigationBarPaint.setColor(mNavigationBarColor);
+            mInsetsState = insetsState;
+        }
+
+        void setInsets(Rect systemBarInsets) {
+            mSystemBarInsets.set(systemBarInsets);
+        }
+
+        int getStatusBarColorViewHeight() {
+            final boolean forceBarBackground =
+                    (mWindowPrivateFlags & PRIVATE_FLAG_FORCE_DRAW_BAR_BACKGROUNDS) != 0;
+            if (STATUS_BAR_COLOR_VIEW_ATTRIBUTES.isVisible(
+                    mInsetsState, mStatusBarColor, mWindowFlags, forceBarBackground)) {
+                return (int) (mSystemBarInsets.top * mScale);
+            } else {
+                return 0;
+            }
+        }
+
+        private boolean isNavigationBarColorViewVisible() {
+            final boolean forceBarBackground =
+                    (mWindowPrivateFlags & PRIVATE_FLAG_FORCE_DRAW_BAR_BACKGROUNDS) != 0;
+            return NAVIGATION_BAR_COLOR_VIEW_ATTRIBUTES.isVisible(
+                    mInsetsState, mNavigationBarColor, mWindowFlags, forceBarBackground);
+        }
+
+        void drawDecors(Canvas c, @Nullable Rect alreadyDrawnFrame) {
+            drawStatusBarBackground(c, alreadyDrawnFrame, getStatusBarColorViewHeight());
+            drawNavigationBarBackground(c);
+        }
+
+        void drawStatusBarBackground(Canvas c, @Nullable Rect alreadyDrawnFrame,
+                int statusBarHeight) {
+            if (statusBarHeight > 0 && Color.alpha(mStatusBarColor) != 0
+                    && (alreadyDrawnFrame == null || c.getWidth() > alreadyDrawnFrame.right)) {
+                final int rightInset = (int) (mSystemBarInsets.right * mScale);
+                final int left = alreadyDrawnFrame != null ? alreadyDrawnFrame.right : 0;
+                c.drawRect(left, 0, c.getWidth() - rightInset, statusBarHeight, mStatusBarPaint);
+            }
+        }
+
+        @VisibleForTesting
+        void drawNavigationBarBackground(Canvas c) {
+            final Rect navigationBarRect = new Rect();
+            getNavigationBarRect(c.getWidth(), c.getHeight(), mSystemBarInsets, navigationBarRect,
+                    mScale);
+            final boolean visible = isNavigationBarColorViewVisible();
+            if (visible && Color.alpha(mNavigationBarColor) != 0 && !navigationBarRect.isEmpty()) {
+                c.drawRect(navigationBarRect, mNavigationBarPaint);
+            }
+        }
+    }
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/CommonAssertions.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/CommonAssertions.kt
index c5b54bc..e3ac3f0 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/CommonAssertions.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/CommonAssertions.kt
@@ -17,6 +17,7 @@
 package com.android.wm.shell.flicker
 
 import android.graphics.Region
+import com.android.server.wm.flicker.DOCKED_STACK_DIVIDER
 import com.android.server.wm.flicker.dsl.EventLogAssertion
 import com.android.server.wm.flicker.dsl.LayersAssertion
 import com.android.server.wm.flicker.helpers.WindowUtils
@@ -52,6 +53,30 @@
 }
 
 @JvmOverloads
+fun LayersAssertion.dockedStackDividerBecomesVisible(
+    bugId: Int = 0,
+    enabled: Boolean = bugId == 0
+) {
+    all("dividerLayerBecomesVisible") {
+        this.hidesLayer(DOCKED_STACK_DIVIDER)
+                .then()
+                .showsLayer(DOCKED_STACK_DIVIDER)
+    }
+}
+
+@JvmOverloads
+fun LayersAssertion.dockedStackDividerBecomesInvisible(
+    bugId: Int = 0,
+    enabled: Boolean = bugId == 0
+) {
+    all("dividerLayerBecomesInvisible") {
+        this.showsLayer(DOCKED_STACK_DIVIDER)
+                .then()
+                .hidesLayer(DOCKED_STACK_DIVIDER)
+    }
+}
+
+@JvmOverloads
 fun LayersAssertion.dockedStackDividerIsInvisible(
     bugId: Int = 0,
     enabled: Boolean = bugId == 0
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/ImeAppHelper.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/ImeAppHelper.kt
index d580104..c546a4d 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/ImeAppHelper.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/ImeAppHelper.kt
@@ -20,7 +20,6 @@
 import androidx.test.uiautomator.By
 import androidx.test.uiautomator.Until
 import com.android.server.wm.flicker.helpers.FIND_TIMEOUT
-import com.android.server.wm.flicker.helpers.waitForIME
 import com.android.wm.shell.flicker.TEST_APP_IME_ACTIVITY_LABEL
 import com.android.wm.shell.flicker.testapp.Components
 import org.junit.Assert
@@ -39,14 +38,9 @@
         Assert.assertNotNull("Text field not found, this usually happens when the device " +
                 "was left in an unknown state (e.g. in split screen)", editText)
         editText.click()
-        if (!uiDevice.waitForIME()) {
-            Assert.fail("IME did not appear")
-        }
     }
 
     fun closeIME() {
         uiDevice.pressBack()
-        // Using only the AccessibilityInfo it is not possible to identify if the IME is active
-        uiDevice.waitForIdle(1000)
     }
 }
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterLegacySplitScreenTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterLegacySplitScreenTest.kt
index 02f6f8c..b33fa55 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterLegacySplitScreenTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/EnterLegacySplitScreenTest.kt
@@ -27,9 +27,9 @@
 import com.android.server.wm.flicker.helpers.isInSplitScreen
 import com.android.server.wm.flicker.helpers.launchSplitScreen
 import com.android.server.wm.flicker.helpers.openQuickstep
+import com.android.server.wm.flicker.helpers.openQuickStepAndClearRecentAppsFromOverview
 import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen
 import com.android.wm.shell.flicker.dockedStackDividerIsInvisible
-import com.android.wm.shell.flicker.dockedStackDividerIsVisible
 import com.android.wm.shell.flicker.helpers.SplitScreenHelper.Companion.TEST_REPETITIONS
 import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible
 import com.android.server.wm.flicker.statusBarLayerIsAlwaysVisible
@@ -38,6 +38,9 @@
 import com.android.wm.shell.flicker.dockedStackPrimaryBoundsIsVisible
 import com.android.wm.shell.flicker.dockedStackSecondaryBoundsIsVisible
 import org.junit.Assert
+import com.android.wm.shell.flicker.dockedStackDividerBecomesVisible
+import com.android.server.wm.flicker.visibleWindowsShownMoreThanOneConsecutiveEntry
+import com.android.server.wm.flicker.visibleLayersShownMoreThanOneConsecutiveEntry
 import org.junit.FixMethodOrder
 import org.junit.Test
 import org.junit.runner.RunWith
@@ -46,7 +49,7 @@
 
 /**
  * Test SplitScreen launch.
- * To run this test: `atest WMShellFlickerTests:EnterSplitScreenTest`
+ * To run this test: `atest WMShellFlickerTests:EnterLegacySplitScreenTest`
  */
 @Presubmit
 @RequiresDevice
@@ -56,6 +59,8 @@
     rotationName: String,
     rotation: Int
 ) : SplitScreenTestBase(rotationName, rotation) {
+    private val letterBox = "Letterbox"
+
     private val splitScreenSetup: FlickerBuilder
         get() = FlickerBuilder(instrumentation).apply {
             val testLaunchActivity = "launch_splitScreen_test_activity"
@@ -65,6 +70,7 @@
             setup {
                 eachRun {
                     uiDevice.wakeUpAndGoToHomeScreen()
+                    uiDevice.openQuickStepAndClearRecentAppsFromOverview()
                 }
             }
             teardown {
@@ -85,6 +91,7 @@
                 windowManagerTrace {
                     navBarWindowIsAlwaysVisible()
                     statusBarWindowIsAlwaysVisible()
+                    visibleWindowsShownMoreThanOneConsecutiveEntry(listOf(launcherPackageName))
                 }
             }
         }
@@ -103,9 +110,12 @@
             }
             assertions {
                 layersTrace {
-                    dockedStackDividerIsVisible()
                     dockedStackPrimaryBoundsIsVisible(
                             rotation, splitScreenApp.defaultWindowName, 169271943)
+                    dockedStackDividerBecomesVisible()
+                    visibleLayersShownMoreThanOneConsecutiveEntry(
+                            listOf(launcherPackageName, splitScreenApp.defaultWindowName)
+                    )
                 }
                 windowManagerTrace {
                     end {
@@ -132,11 +142,15 @@
             }
             assertions {
                 layersTrace {
-                    dockedStackDividerIsVisible()
                     dockedStackPrimaryBoundsIsVisible(
                             rotation, splitScreenApp.defaultWindowName, 169271943)
                     dockedStackSecondaryBoundsIsVisible(
                             rotation, secondaryApp.defaultWindowName, 169271943)
+                    dockedStackDividerBecomesVisible()
+                    visibleLayersShownMoreThanOneConsecutiveEntry(
+                            listOf(launcherPackageName, splitScreenApp.defaultWindowName,
+                                    secondaryApp.defaultWindowName)
+                    )
                 }
                 windowManagerTrace {
                     end {
@@ -166,6 +180,9 @@
             assertions {
                 layersTrace {
                     dockedStackDividerIsInvisible()
+                    visibleLayersShownMoreThanOneConsecutiveEntry(
+                            listOf(launcherPackageName, nonResizeableApp.defaultWindowName)
+                    )
                 }
                 windowManagerTrace {
                     end {
@@ -197,6 +214,10 @@
                         val displayBounds = WindowUtils.getDisplayBounds(rotation)
                         this.hasVisibleRegion(nonResizeableApp.defaultWindowName, displayBounds)
                     }
+                    visibleLayersShownMoreThanOneConsecutiveEntry(
+                            listOf(launcherPackageName, splitScreenApp.defaultWindowName,
+                                    nonResizeableApp.defaultWindowName, letterBox)
+                    )
                 }
                 windowManagerTrace {
                     end {
@@ -229,6 +250,10 @@
                         val displayBounds = WindowUtils.getDisplayBounds(rotation)
                         this.hasVisibleRegion(nonResizeableApp.defaultWindowName, displayBounds)
                     }
+                    visibleLayersShownMoreThanOneConsecutiveEntry(
+                            listOf(launcherPackageName, splitScreenApp.defaultWindowName,
+                                    nonResizeableApp.defaultWindowName, letterBox)
+                    )
                 }
                 windowManagerTrace {
                     end {
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ExitLegacySplitScreenFromBottomTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ExitLegacySplitScreenFromBottomTest.kt
new file mode 100644
index 0000000..573ffc6
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ExitLegacySplitScreenFromBottomTest.kt
@@ -0,0 +1,94 @@
+/*
+ * 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.flicker.legacysplitscreen
+
+import android.view.Surface
+import androidx.test.filters.RequiresDevice
+import androidx.test.platform.app.InstrumentationRegistry
+import com.android.server.wm.flicker.Flicker
+import com.android.server.wm.flicker.FlickerTestRunner
+import com.android.server.wm.flicker.FlickerTestRunnerFactory
+import com.android.server.wm.flicker.helpers.StandardAppHelper
+import com.android.server.wm.flicker.endRotation
+import com.android.server.wm.flicker.helpers.buildTestTag
+import com.android.server.wm.flicker.helpers.exitSplitScreen
+import com.android.server.wm.flicker.helpers.exitSplitScreenFromBottom
+import com.android.server.wm.flicker.helpers.isInSplitScreen
+import com.android.server.wm.flicker.helpers.launchSplitScreen
+import com.android.server.wm.flicker.helpers.setRotation
+import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen
+import com.android.server.wm.flicker.repetitions
+import org.junit.FixMethodOrder
+import org.junit.runner.RunWith
+import org.junit.runners.MethodSorters
+import org.junit.runners.Parameterized
+
+/**
+ * Test open app to split screen.
+ * To run this test: `atest WMShellFlickerTests:ExitLegacySplitScreenFromBottomTest`
+ */
+@RequiresDevice
+@RunWith(Parameterized::class)
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+class ExitLegacySplitScreenFromBottomTest(
+    testName: String,
+    flickerSpec: Flicker
+) : FlickerTestRunner(testName, flickerSpec) {
+    companion object {
+        @Parameterized.Parameters(name = "{0}")
+        @JvmStatic
+        fun getParams(): Collection<Array<Any>> {
+            val instrumentation = InstrumentationRegistry.getInstrumentation()
+            val testApp = StandardAppHelper(instrumentation,
+                    "com.android.wm.shell.flicker.testapp", "SimpleApp")
+
+            // b/161435597 causes the test not to work on 90 degrees
+            return FlickerTestRunnerFactory(instrumentation, listOf(Surface.ROTATION_0))
+                    .buildTest { configuration ->
+                        withTestName {
+                            buildTestTag("exitSplitScreenFromBottom", testApp,
+                                    configuration)
+                        }
+                        repeat { configuration.repetitions }
+                        setup {
+                            test {
+                                device.wakeUpAndGoToHomeScreen()
+                            }
+                            eachRun {
+                                testApp.open()
+                                device.launchSplitScreen()
+                                device.waitForIdle()
+                                this.setRotation(configuration.endRotation)
+                            }
+                        }
+                        teardown {
+                            eachRun {
+                                testApp.exit()
+                            }
+                            test {
+                                if (device.isInSplitScreen()) {
+                                    device.exitSplitScreen()
+                                }
+                            }
+                        }
+                        transitions {
+                            device.exitSplitScreenFromBottom()
+                        }
+                    }
+        }
+    }
+}
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ExitLegacySplitScreenTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ExitLegacySplitScreenTest.kt
index 33306bf..c51c73a 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ExitLegacySplitScreenTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ExitLegacySplitScreenTest.kt
@@ -21,16 +21,22 @@
 import android.view.Surface
 import androidx.test.filters.FlakyTest
 import androidx.test.filters.RequiresDevice
+import com.android.server.wm.flicker.visibleLayersShownMoreThanOneConsecutiveEntry
+import com.android.server.wm.flicker.visibleWindowsShownMoreThanOneConsecutiveEntry
+import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible
+import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible
+import com.android.server.wm.flicker.layerBecomesInvisible
 import com.android.server.wm.flicker.dsl.FlickerBuilder
 import com.android.server.wm.flicker.dsl.runWithFlicker
 import com.android.server.wm.flicker.helpers.exitSplitScreen
 import com.android.server.wm.flicker.helpers.launchSplitScreen
+import com.android.server.wm.flicker.helpers.openQuickStepAndClearRecentAppsFromOverview
 import com.android.server.wm.flicker.helpers.resizeSplitScreen
 import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen
-import com.android.wm.shell.flicker.dockedStackDividerIsInvisible
-import com.android.wm.shell.flicker.helpers.SplitScreenHelper.Companion.TEST_REPETITIONS
 import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible
 import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible
+import com.android.wm.shell.flicker.dockedStackDividerIsInvisible
+import com.android.wm.shell.flicker.helpers.SplitScreenHelper.Companion.TEST_REPETITIONS
 import org.junit.FixMethodOrder
 import org.junit.Test
 import org.junit.runner.RunWith
@@ -39,7 +45,7 @@
 
 /**
  * Test exit SplitScreen mode.
- * To run this test: `atest WMShellFlickerTests:ExitSplitScreenTest`
+ * To run this test: `atest WMShellFlickerTests:ExitLegacySplitScreenTest`
  */
 @Presubmit
 @RequiresDevice
@@ -58,10 +64,9 @@
             setup {
                 eachRun {
                     uiDevice.wakeUpAndGoToHomeScreen()
-                    secondaryApp.open()
-                    uiDevice.pressHome()
-                    splitScreenApp.open()
-                    uiDevice.pressHome()
+                    uiDevice.openQuickStepAndClearRecentAppsFromOverview()
+                    secondaryApp.launchViaIntent()
+                    splitScreenApp.launchViaIntent()
                     uiDevice.launchSplitScreen()
                 }
             }
@@ -71,6 +76,15 @@
                     secondaryApp.exit()
                 }
             }
+            assertions {
+                windowManagerTrace {
+                    visibleWindowsShownMoreThanOneConsecutiveEntry()
+                }
+                layersTrace {
+                    visibleLayersShownMoreThanOneConsecutiveEntry(
+                            listOf(launcherPackageName))
+                }
+            }
         }
 
     @Test
@@ -87,6 +101,7 @@
             assertions {
                 layersTrace {
                     dockedStackDividerIsInvisible()
+                    layerBecomesInvisible(splitScreenApp.defaultWindowName)
                 }
                 windowManagerTrace {
                     navBarWindowIsAlwaysVisible()
@@ -137,4 +152,4 @@
             return supportedRotations.map { arrayOf(Surface.rotationToString(it), it) }
         }
     }
-}
\ No newline at end of file
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenToLauncherTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenToLauncherTest.kt
index cc02aa3..629c71f 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenToLauncherTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenToLauncherTest.kt
@@ -17,10 +17,10 @@
 package com.android.wm.shell.flicker.legacysplitscreen
 
 import android.platform.test.annotations.Presubmit
+import android.support.test.launcherhelper.LauncherStrategyFactory
 import android.view.Surface
 import androidx.test.filters.RequiresDevice
 import androidx.test.platform.app.InstrumentationRegistry
-import com.android.server.wm.flicker.DOCKED_STACK_DIVIDER
 import com.android.server.wm.flicker.Flicker
 import com.android.server.wm.flicker.FlickerTestRunner
 import com.android.server.wm.flicker.FlickerTestRunnerFactory
@@ -31,16 +31,21 @@
 import com.android.server.wm.flicker.helpers.exitSplitScreen
 import com.android.server.wm.flicker.helpers.isInSplitScreen
 import com.android.server.wm.flicker.helpers.launchSplitScreen
+import com.android.server.wm.flicker.helpers.openQuickStepAndClearRecentAppsFromOverview
 import com.android.server.wm.flicker.helpers.setRotation
 import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen
 import com.android.server.wm.flicker.navBarLayerIsAlwaysVisible
 import com.android.server.wm.flicker.navBarLayerRotatesAndScales
+import com.android.server.wm.flicker.visibleWindowsShownMoreThanOneConsecutiveEntry
+import com.android.server.wm.flicker.visibleLayersShownMoreThanOneConsecutiveEntry
+import com.android.server.wm.flicker.layerBecomesInvisible
 import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible
 import com.android.server.wm.flicker.noUncoveredRegions
 import com.android.server.wm.flicker.repetitions
 import com.android.server.wm.flicker.statusBarLayerIsAlwaysVisible
 import com.android.server.wm.flicker.statusBarLayerRotatesScales
 import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible
+import com.android.wm.shell.flicker.dockedStackDividerBecomesInvisible
 import org.junit.FixMethodOrder
 import org.junit.runner.RunWith
 import org.junit.runners.MethodSorters
@@ -48,7 +53,7 @@
 
 /**
  * Test open app to split screen.
- * To run this test: `atest WMShellFlickerTests:SplitScreenToLauncherTest`
+ * To run this test: `atest WMShellFlickerTests:LegacySplitScreenToLauncherTest`
  */
 @Presubmit
 @RequiresDevice
@@ -63,6 +68,8 @@
         @JvmStatic
         fun getParams(): Collection<Array<Any>> {
             val instrumentation = InstrumentationRegistry.getInstrumentation()
+            val launcherPackageName = LauncherStrategyFactory.getInstance(instrumentation)
+                    .launcherStrategy.supportedLauncherPackage
             val testApp = StandardAppHelper(instrumentation,
                 "com.android.wm.shell.flicker.testapp", "SimpleApp")
 
@@ -76,6 +83,7 @@
                     setup {
                         test {
                             device.wakeUpAndGoToHomeScreen()
+                            device.openQuickStepAndClearRecentAppsFromOverview()
                         }
                         eachRun {
                             testApp.open()
@@ -101,6 +109,7 @@
                         windowManagerTrace {
                             navBarWindowIsAlwaysVisible()
                             statusBarWindowIsAlwaysVisible()
+                            visibleWindowsShownMoreThanOneConsecutiveEntry()
                         }
 
                         layersTrace {
@@ -109,19 +118,13 @@
                             noUncoveredRegions(configuration.endRotation)
                             navBarLayerRotatesAndScales(configuration.endRotation)
                             statusBarLayerRotatesScales(configuration.endRotation)
+                            visibleLayersShownMoreThanOneConsecutiveEntry(
+                                    listOf(launcherPackageName))
 
                             // b/161435597 causes the test not to work on 90 degrees
-                            all("dividerLayerBecomesInvisible") {
-                                this.showsLayer(DOCKED_STACK_DIVIDER)
-                                    .then()
-                                    .hidesLayer(DOCKED_STACK_DIVIDER)
-                            }
+                            dockedStackDividerBecomesInvisible()
 
-                            all("appLayerBecomesInvisible") {
-                                this.showsLayer(testApp.getPackage())
-                                    .then()
-                                    .hidesLayer(testApp.getPackage())
-                            }
+                            layerBecomesInvisible(testApp.getPackage())
                         }
 
                         eventLog {
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/OpenAppToLegacySplitScreenTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/OpenAppToLegacySplitScreenTest.kt
index bb80726..af03869 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/OpenAppToLegacySplitScreenTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/OpenAppToLegacySplitScreenTest.kt
@@ -17,30 +17,36 @@
 package com.android.wm.shell.flicker.legacysplitscreen
 
 import android.platform.test.annotations.Presubmit
+import android.support.test.launcherhelper.LauncherStrategyFactory
 import android.view.Surface
 import androidx.test.filters.RequiresDevice
 import androidx.test.platform.app.InstrumentationRegistry
-import com.android.server.wm.flicker.DOCKED_STACK_DIVIDER
 import com.android.server.wm.flicker.Flicker
 import com.android.server.wm.flicker.FlickerTestRunner
 import com.android.server.wm.flicker.FlickerTestRunnerFactory
-import com.android.server.wm.flicker.endRotation
 import com.android.server.wm.flicker.helpers.StandardAppHelper
+import com.android.server.wm.flicker.endRotation
 import com.android.server.wm.flicker.focusChanges
 import com.android.server.wm.flicker.helpers.buildTestTag
 import com.android.server.wm.flicker.helpers.exitSplitScreen
 import com.android.server.wm.flicker.helpers.isInSplitScreen
 import com.android.server.wm.flicker.helpers.launchSplitScreen
+import com.android.server.wm.flicker.helpers.openQuickStepAndClearRecentAppsFromOverview
 import com.android.server.wm.flicker.helpers.setRotation
 import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen
 import com.android.server.wm.flicker.navBarLayerIsAlwaysVisible
 import com.android.server.wm.flicker.navBarLayerRotatesAndScales
+import com.android.server.wm.flicker.appWindowBecomesVisible
+import com.android.server.wm.flicker.visibleWindowsShownMoreThanOneConsecutiveEntry
+import com.android.server.wm.flicker.visibleLayersShownMoreThanOneConsecutiveEntry
+import com.android.server.wm.flicker.layerBecomesVisible
 import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible
 import com.android.server.wm.flicker.noUncoveredRegions
 import com.android.server.wm.flicker.repetitions
 import com.android.server.wm.flicker.statusBarLayerIsAlwaysVisible
 import com.android.server.wm.flicker.statusBarLayerRotatesScales
 import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible
+import com.android.wm.shell.flicker.dockedStackDividerBecomesVisible
 import org.junit.FixMethodOrder
 import org.junit.runner.RunWith
 import org.junit.runners.MethodSorters
@@ -48,7 +54,7 @@
 
 /**
  * Test open app to split screen.
- * To run this test: `atest WMShellFlickerTests:OpenAppToSplitScreenTest`
+ * To run this test: `atest WMShellFlickerTests:OpenAppToLegacySplitScreenTest`
  */
 @Presubmit
 @RequiresDevice
@@ -63,6 +69,8 @@
         @JvmStatic
         fun getParams(): Collection<Array<Any>> {
             val instrumentation = InstrumentationRegistry.getInstrumentation()
+            val launcherPackageName = LauncherStrategyFactory.getInstance(instrumentation)
+                    .launcherStrategy.supportedLauncherPackage
             val testApp = StandardAppHelper(instrumentation,
                 "com.android.wm.shell.flicker.testapp", "SimpleApp")
 
@@ -76,9 +84,11 @@
                     setup {
                         test {
                             device.wakeUpAndGoToHomeScreen()
+                            device.openQuickStepAndClearRecentAppsFromOverview()
                         }
                         eachRun {
                             testApp.open()
+                            device.pressHome()
                             this.setRotation(configuration.endRotation)
                         }
                     }
@@ -99,6 +109,9 @@
                         windowManagerTrace {
                             navBarWindowIsAlwaysVisible()
                             statusBarWindowIsAlwaysVisible()
+                            visibleWindowsShownMoreThanOneConsecutiveEntry()
+
+                            appWindowBecomesVisible(testApp.getPackage())
                         }
 
                         layersTrace {
@@ -108,12 +121,11 @@
                             navBarLayerRotatesAndScales(configuration.endRotation,
                                 bugId = 140855415)
                             statusBarLayerRotatesScales(configuration.endRotation)
+                            visibleLayersShownMoreThanOneConsecutiveEntry(
+                                    listOf(launcherPackageName))
 
-                            all("dividerLayerBecomesVisible") {
-                                this.hidesLayer(DOCKED_STACK_DIVIDER)
-                                    .then()
-                                    .showsLayer(DOCKED_STACK_DIVIDER)
-                            }
+                            dockedStackDividerBecomesVisible()
+                            layerBecomesVisible(testApp.getPackage())
                         }
 
                         eventLog {
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ResizeLegacySplitScreenTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ResizeLegacySplitScreenTest.kt
index e3beb41..391cb2a 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ResizeLegacySplitScreenTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ResizeLegacySplitScreenTest.kt
@@ -47,6 +47,8 @@
 import com.android.server.wm.flicker.startRotation
 import com.android.server.wm.flicker.statusBarLayerIsAlwaysVisible
 import com.android.server.wm.flicker.statusBarLayerRotatesScales
+import com.android.server.wm.flicker.visibleWindowsShownMoreThanOneConsecutiveEntry
+import com.android.server.wm.flicker.visibleLayersShownMoreThanOneConsecutiveEntry
 import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible
 import org.junit.FixMethodOrder
 import org.junit.runner.RunWith
@@ -55,7 +57,7 @@
 
 /**
  * Test split screen resizing window transitions.
- * To run this test: `atest WMShellFlickerTests:ResizeSplitScreenTest`
+ * To run this test: `atest WMShellFlickerTests:ResizeLegacySplitScreenTest`
  *
  * Currently it runs only in 0 degrees because of b/156100803
  */
@@ -131,6 +133,7 @@
                         windowManagerTrace {
                             navBarWindowIsAlwaysVisible()
                             statusBarWindowIsAlwaysVisible()
+                            visibleWindowsShownMoreThanOneConsecutiveEntry()
 
                             all("topAppWindowIsAlwaysVisible", bugId = 156223549) {
                                 this.showsAppWindow(sSimpleActivity)
@@ -147,6 +150,7 @@
                             noUncoveredRegions(configuration.endRotation)
                             navBarLayerRotatesAndScales(configuration.endRotation)
                             statusBarLayerRotatesScales(configuration.endRotation)
+                            visibleLayersShownMoreThanOneConsecutiveEntry()
 
                             all("topAppLayerIsAlwaysVisible") {
                                 this.showsLayer(sSimpleActivity)
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateOneLaunchedAppTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateOneLaunchedAppTest.kt
index ae2200c..923f2a4 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateOneLaunchedAppTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateOneLaunchedAppTest.kt
@@ -23,6 +23,7 @@
 import com.android.server.wm.flicker.helpers.exitSplitScreen
 import com.android.server.wm.flicker.helpers.isInSplitScreen
 import com.android.server.wm.flicker.helpers.launchSplitScreen
+import com.android.server.wm.flicker.helpers.openQuickStepAndClearRecentAppsFromOverview
 import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen
 import com.android.server.wm.flicker.navBarLayerRotatesAndScales
 import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible
@@ -56,7 +57,8 @@
             }
             setup {
                 test {
-                    device.wakeUpAndGoToHomeScreen()
+                    uiDevice.wakeUpAndGoToHomeScreen()
+                    uiDevice.openQuickStepAndClearRecentAppsFromOverview()
                 }
             }
             teardown {
@@ -81,7 +83,7 @@
             }
             transitions {
                 splitScreenApp.launchViaIntent()
-                device.launchSplitScreen()
+                uiDevice.launchSplitScreen()
                 setRotation(rotation)
             }
             assertions {
@@ -114,7 +116,7 @@
             transitions {
                 splitScreenApp.launchViaIntent()
                 setRotation(rotation)
-                device.launchSplitScreen()
+                uiDevice.launchSplitScreen()
             }
             assertions {
                 layersTrace {
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateTwoLaunchedAppTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateTwoLaunchedAppTest.kt
index a1b44f0..4578f68 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateTwoLaunchedAppTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/RotateTwoLaunchedAppTest.kt
@@ -23,6 +23,7 @@
 import com.android.server.wm.flicker.helpers.exitSplitScreen
 import com.android.server.wm.flicker.helpers.isInSplitScreen
 import com.android.server.wm.flicker.helpers.launchSplitScreen
+import com.android.server.wm.flicker.helpers.openQuickStepAndClearRecentAppsFromOverview
 import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen
 import com.android.server.wm.flicker.navBarLayerRotatesAndScales
 import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible
@@ -57,7 +58,8 @@
             }
             setup {
                 test {
-                    device.wakeUpAndGoToHomeScreen()
+                    uiDevice.wakeUpAndGoToHomeScreen()
+                    uiDevice.openQuickStepAndClearRecentAppsFromOverview()
                 }
             }
             teardown {
@@ -83,7 +85,7 @@
             transitions {
                 secondaryApp.launchViaIntent()
                 splitScreenApp.launchViaIntent()
-                device.launchSplitScreen()
+                uiDevice.launchSplitScreen()
                 splitScreenApp.reopenAppFromOverview()
                 setRotation(rotation)
             }
@@ -121,7 +123,7 @@
                 secondaryApp.launchViaIntent()
                 splitScreenApp.launchViaIntent()
                 setRotation(rotation)
-                device.launchSplitScreen()
+                uiDevice.launchSplitScreen()
                 splitScreenApp.reopenAppFromOverview()
             }
             assertions {
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/SplitScreenTestBase.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/SplitScreenTestBase.kt
index a2e325e..a536ec8 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/SplitScreenTestBase.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/SplitScreenTestBase.kt
@@ -16,6 +16,7 @@
 
 package com.android.wm.shell.flicker.legacysplitscreen
 
+import android.support.test.launcherhelper.LauncherStrategyFactory
 import com.android.wm.shell.flicker.NonRotationTestBase
 import com.android.wm.shell.flicker.TEST_APP_NONRESIZEABLE_LABEL
 import com.android.wm.shell.flicker.TEST_APP_SPLITSCREEN_PRIMARY_LABEL
@@ -36,4 +37,6 @@
     protected val nonResizeableApp = SplitScreenHelper(instrumentation,
             TEST_APP_NONRESIZEABLE_LABEL,
             Components.NonResizeableActivity())
+    protected val launcherPackageName = LauncherStrategyFactory.getInstance(instrumentation)
+            .launcherStrategy.supportedLauncherPackage
 }
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipKeyboardTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipKeyboardTest.kt
index 6b44ce6..866d654 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipKeyboardTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipKeyboardTest.kt
@@ -25,8 +25,10 @@
 import com.android.server.wm.flicker.helpers.closePipWindow
 import com.android.server.wm.flicker.helpers.hasPipWindow
 import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen
+import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper
 import com.android.wm.shell.flicker.IME_WINDOW_NAME
 import com.android.wm.shell.flicker.helpers.ImeAppHelper
+import com.android.wm.shell.flicker.testapp.Components
 import org.junit.FixMethodOrder
 import org.junit.Test
 import org.junit.runner.RunWith
@@ -46,6 +48,8 @@
     rotation: Int
 ) : PipTestBase(rotationName, rotation) {
     private val keyboardApp = ImeAppHelper(instrumentation)
+    private val keyboardComponent = Components.ImeActivity().componentName
+    private val helper = WindowManagerStateHelper()
 
     private val keyboardScenario: FlickerBuilder
         get() = FlickerBuilder(instrumentation).apply {
@@ -64,6 +68,8 @@
                     // UiAutomator doesn't support to launch the multiple Activities in a task.
                     // So use launchActivity() for the Keyboard Activity.
                     keyboardApp.launchViaIntent()
+                    helper.waitForAppTransitionIdle()
+                    helper.waitForFullScreenApp(keyboardComponent)
                 }
             }
             teardown {
@@ -88,9 +94,11 @@
             transitions {
                 // open the soft keyboard
                 keyboardApp.openIME()
+                helper.waitImeWindowShown()
 
                 // then close it again
                 keyboardApp.closeIME()
+                helper.waitImeWindowGone()
             }
             assertions {
                 windowManagerTrace {
@@ -112,11 +120,13 @@
             transitions {
                 // open the soft keyboard
                 keyboardApp.openIME()
+                helper.waitImeWindowShown()
             }
             teardown {
                 eachRun {
                     // close the keyboard
                     keyboardApp.closeIME()
+                    helper.waitImeWindowGone()
                 }
             }
             assertions {
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipLegacySplitScreenTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipLegacySplitScreenTest.kt
index 81cdbf0..9eae179 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipLegacySplitScreenTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipLegacySplitScreenTest.kt
@@ -41,7 +41,7 @@
 
 /**
  * Test Pip with split-screen.
- * To run this test: `atest WMShellFlickerTests:PipSplitScreenTest`
+ * To run this test: `atest WMShellFlickerTests:PipLegacySplitScreenTest`
  */
 @RequiresDevice
 @RunWith(Parameterized::class)
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipAnimationControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipAnimationControllerTest.java
index 7f280cd..d30fa38 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipAnimationControllerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipAnimationControllerTest.java
@@ -197,6 +197,11 @@
         }
 
         @Override
+        public SurfaceControl.Transaction setFrameTimelineVsync(long frameTimelineVsyncId) {
+            return this;
+        }
+
+        @Override
         public void apply() {}
     }
 }
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipBoundsStateTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipBoundsStateTest.java
index 8ba301a..dea24d3 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipBoundsStateTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipBoundsStateTest.java
@@ -31,14 +31,13 @@
 
 import androidx.test.filters.SmallTest;
 
+import com.android.internal.util.function.TriConsumer;
 import com.android.wm.shell.ShellTestCase;
 
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
-import java.util.function.BiConsumer;
-
 /**
  * Tests for {@link PipBoundsState}.
  */
@@ -117,23 +116,33 @@
 
     @Test
     public void testSetShelfVisibility_changed_callbackInvoked() {
-        final BiConsumer<Boolean, Integer> callback = mock(BiConsumer.class);
+        final TriConsumer<Boolean, Integer, Boolean> callback = mock(TriConsumer.class);
         mPipBoundsState.setOnShelfVisibilityChangeCallback(callback);
 
         mPipBoundsState.setShelfVisibility(true, 100);
 
-        verify(callback).accept(true, 100);
+        verify(callback).accept(true, 100, true);
+    }
+
+    @Test
+    public void testSetShelfVisibility_changedWithoutUpdateMovBounds_callbackInvoked() {
+        final TriConsumer<Boolean, Integer, Boolean> callback = mock(TriConsumer.class);
+        mPipBoundsState.setOnShelfVisibilityChangeCallback(callback);
+
+        mPipBoundsState.setShelfVisibility(true, 100, false);
+
+        verify(callback).accept(true, 100, false);
     }
 
     @Test
     public void testSetShelfVisibility_notChanged_callbackNotInvoked() {
-        final BiConsumer<Boolean, Integer> callback = mock(BiConsumer.class);
+        final TriConsumer<Boolean, Integer, Boolean> callback = mock(TriConsumer.class);
         mPipBoundsState.setShelfVisibility(true, 100);
         mPipBoundsState.setOnShelfVisibilityChangeCallback(callback);
 
         mPipBoundsState.setShelfVisibility(true, 100);
 
-        verify(callback, never()).accept(true, 100);
+        verify(callback, never()).accept(true, 100, true);
     }
 
     @Test
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawerTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawerTests.java
index f5628ab..07115c2 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawerTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawerTests.java
@@ -41,11 +41,14 @@
 import android.view.View;
 import android.view.WindowManager;
 import android.view.WindowMetrics;
+import android.window.StartingWindowInfo;
 
 import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.SmallTest;
 import androidx.test.platform.app.InstrumentationRegistry;
 
+import com.android.wm.shell.common.HandlerExecutor;
+import com.android.wm.shell.common.ShellExecutor;
 import com.android.wm.shell.startingsurface.StartingSurfaceDrawer;
 
 import org.junit.Before;
@@ -70,8 +73,8 @@
     static final class TestStartingSurfaceDrawer extends StartingSurfaceDrawer{
         int mAddWindowForTask = 0;
 
-        TestStartingSurfaceDrawer(Context context) {
-            super(context);
+        TestStartingSurfaceDrawer(Context context, ShellExecutor executor) {
+            super(context, executor);
         }
 
         @Override
@@ -109,36 +112,38 @@
         doReturn(metrics).when(mMockWindowManager).getMaximumWindowMetrics();
         doNothing().when(mMockWindowManager).addView(any(), any());
 
-        mStartingSurfaceDrawer = spy(new TestStartingSurfaceDrawer(context));
+        mStartingSurfaceDrawer = spy(new TestStartingSurfaceDrawer(context,
+                new HandlerExecutor(new Handler(Looper.getMainLooper()))));
     }
 
     @Test
     public void testAddSplashScreenSurface() {
         final int taskId = 1;
         final Handler mainLoop = new Handler(Looper.getMainLooper());
-        final ActivityManager.RunningTaskInfo taskInfo =
-                createTaskInfo(taskId, WINDOWING_MODE_FULLSCREEN);
-        mStartingSurfaceDrawer.addStartingWindow(taskInfo, mBinder);
+        final StartingWindowInfo windowInfo =
+                createWindowInfo(taskId, WINDOWING_MODE_FULLSCREEN);
+        mStartingSurfaceDrawer.addStartingWindow(windowInfo, mBinder);
         waitHandlerIdle(mainLoop);
         verify(mStartingSurfaceDrawer).postAddWindow(eq(taskId), eq(mBinder), any(), any(), any());
         assertEquals(mStartingSurfaceDrawer.mAddWindowForTask, taskId);
 
-        mStartingSurfaceDrawer.removeStartingWindow(taskInfo);
+        mStartingSurfaceDrawer.removeStartingWindow(windowInfo.taskInfo.taskId);
         waitHandlerIdle(mainLoop);
         verify(mStartingSurfaceDrawer).removeWindowSynced(eq(taskId));
         assertEquals(mStartingSurfaceDrawer.mAddWindowForTask, 0);
     }
 
-    private ActivityManager.RunningTaskInfo createTaskInfo(int taskId, int windowingMode) {
-        ActivityManager.RunningTaskInfo taskInfo = new ActivityManager.RunningTaskInfo();
+    private StartingWindowInfo createWindowInfo(int taskId, int windowingMode) {
+        StartingWindowInfo windowInfo = new StartingWindowInfo();
         final ActivityInfo info = new ActivityInfo();
         info.applicationInfo = new ApplicationInfo();
         info.packageName = "test";
         info.theme = android.R.style.Theme;
+        final ActivityManager.RunningTaskInfo taskInfo = new ActivityManager.RunningTaskInfo();
         taskInfo.topActivityInfo = info;
         taskInfo.taskId = taskId;
-        taskInfo.configuration.windowConfiguration.setWindowingMode(windowingMode);
-        return taskInfo;
+        windowInfo.taskInfo = taskInfo;
+        return windowInfo;
     }
 
     private static void waitHandlerIdle(Handler handler) {
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/startingsurface/TaskSnapshotWindowTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/startingsurface/TaskSnapshotWindowTest.java
new file mode 100644
index 0000000..94af329
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/startingsurface/TaskSnapshotWindowTest.java
@@ -0,0 +1,293 @@
+/*
+ * Copyright (C) 2017 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 unittest.src.com.android.wm.shell.startingsurface;
+
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
+import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
+import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
+import static android.view.WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
+
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.never;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.when;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyInt;
+import static org.mockito.Matchers.eq;
+
+import android.app.ActivityManager.TaskDescription;
+import android.content.ComponentName;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.ColorSpace;
+import android.graphics.Point;
+import android.graphics.Rect;
+import android.hardware.HardwareBuffer;
+import android.view.InsetsState;
+import android.view.Surface;
+import android.view.SurfaceControl;
+import android.window.TaskSnapshot;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.SmallTest;
+
+import com.android.wm.shell.startingsurface.TaskSnapshotWindow;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Test class for {@link TaskSnapshotWindow}.
+ *
+ */
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class TaskSnapshotWindowTest {
+
+    private TaskSnapshotWindow mWindow;
+
+    private void setupSurface(int width, int height) {
+        setupSurface(width, height, new Rect(), 0, FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS,
+                new Rect(0, 0, width, height));
+    }
+
+    private void setupSurface(int width, int height, Rect contentInsets, int sysuiVis,
+            int windowFlags, Rect taskBounds) {
+        // Previously when constructing TaskSnapshots for this test, scale was 1.0f, so to mimic
+        // this behavior set the taskSize to be the same as the taskBounds width and height. The
+        // taskBounds passed here are assumed to be the same task bounds as when the snapshot was
+        // taken. We assume there is no aspect ratio mismatch between the screenshot and the
+        // taskBounds
+        assertEquals(width, taskBounds.width());
+        assertEquals(height, taskBounds.height());
+        Point taskSize = new Point(taskBounds.width(), taskBounds.height());
+
+        final TaskSnapshot snapshot = createTaskSnapshot(width, height, taskSize, contentInsets);
+        mWindow = new TaskSnapshotWindow(new SurfaceControl(), snapshot, "Test",
+                createTaskDescription(Color.WHITE, Color.RED, Color.BLUE),
+                0 /* appearance */, windowFlags /* windowFlags */, 0 /* privateWindowFlags */,
+                taskBounds, ORIENTATION_PORTRAIT, ACTIVITY_TYPE_STANDARD, new InsetsState(),
+                null /* clearWindow */);
+    }
+
+    private TaskSnapshot createTaskSnapshot(int width, int height, Point taskSize,
+            Rect contentInsets) {
+        final HardwareBuffer buffer = HardwareBuffer.create(width, height, HardwareBuffer.RGBA_8888,
+                1, HardwareBuffer.USAGE_CPU_READ_RARELY);
+        return new TaskSnapshot(
+                System.currentTimeMillis(),
+                new ComponentName("", ""), buffer,
+                ColorSpace.get(ColorSpace.Named.SRGB), ORIENTATION_PORTRAIT,
+                Surface.ROTATION_0, taskSize, contentInsets, false,
+                true /* isRealSnapshot */, WINDOWING_MODE_FULLSCREEN,
+                0 /* systemUiVisibility */, false /* isTranslucent */);
+    }
+
+    private static TaskDescription createTaskDescription(int background, int statusBar,
+            int navigationBar) {
+        final TaskDescription td = new TaskDescription();
+        td.setBackgroundColor(background);
+        td.setStatusBarColor(statusBar);
+        td.setNavigationBarColor(navigationBar);
+        return td;
+    }
+
+    @Test
+    public void fillEmptyBackground_fillHorizontally() {
+        setupSurface(200, 100);
+        final Canvas mockCanvas = mock(Canvas.class);
+        when(mockCanvas.getWidth()).thenReturn(200);
+        when(mockCanvas.getHeight()).thenReturn(100);
+        mWindow.drawBackgroundAndBars(mockCanvas, new Rect(0, 0, 100, 200));
+        verify(mockCanvas).drawRect(eq(100.0f), eq(0.0f), eq(200.0f), eq(100.0f), any());
+    }
+
+    @Test
+    public void fillEmptyBackground_fillVertically() {
+        setupSurface(100, 200);
+        final Canvas mockCanvas = mock(Canvas.class);
+        when(mockCanvas.getWidth()).thenReturn(100);
+        when(mockCanvas.getHeight()).thenReturn(200);
+        mWindow.drawBackgroundAndBars(mockCanvas, new Rect(0, 0, 200, 100));
+        verify(mockCanvas).drawRect(eq(0.0f), eq(100.0f), eq(100.0f), eq(200.0f), any());
+    }
+
+    @Test
+    public void fillEmptyBackground_fillBoth() {
+        setupSurface(200, 200);
+        final Canvas mockCanvas = mock(Canvas.class);
+        when(mockCanvas.getWidth()).thenReturn(200);
+        when(mockCanvas.getHeight()).thenReturn(200);
+        mWindow.drawBackgroundAndBars(mockCanvas, new Rect(0, 0, 100, 100));
+        verify(mockCanvas).drawRect(eq(100.0f), eq(0.0f), eq(200.0f), eq(100.0f), any());
+        verify(mockCanvas).drawRect(eq(0.0f), eq(100.0f), eq(200.0f), eq(200.0f), any());
+    }
+
+    @Test
+    public void fillEmptyBackground_dontFill_sameSize() {
+        setupSurface(100, 100);
+        final Canvas mockCanvas = mock(Canvas.class);
+        when(mockCanvas.getWidth()).thenReturn(100);
+        when(mockCanvas.getHeight()).thenReturn(100);
+        mWindow.drawBackgroundAndBars(mockCanvas, new Rect(0, 0, 100, 100));
+        verify(mockCanvas, never()).drawRect(anyInt(), anyInt(), anyInt(), anyInt(), any());
+    }
+
+    @Test
+    public void fillEmptyBackground_dontFill_bitmapLarger() {
+        setupSurface(100, 100);
+        final Canvas mockCanvas = mock(Canvas.class);
+        when(mockCanvas.getWidth()).thenReturn(100);
+        when(mockCanvas.getHeight()).thenReturn(100);
+        mWindow.drawBackgroundAndBars(mockCanvas, new Rect(0, 0, 200, 200));
+        verify(mockCanvas, never()).drawRect(anyInt(), anyInt(), anyInt(), anyInt(), any());
+    }
+
+    @Test
+    public void testCalculateSnapshotCrop() {
+        setupSurface(100, 100, new Rect(0, 10, 0, 10), 0, 0, new Rect(0, 0, 100, 100));
+        assertEquals(new Rect(0, 0, 100, 90), mWindow.calculateSnapshotCrop());
+    }
+
+    @Test
+    public void testCalculateSnapshotCrop_taskNotOnTop() {
+        setupSurface(100, 100, new Rect(0, 10, 0, 10), 0, 0, new Rect(0, 50, 100, 150));
+        assertEquals(new Rect(0, 10, 100, 90), mWindow.calculateSnapshotCrop());
+    }
+
+    @Test
+    public void testCalculateSnapshotCrop_navBarLeft() {
+        setupSurface(100, 100, new Rect(10, 10, 0, 0), 0, 0, new Rect(0, 0, 100, 100));
+        assertEquals(new Rect(10, 0, 100, 100), mWindow.calculateSnapshotCrop());
+    }
+
+    @Test
+    public void testCalculateSnapshotCrop_navBarRight() {
+        setupSurface(100, 100, new Rect(0, 10, 10, 0), 0, 0, new Rect(0, 0, 100, 100));
+        assertEquals(new Rect(0, 0, 90, 100), mWindow.calculateSnapshotCrop());
+    }
+
+    @Test
+    public void testCalculateSnapshotCrop_waterfall() {
+        setupSurface(100, 100, new Rect(5, 10, 5, 10), 0, 0, new Rect(0, 0, 100, 100));
+        assertEquals(new Rect(5, 0, 95, 90), mWindow.calculateSnapshotCrop());
+    }
+
+    @Test
+    public void testCalculateSnapshotFrame() {
+        setupSurface(100, 100);
+        final Rect insets = new Rect(0, 10, 0, 10);
+        mWindow.setFrames(new Rect(0, 0, 100, 100), insets);
+        assertEquals(new Rect(0, 0, 100, 80),
+                mWindow.calculateSnapshotFrame(new Rect(0, 10, 100, 90)));
+    }
+
+    @Test
+    public void testCalculateSnapshotFrame_navBarLeft() {
+        setupSurface(100, 100);
+        final Rect insets = new Rect(10, 10, 0, 0);
+        mWindow.setFrames(new Rect(0, 0, 100, 100), insets);
+        assertEquals(new Rect(10, 0, 100, 90),
+                mWindow.calculateSnapshotFrame(new Rect(10, 10, 100, 100)));
+    }
+
+    @Test
+    public void testCalculateSnapshotFrame_waterfall() {
+        setupSurface(100, 100, new Rect(5, 10, 5, 10), 0, 0, new Rect(0, 0, 100, 100));
+        final Rect insets = new Rect(0, 10, 0, 10);
+        mWindow.setFrames(new Rect(5, 0, 95, 100), insets);
+        assertEquals(new Rect(0, 0, 90, 90),
+                mWindow.calculateSnapshotFrame(new Rect(5, 0, 95, 90)));
+    }
+
+    @Test
+    public void testDrawStatusBarBackground() {
+        setupSurface(100, 100);
+        final Rect insets = new Rect(0, 10, 10, 0);
+        mWindow.setFrames(new Rect(0, 0, 100, 100), insets);
+        final Canvas mockCanvas = mock(Canvas.class);
+        when(mockCanvas.getWidth()).thenReturn(100);
+        when(mockCanvas.getHeight()).thenReturn(100);
+        mWindow.drawStatusBarBackground(mockCanvas, new Rect(0, 0, 50, 100));
+        verify(mockCanvas).drawRect(eq(50.0f), eq(0.0f), eq(90.0f), eq(10.0f), any());
+    }
+
+    @Test
+    public void testDrawStatusBarBackground_nullFrame() {
+        setupSurface(100, 100);
+        final Rect insets = new Rect(0, 10, 10, 0);
+        mWindow.setFrames(new Rect(0, 0, 100, 100), insets);
+        final Canvas mockCanvas = mock(Canvas.class);
+        when(mockCanvas.getWidth()).thenReturn(100);
+        when(mockCanvas.getHeight()).thenReturn(100);
+        mWindow.drawStatusBarBackground(mockCanvas, null);
+        verify(mockCanvas).drawRect(eq(0.0f), eq(0.0f), eq(90.0f), eq(10.0f), any());
+    }
+
+    @Test
+    public void testDrawStatusBarBackground_nope() {
+        setupSurface(100, 100);
+        final Rect insets = new Rect(0, 10, 10, 0);
+        mWindow.setFrames(new Rect(0, 0, 100, 100), insets);
+        final Canvas mockCanvas = mock(Canvas.class);
+        when(mockCanvas.getWidth()).thenReturn(100);
+        when(mockCanvas.getHeight()).thenReturn(100);
+        mWindow.drawStatusBarBackground(mockCanvas, new Rect(0, 0, 100, 100));
+        verify(mockCanvas, never()).drawRect(anyInt(), anyInt(), anyInt(), anyInt(), any());
+    }
+
+    @Test
+    public void testDrawNavigationBarBackground() {
+        final Rect insets = new Rect(0, 10, 0, 10);
+        setupSurface(100, 100, insets, 0, FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS,
+                new Rect(0, 0, 100, 100));
+        mWindow.setFrames(new Rect(0, 0, 100, 100), insets);
+        final Canvas mockCanvas = mock(Canvas.class);
+        when(mockCanvas.getWidth()).thenReturn(100);
+        when(mockCanvas.getHeight()).thenReturn(100);
+        mWindow.drawNavigationBarBackground(mockCanvas);
+        verify(mockCanvas).drawRect(eq(new Rect(0, 90, 100, 100)), any());
+    }
+
+    @Test
+    public void testDrawNavigationBarBackground_left() {
+        final Rect insets = new Rect(10, 10, 0, 0);
+        setupSurface(100, 100, insets, 0, FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS,
+                new Rect(0, 0, 100, 100));
+        mWindow.setFrames(new Rect(0, 0, 100, 100), insets);
+        final Canvas mockCanvas = mock(Canvas.class);
+        when(mockCanvas.getWidth()).thenReturn(100);
+        when(mockCanvas.getHeight()).thenReturn(100);
+        mWindow.drawNavigationBarBackground(mockCanvas);
+        verify(mockCanvas).drawRect(eq(new Rect(0, 0, 10, 100)), any());
+    }
+
+    @Test
+    public void testDrawNavigationBarBackground_right() {
+        final Rect insets = new Rect(0, 10, 10, 0);
+        setupSurface(100, 100, insets, 0, FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS,
+                new Rect(0, 0, 100, 100));
+        mWindow.setFrames(new Rect(0, 0, 100, 100), insets);
+        final Canvas mockCanvas = mock(Canvas.class);
+        when(mockCanvas.getWidth()).thenReturn(100);
+        when(mockCanvas.getHeight()).thenReturn(100);
+        mWindow.drawNavigationBarBackground(mockCanvas);
+        verify(mockCanvas).drawRect(eq(new Rect(90, 0, 100, 100)), any());
+    }
+}
diff --git a/libs/androidfw/AssetManager2.cpp b/libs/androidfw/AssetManager2.cpp
index a545b3d..bec80a7 100644
--- a/libs/androidfw/AssetManager2.cpp
+++ b/libs/androidfw/AssetManager2.cpp
@@ -670,7 +670,7 @@
     }
 
     auto entry_flags = type_spec->GetFlagsForEntryIndex(entry_idx);
-    if (UNLIKELY(!entry_flags)) {
+    if (UNLIKELY(!entry_flags.has_value())) {
       return base::unexpected(entry_flags.error());
     }
     type_flags |= entry_flags.value();
diff --git a/libs/androidfw/ResourceTypes.cpp b/libs/androidfw/ResourceTypes.cpp
index 4010e4e..bce70e2 100644
--- a/libs/androidfw/ResourceTypes.cpp
+++ b/libs/androidfw/ResourceTypes.cpp
@@ -897,12 +897,12 @@
             // Decode the UTF-16 length. This is not used if we're not
             // converting to UTF-16 from UTF-8.
             const base::expected<size_t, IOError> u16len = decodeLength(&str);
-            if (UNLIKELY(!u16len)) {
+            if (UNLIKELY(!u16len.has_value())) {
                 return base::unexpected(u16len.error());
             }
 
             const base::expected<size_t, IOError> u8len = decodeLength(&str);
-            if (UNLIKELY(!u8len)) {
+            if (UNLIKELY(!u8len.has_value())) {
                 return base::unexpected(u8len.error());
             }
 
diff --git a/libs/androidfw/ResourceUtils.cpp b/libs/androidfw/ResourceUtils.cpp
index a34aa72..87fb2c0 100644
--- a/libs/androidfw/ResourceUtils.cpp
+++ b/libs/androidfw/ResourceUtils.cpp
@@ -56,7 +56,8 @@
     .package_len = package_name.size(),
   };
 
-  if (base::expected<StringPiece, NullOrIOError> type_str = type_string_ref.string8()) {
+  if (base::expected<StringPiece, NullOrIOError> type_str = type_string_ref.string8();
+      type_str.ok()) {
     name.type = type_str->data();
     name.type_len = type_str->size();
   } else if (UNLIKELY(IsIOError(type_str))) {
@@ -64,7 +65,8 @@
   }
 
   if (name.type == nullptr) {
-    if (base::expected<StringPiece16, NullOrIOError> type16_str = type_string_ref.string16()) {
+    if (base::expected<StringPiece16, NullOrIOError> type16_str = type_string_ref.string16();
+        type16_str.ok()) {
       name.type16 = type16_str->data();
       name.type_len = type16_str->size();
     } else if (!type16_str.has_value()) {
@@ -72,7 +74,8 @@
     }
   }
 
-  if (base::expected<StringPiece, NullOrIOError> entry_str = entry_string_ref.string8()) {
+  if (base::expected<StringPiece, NullOrIOError> entry_str = entry_string_ref.string8();
+      entry_str.ok()) {
     name.entry = entry_str->data();
     name.entry_len = entry_str->size();
   } else if (UNLIKELY(IsIOError(entry_str))) {
@@ -80,7 +83,8 @@
   }
 
   if (name.entry == nullptr) {
-    if (base::expected<StringPiece16, NullOrIOError> entry16_str = entry_string_ref.string16()) {
+    if (base::expected<StringPiece16, NullOrIOError> entry16_str = entry_string_ref.string16();
+        entry16_str.ok()) {
       name.entry16 = entry16_str->data();
       name.entry_len = entry16_str->size();
     } else if (!entry16_str.has_value()) {
diff --git a/libs/hwui/pipeline/skia/GLFunctorDrawable.cpp b/libs/hwui/pipeline/skia/GLFunctorDrawable.cpp
index bfbdc5c..c6c9e9d 100644
--- a/libs/hwui/pipeline/skia/GLFunctorDrawable.cpp
+++ b/libs/hwui/pipeline/skia/GLFunctorDrawable.cpp
@@ -19,8 +19,6 @@
 #include <private/hwui/DrawGlInfo.h>
 #include "FunctorDrawable.h"
 #include "GrBackendSurface.h"
-#include "GrRenderTarget.h"
-#include "GrRenderTargetContext.h"
 #include "RenderNode.h"
 #include "SkAndroidFrameworkUtils.h"
 #include "SkClipStack.h"
@@ -40,19 +38,13 @@
 }
 
 static void GetFboDetails(SkCanvas* canvas, GLuint* outFboID, SkISize* outFboSize) {
-    GrRenderTargetContext* renderTargetContext =
-            canvas->internal_private_accessTopLayerRenderTargetContext();
-    LOG_ALWAYS_FATAL_IF(!renderTargetContext, "Failed to retrieve GrRenderTargetContext");
-
-    GrRenderTarget* renderTarget = renderTargetContext->accessRenderTarget();
-    LOG_ALWAYS_FATAL_IF(!renderTarget, "accessRenderTarget failed");
-
+    GrBackendRenderTarget renderTarget = canvas->topLayerBackendRenderTarget();
     GrGLFramebufferInfo fboInfo;
-    LOG_ALWAYS_FATAL_IF(!renderTarget->getBackendRenderTarget().getGLFramebufferInfo(&fboInfo),
+    LOG_ALWAYS_FATAL_IF(!renderTarget.getGLFramebufferInfo(&fboInfo),
         "getGLFrameBufferInfo failed");
 
     *outFboID = fboInfo.fFBOID;
-    *outFboSize = SkISize::Make(renderTargetContext->width(), renderTargetContext->height());
+    *outFboSize = renderTarget.dimensions();
 }
 
 void GLFunctorDrawable::onDraw(SkCanvas* canvas) {
@@ -75,7 +67,7 @@
     SkISize fboSize;
     GetFboDetails(canvas, &fboID, &fboSize);
 
-    SkIRect surfaceBounds = canvas->internal_private_getTopLayerBounds();
+    SkIRect surfaceBounds = canvas->topLayerBounds();
     SkIRect clipBounds = canvas->getDeviceClipBounds();
     SkM44 mat4(canvas->getLocalToDevice());
     SkRegion clipRegion;
diff --git a/location/java/android/location/GnssMeasurementRequest.aidl b/location/java/android/location/GnssMeasurementRequest.aidl
new file mode 100644
index 0000000..7e50728
--- /dev/null
+++ b/location/java/android/location/GnssMeasurementRequest.aidl
@@ -0,0 +1,19 @@
+/*
+ * 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 android.location;
+
+parcelable GnssMeasurementRequest;
diff --git a/location/java/android/location/GnssMeasurementRequest.java b/location/java/android/location/GnssMeasurementRequest.java
new file mode 100644
index 0000000..613f591
--- /dev/null
+++ b/location/java/android/location/GnssMeasurementRequest.java
@@ -0,0 +1,152 @@
+/*
+ * 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 android.location;
+
+import android.annotation.NonNull;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * This class contains extra parameters to pass in a GNSS measurement request.
+ */
+public final class GnssMeasurementRequest implements Parcelable {
+    private final boolean mFullTracking;
+
+    /**
+     * Creates a {@link GnssMeasurementRequest} with a full list of parameters.
+     */
+    private GnssMeasurementRequest(boolean fullTracking) {
+        mFullTracking = fullTracking;
+    }
+
+    /**
+     * Represents whether to enable full GNSS tracking.
+     *
+     * <p>If true, GNSS chipset switches off duty cycling. In such a mode, no clock
+     * discontinuities are expected, and when supported, carrier phase should be continuous in
+     * good signal conditions. All non-blocklisted, healthy constellations, satellites and
+     * frequency bands that the chipset supports must be reported in this mode. The GNSS chipset
+     * will consume more power in full tracking mode than in duty cycling mode. If false, GNSS
+     * chipset optimizes power via duty cycling, constellations and frequency limits, etc.
+     *
+     * <p>Full GNSS tracking mode affects GnssMeasurement and other GNSS functionalities
+     * including GNSS location.
+     */
+    public boolean isFullTracking() {
+        return mFullTracking;
+    }
+
+    @NonNull
+    public static final Creator<GnssMeasurementRequest> CREATOR =
+            new Creator<GnssMeasurementRequest>() {
+                @Override
+                @NonNull
+                public GnssMeasurementRequest createFromParcel(@NonNull Parcel parcel) {
+                    return new GnssMeasurementRequest(parcel.readBoolean());
+                }
+
+                @Override
+                public GnssMeasurementRequest[] newArray(int i) {
+                    return new GnssMeasurementRequest[i];
+                }
+            };
+
+    @Override
+    public void writeToParcel(@NonNull Parcel parcel, int flags) {
+        parcel.writeBoolean(mFullTracking);
+    }
+
+    @NonNull
+    @Override
+    public String toString() {
+        StringBuilder s = new StringBuilder();
+        s.append("GnssMeasurementRequest[");
+        if (mFullTracking) {
+            s.append("FullTracking");
+        }
+        s.append(']');
+        return s.toString();
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) return true;
+        if (obj == null) return false;
+        if (!(obj instanceof GnssMeasurementRequest)) return false;
+
+        GnssMeasurementRequest other = (GnssMeasurementRequest) obj;
+        if (mFullTracking != other.mFullTracking) return false;
+
+        return true;
+    }
+
+    @Override
+    public int hashCode() {
+        return mFullTracking ? 1 : 0;
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    /** Builder for {@link GnssMeasurementRequest} */
+    public static final class Builder {
+        private boolean mFullTracking;
+
+        /**
+         * Constructs a {@link Builder} instance.
+         */
+        public Builder() {
+        }
+
+        /**
+         * Constructs a {@link Builder} instance by copying a {@link GnssMeasurementRequest}.
+         */
+        public Builder(@NonNull GnssMeasurementRequest request) {
+            mFullTracking = request.isFullTracking();
+        }
+
+        /**
+         * Set the value of whether to enable full GNSS tracking, which is false by default.
+         *
+         * <p>If true, GNSS chipset switches off duty cycling. In such a mode, no clock
+         * discontinuities are expected, and when supported, carrier phase should be continuous in
+         * good signal conditions. All non-blocklisted, healthy constellations, satellites and
+         * frequency bands that the chipset supports must be reported in this mode. The GNSS chipset
+         * will consume more power in full tracking mode than in duty cycling mode. If false,
+         * GNSS chipset optimizes power via duty cycling, constellations and frequency limits, etc.
+         *
+         * <p>Full GNSS tracking mode affects GnssMeasurement and other GNSS functionalities
+         * including GNSS location.
+         *
+         * <p>Full tracking requests always override non-full tracking requests. If any full
+         * tracking request occurs, all listeners on the device will receive full tracking GNSS
+         * measurements.
+         */
+        @NonNull public Builder setFullTracking(boolean value) {
+            mFullTracking = value;
+            return this;
+        }
+
+        /** Builds a {@link GnssMeasurementRequest} instance as specified by this builder. */
+        @NonNull
+        public GnssMeasurementRequest build() {
+            return new GnssMeasurementRequest(mFullTracking);
+        }
+    }
+}
diff --git a/location/java/android/location/GnssRequest.java b/location/java/android/location/GnssRequest.java
index 5fc9161..9c9766f 100644
--- a/location/java/android/location/GnssRequest.java
+++ b/location/java/android/location/GnssRequest.java
@@ -45,11 +45,23 @@
      * frequency bands that the chipset supports must be reported in this mode. The GNSS chipset
      * is allowed to consume more power in this mode. If false, GNSS chipset optimizes power via
      * duty cycling, constellations and frequency limits, etc.
+     *
+     * <p>Full GNSS tracking mode affects GnssMeasurement and other GNSS functionalities
+     * including GNSS location.
      */
     public boolean isFullTracking() {
         return mFullTracking;
     }
 
+    /**
+     * Converts the {@link GnssRequest} into a {@link GnssMeasurementRequest}.
+     * @hide
+     */
+    @NonNull
+    public GnssMeasurementRequest toGnssMeasurementRequest() {
+        return new GnssMeasurementRequest.Builder().setFullTracking(isFullTracking()).build();
+    }
+
     @NonNull
     public static final Creator<GnssRequest> CREATOR =
             new Creator<GnssRequest>() {
@@ -131,6 +143,9 @@
          * is allowed to consume more power in this mode. If false, GNSS chipset optimizes power via
          * duty cycling, constellations and frequency limits, etc.
          *
+         * <p>Full GNSS tracking mode affects GnssMeasurement and other GNSS functionalities
+         * including GNSS location.
+         *
          * <p>Full tracking requests always override non-full tracking requests. If any full
          * tracking request occurs, all listeners on the device will receive full tracking GNSS
          * measurements.
diff --git a/location/java/android/location/ILocationManager.aidl b/location/java/android/location/ILocationManager.aidl
index 92e2136..a666eb4 100644
--- a/location/java/android/location/ILocationManager.aidl
+++ b/location/java/android/location/ILocationManager.aidl
@@ -22,7 +22,7 @@
 import android.location.GeocoderParams;
 import android.location.Geofence;
 import android.location.GnssMeasurementCorrections;
-import android.location.GnssRequest;
+import android.location.GnssMeasurementRequest;
 import android.location.IGeocodeListener;
 import android.location.IGnssAntennaInfoListener;
 import android.location.IGnssMeasurementsListener;
@@ -78,7 +78,7 @@
     void registerGnssStatusCallback(in IGnssStatusListener callback, String packageName, String attributionTag);
     void unregisterGnssStatusCallback(in IGnssStatusListener callback);
 
-    void addGnssMeasurementsListener(in GnssRequest request, in IGnssMeasurementsListener listener, String packageName, String attributionTag);
+    void addGnssMeasurementsListener(in GnssMeasurementRequest request, in IGnssMeasurementsListener listener, String packageName, String attributionTag);
     void removeGnssMeasurementsListener(in IGnssMeasurementsListener listener);
     void injectGnssMeasurementCorrections(in GnssMeasurementCorrections corrections);
 
diff --git a/location/java/android/location/LocationManager.java b/location/java/android/location/LocationManager.java
index 914beaf..ecdba1f 100644
--- a/location/java/android/location/LocationManager.java
+++ b/location/java/android/location/LocationManager.java
@@ -2371,7 +2371,7 @@
             handler = new Handler();
         }
 
-        return registerGnssMeasurementsCallback(new GnssRequest.Builder().build(),
+        return registerGnssMeasurementsCallback(new GnssMeasurementRequest.Builder().build(),
                 new HandlerExecutor(handler), callback);
     }
 
@@ -2390,8 +2390,8 @@
     public boolean registerGnssMeasurementsCallback(
             @NonNull @CallbackExecutor Executor executor,
             @NonNull GnssMeasurementsEvent.Callback callback) {
-        return registerGnssMeasurementsCallback(new GnssRequest.Builder().build(), executor,
-                callback);
+        return registerGnssMeasurementsCallback(new GnssMeasurementRequest.Builder().build(),
+                executor, callback);
     }
 
     /**
@@ -2408,14 +2408,42 @@
      * @throws IllegalArgumentException if callback is null
      * @throws SecurityException        if the ACCESS_FINE_LOCATION permission is not present
      * @hide
+     * @deprecated Use {@link #registerGnssMeasurementsCallback(GnssMeasurementRequest, Executor,
+     * GnssMeasurementsEvent.Callback)} instead.
      */
+    @Deprecated
     @SystemApi
-    @RequiresPermission(allOf = {ACCESS_FINE_LOCATION, LOCATION_HARDWARE})
+    @RequiresPermission(ACCESS_FINE_LOCATION)
     public boolean registerGnssMeasurementsCallback(
             @NonNull GnssRequest request,
             @NonNull @CallbackExecutor Executor executor,
             @NonNull GnssMeasurementsEvent.Callback callback) {
         Preconditions.checkArgument(request != null, "invalid null request");
+        getGnssMeasurementsTransportMultiplexer().addListener(request.toGnssMeasurementRequest(),
+                callback, executor);
+        return true;
+    }
+
+    /**
+     * Registers a GNSS measurement callback.
+     *
+     * @param request  extra parameters to pass to GNSS measurement provider. For example, if {@link
+     *                 GnssMeasurementRequest#isFullTracking()} is true, GNSS chipset switches off
+     *                 duty cycling.
+     * @param executor the executor that the callback runs on
+     * @param callback a {@link GnssMeasurementsEvent.Callback} object to register.
+     * @return {@code true} always if the callback was added successfully, {@code false} otherwise.
+     * @throws IllegalArgumentException if request is null
+     * @throws IllegalArgumentException if executor is null
+     * @throws IllegalArgumentException if callback is null
+     * @throws SecurityException        if the ACCESS_FINE_LOCATION permission is not present
+     */
+    @RequiresPermission(ACCESS_FINE_LOCATION)
+    public boolean registerGnssMeasurementsCallback(
+            @NonNull GnssMeasurementRequest request,
+            @NonNull @CallbackExecutor Executor executor,
+            @NonNull GnssMeasurementsEvent.Callback callback) {
+        Preconditions.checkArgument(request != null, "invalid null request");
         getGnssMeasurementsTransportMultiplexer().addListener(request, callback, executor);
         return true;
     }
@@ -2907,14 +2935,14 @@
     }
 
     private class GnssMeasurementsTransportMultiplexer extends
-            ListenerTransportMultiplexer<GnssRequest, GnssMeasurementsEvent.Callback> {
+            ListenerTransportMultiplexer<GnssMeasurementRequest, GnssMeasurementsEvent.Callback> {
 
         private @Nullable IGnssMeasurementsListener mListenerTransport;
 
         GnssMeasurementsTransportMultiplexer() {}
 
         @Override
-        protected void registerWithServer(GnssRequest request) throws RemoteException {
+        protected void registerWithServer(GnssMeasurementRequest request) throws RemoteException {
             IGnssMeasurementsListener transport = mListenerTransport;
             if (transport == null) {
                 transport = new GnssMeasurementsListener();
@@ -2937,9 +2965,10 @@
         }
 
         @Override
-        protected GnssRequest mergeRequests(Collection<GnssRequest> requests) {
-            GnssRequest.Builder builder = new GnssRequest.Builder();
-            for (GnssRequest request : requests) {
+        protected GnssMeasurementRequest mergeRequests(
+                Collection<GnssMeasurementRequest> requests) {
+            GnssMeasurementRequest.Builder builder = new GnssMeasurementRequest.Builder();
+            for (GnssMeasurementRequest request : requests) {
                 if (request.isFullTracking()) {
                     builder.setFullTracking(true);
                     break;
diff --git a/media/java/android/media/AudioDeviceAttributes.java b/media/java/android/media/AudioDeviceAttributes.java
index 6c8b500..7caac89 100644
--- a/media/java/android/media/AudioDeviceAttributes.java
+++ b/media/java/android/media/AudioDeviceAttributes.java
@@ -120,7 +120,13 @@
         mAddress = address;
     }
 
-    /*package*/ AudioDeviceAttributes(int nativeType, @NonNull String address) {
+    /**
+     * @hide
+     * Constructor from internal device type and address
+     * @param type the internal device type, as defined in {@link AudioSystem}
+     * @param address the address of the device, or an empty string for devices without one
+     */
+    public AudioDeviceAttributes(int nativeType, @NonNull String address) {
         mRole = (nativeType & AudioSystem.DEVICE_BIT_IN) != 0 ? ROLE_INPUT : ROLE_OUTPUT;
         mType = AudioDeviceInfo.convertInternalDeviceToDeviceType(nativeType);
         mAddress = address;
@@ -191,10 +197,8 @@
     public String toString() {
         return new String("AudioDeviceAttributes:"
                 + " role:" + roleToString(mRole)
-                + " type:" + (mRole == ROLE_OUTPUT ? AudioSystem.getOutputDeviceName(
-                        AudioDeviceInfo.convertDeviceTypeToInternalDevice(mType))
-                        : AudioSystem.getInputDeviceName(
-                                AudioDeviceInfo.convertDeviceTypeToInternalDevice(mType)))
+                + " type:" + (mRole == ROLE_OUTPUT ? AudioSystem.getOutputDeviceName(mNativeType)
+                        : AudioSystem.getInputDeviceName(mNativeType))
                 + " addr:" + mAddress);
     }
 
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index d9cfb63..367b784 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -6183,6 +6183,29 @@
     }
 
     /**
+     * Returns an {@link AudioDeviceInfo} corresponding to the specified {@link AudioPort} ID.
+     * @param portId The audio port ID to look up for.
+     * @param flags A set of bitflags specifying the criteria to test.
+     * @see #GET_DEVICES_OUTPUTS
+     * @see #GET_DEVICES_INPUTS
+     * @see #GET_DEVICES_ALL
+     * @return An AudioDeviceInfo or null if no device with matching port ID is found.
+     * @hide
+     */
+    public static AudioDeviceInfo getDeviceForPortId(int portId, int flags) {
+        if (portId == 0) {
+            return null;
+        }
+        AudioDeviceInfo[] devices = getDevicesStatic(flags);
+        for (AudioDeviceInfo device : devices) {
+            if (device.getId() == portId) {
+                return device;
+            }
+        }
+        return null;
+    }
+
+    /**
      * Registers an {@link AudioDeviceCallback} object to receive notifications of changes
      * to the set of connected audio devices.
      * @param callback The {@link AudioDeviceCallback} object to receive connect/disconnect
@@ -6869,6 +6892,297 @@
         return hwSyncId;
     }
 
+    /**
+     * Selects the audio device that should be used for communication use cases, for instance voice
+     * or video calls. This method can be used by voice or video chat applications to select a
+     * different audio device than the one selected by default by the platform.
+     * <p>The device selection is expressed as an {@link AudioDeviceInfo}, of role sink
+     * ({@link AudioDeviceInfo#isSink()} is <code>true</code>) and of one of the following types:
+     * <ul>
+     *   <li> {@link AudioDeviceInfo#TYPE_BUILTIN_EARPIECE}
+     *   <li> {@link AudioDeviceInfo#TYPE_BUILTIN_SPEAKER}
+     *   <li> {@link AudioDeviceInfo#TYPE_WIRED_HEADSET}
+     *   <li> {@link AudioDeviceInfo#TYPE_BLUETOOTH_SCO}
+     *   <li> {@link AudioDeviceInfo#TYPE_USB_HEADSET}
+     *   <li> {@link AudioDeviceInfo#TYPE_BLE_HEADSET}
+     * </ul>
+     * The selection is active as long as the requesting application lives, until
+     * {@link #clearDeviceForCommunication} is called or until the device is disconnected.
+     * It is therefore important for applications to clear the request when a call ends or the
+     * application is paused.
+     * <p>In case of simultaneous requests by multiple applications the priority is given to the
+     * application currently controlling the audio mode (see {@link #setMode(int)}). This is the
+     * latest application having selected mode {@link #MODE_IN_COMMUNICATION} or mode
+     * {@link #MODE_IN_CALL}. Note that <code>MODE_IN_CALL</code> can only be selected by the main
+     * telephony application with permission
+     * {@link android.Manifest.permission#MODIFY_PHONE_STATE}.
+     * <p> If the requested devices is not currently available, the request will be rejected and
+     * the method will return false.
+     * <p>This API replaces the following deprecated APIs:
+     * <ul>
+     *   <li> {@link #startBluetoothSco()}
+     *   <li> {@link #stopBluetoothSco()}
+     *   <li> {@link #setSpeakerphoneOn(boolean)}
+     * </ul>
+     * <h4>Example</h4>
+     * <p>The example below shows how to enable and disable speakerphone mode.
+     * <pre class="prettyprint">
+     * // Get an AudioManager instance
+     * AudioManager audioManager = Context.getSystemService(AudioManager.class);
+     * try {
+     *     AudioDeviceInfo speakerDevice = null;
+     *     AudioDeviceInfo[] devices = audioManager.getDevices(GET_DEVICES_OUTPUTS);
+     *     for (AudioDeviceInfo device : devices) {
+     *         if (device.getType() == AudioDeviceInfo.TYPE_BUILTIN_SPEAKER) {
+     *             speakerDevice = device;
+     *             break;
+     *         }
+     *     }
+     *     if (speakerDevice != null) {
+     *         // Turn speakerphone ON.
+     *         boolean result = audioManager.setDeviceForCommunication(speakerDevice);
+     *         if (!result) {
+     *             // Handle error.
+     *         }
+     *         // Turn speakerphone OFF.
+     *         audioManager.clearDeviceForCommunication();
+     *     }
+     * } catch (IllegalArgumentException e) {
+     *     // Handle exception.
+     * }
+     * </pre>
+     * @param device the requested audio device.
+     * @return <code>true</code> if the request was accepted, <code>false</code> otherwise.
+     * @throws IllegalArgumentException If an invalid device is specified.
+     */
+    public boolean setDeviceForCommunication(@NonNull AudioDeviceInfo device) {
+        Objects.requireNonNull(device);
+        try {
+            if (device.getId() == 0) {
+                throw new IllegalArgumentException("In valid device: " + device);
+            }
+            return getService().setDeviceForCommunication(mICallBack, device.getId());
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Cancels previous communication device selection made with
+     * {@link #setDeviceForCommunication(AudioDeviceInfo)}.
+     */
+    public void clearDeviceForCommunication() {
+        try {
+            getService().setDeviceForCommunication(mICallBack, 0);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Returns currently selected audio device for communication.
+     * <p>This API replaces the following deprecated APIs:
+     * <ul>
+     *   <li> {@link #isBluetoothScoOn()}
+     *   <li> {@link #isSpeakerphoneOn()}
+     * </ul>
+     * @return an {@link AudioDeviceInfo} indicating which audio device is
+     * currently selected or communication use cases or null if default selection
+     * is used.
+     */
+    @Nullable
+    public AudioDeviceInfo getDeviceForCommunication() {
+        try {
+            return getDeviceForPortId(
+                    getService().getDeviceForCommunication(), GET_DEVICES_OUTPUTS);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * @hide
+     * Returns an {@link AudioDeviceInfo} corresponding to a connected device of the type provided.
+     * The type must be a valid output type defined in <code>AudioDeviceInfo</code> class,
+     * for instance {@link AudioDeviceInfo#TYPE_BUILTIN_SPEAKER}.
+     * The method will return null if no device of the provided type is connected.
+     * If more than one device of the provided type is connected, an object corresponding to the
+     * first device encountered in the enumeration list will be returned.
+     * @param deviceType The device device for which an <code>AudioDeviceInfo</code>
+     * object is queried.
+     * @return An AudioDeviceInfo object or null if no device with the requested type is connected.
+     * @throws IllegalArgumentException If an invalid device type is specified.
+     */
+    @TestApi
+    @Nullable
+    public static AudioDeviceInfo getDeviceInfoFromType(
+            @AudioDeviceInfo.AudioDeviceTypeOut int deviceType) {
+        AudioDeviceInfo[] devices = getDevicesStatic(GET_DEVICES_OUTPUTS);
+        for (AudioDeviceInfo device : devices) {
+            if (device.getType() == deviceType) {
+                return device;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Listener registered by client to be notified upon communication audio device change.
+     * See {@link #setDeviceForCommunication(AudioDeviceInfo)}.
+     */
+    public interface OnCommunicationDeviceChangedListener {
+        /**
+         * Callback method called upon communication audio device change.
+         * @param device the audio device selected for communication use cases
+         */
+        void onCommunicationDeviceChanged(@Nullable AudioDeviceInfo device);
+    }
+
+    /**
+     * Adds a listener for being notified of changes to the communication audio device.
+     * See {@link #setDeviceForCommunication(AudioDeviceInfo)}.
+     * @param executor
+     * @param listener
+     */
+    public void addOnCommunicationDeviceChangedListener(
+            @NonNull @CallbackExecutor Executor executor,
+            @NonNull OnCommunicationDeviceChangedListener listener) {
+        Objects.requireNonNull(executor);
+        Objects.requireNonNull(listener);
+        synchronized (mCommDevListenerLock) {
+            if (hasCommDevListener(listener)) {
+                throw new IllegalArgumentException(
+                        "attempt to call addOnCommunicationDeviceChangedListener() "
+                                + "on a previously registered listener");
+            }
+            // lazy initialization of the list of strategy-preferred device listener
+            if (mCommDevListeners == null) {
+                mCommDevListeners = new ArrayList<>();
+            }
+            final int oldCbCount = mCommDevListeners.size();
+            mCommDevListeners.add(new CommDevListenerInfo(listener, executor));
+            if (oldCbCount == 0 && mCommDevListeners.size() > 0) {
+                // register binder for callbacks
+                if (mCommDevDispatcherStub == null) {
+                    mCommDevDispatcherStub = new CommunicationDeviceDispatcherStub();
+                }
+                try {
+                    getService().registerCommunicationDeviceDispatcher(mCommDevDispatcherStub);
+                } catch (RemoteException e) {
+                    throw e.rethrowFromSystemServer();
+                }
+            }
+        }
+    }
+
+    /**
+     * Removes a previously added listener of changes to the communication audio device.
+     * See {@link #setDeviceForCommunication(AudioDeviceInfo)}.
+     * @param listener
+     */
+    public void removeOnCommunicationDeviceChangedListener(
+            @NonNull OnCommunicationDeviceChangedListener listener) {
+        Objects.requireNonNull(listener);
+        synchronized (mCommDevListenerLock) {
+            if (!removeCommDevListener(listener)) {
+                throw new IllegalArgumentException(
+                        "attempt to call removeOnCommunicationDeviceChangedListener() "
+                                + "on an unregistered listener");
+            }
+            if (mCommDevListeners.size() == 0) {
+                // unregister binder for callbacks
+                try {
+                    getService().unregisterCommunicationDeviceDispatcher(
+                            mCommDevDispatcherStub);
+                } catch (RemoteException e) {
+                    throw e.rethrowFromSystemServer();
+                } finally {
+                    mCommDevDispatcherStub = null;
+                    mCommDevListeners = null;
+                }
+            }
+        }
+    }
+
+    private final Object mCommDevListenerLock = new Object();
+    /**
+     * List of listeners for preferred device for strategy and their associated Executor.
+     * List is lazy-initialized on first registration
+     */
+    @GuardedBy("mCommDevListenerLock")
+    private @Nullable ArrayList<CommDevListenerInfo> mCommDevListeners;
+
+    private static class CommDevListenerInfo {
+        final @NonNull OnCommunicationDeviceChangedListener mListener;
+        final @NonNull Executor mExecutor;
+
+        CommDevListenerInfo(OnCommunicationDeviceChangedListener listener, Executor exe) {
+            mListener = listener;
+            mExecutor = exe;
+        }
+    }
+
+    @GuardedBy("mCommDevListenerLock")
+    private CommunicationDeviceDispatcherStub mCommDevDispatcherStub;
+
+    private final class CommunicationDeviceDispatcherStub
+            extends ICommunicationDeviceDispatcher.Stub {
+
+        @Override
+        public void dispatchCommunicationDeviceChanged(int portId) {
+            // make a shallow copy of listeners so callback is not executed under lock
+            final ArrayList<CommDevListenerInfo> commDevListeners;
+            synchronized (mCommDevListenerLock) {
+                if (mCommDevListeners == null || mCommDevListeners.size() == 0) {
+                    return;
+                }
+                commDevListeners = (ArrayList<CommDevListenerInfo>) mCommDevListeners.clone();
+            }
+            AudioDeviceInfo device = getDeviceForPortId(portId, GET_DEVICES_OUTPUTS);
+            final long ident = Binder.clearCallingIdentity();
+            try {
+                for (CommDevListenerInfo info : commDevListeners) {
+                    info.mExecutor.execute(() ->
+                            info.mListener.onCommunicationDeviceChanged(device));
+                }
+            } finally {
+                Binder.restoreCallingIdentity(ident);
+            }
+        }
+    }
+
+    @GuardedBy("mCommDevListenerLock")
+    private @Nullable CommDevListenerInfo getCommDevListenerInfo(
+            OnCommunicationDeviceChangedListener listener) {
+        if (mCommDevListeners == null) {
+            return null;
+        }
+        for (CommDevListenerInfo info : mCommDevListeners) {
+            if (info.mListener == listener) {
+                return info;
+            }
+        }
+        return null;
+    }
+
+    @GuardedBy("mCommDevListenerLock")
+    private boolean hasCommDevListener(OnCommunicationDeviceChangedListener listener) {
+        return getCommDevListenerInfo(listener) != null;
+    }
+
+    @GuardedBy("mCommDevListenerLock")
+    /**
+     * @return true if the listener was removed from the list
+     */
+    private boolean removeCommDevListener(OnCommunicationDeviceChangedListener listener) {
+        final CommDevListenerInfo infoToRemove = getCommDevListenerInfo(listener);
+        if (infoToRemove != null) {
+            mCommDevListeners.remove(infoToRemove);
+            return true;
+        }
+        return false;
+    }
+
     //---------------------------------------------------------
     // Inner classes
     //--------------------
diff --git a/media/java/android/media/AudioPlaybackConfiguration.java b/media/java/android/media/AudioPlaybackConfiguration.java
index b9f449c..17305a5 100644
--- a/media/java/android/media/AudioPlaybackConfiguration.java
+++ b/media/java/android/media/AudioPlaybackConfiguration.java
@@ -21,7 +21,6 @@
 
 import android.annotation.IntDef;
 import android.annotation.NonNull;
-import android.annotation.Nullable;
 import android.annotation.SystemApi;
 import android.os.Binder;
 import android.os.IBinder;
@@ -48,8 +47,6 @@
     public static final int PLAYER_PIID_INVALID = -1;
     /** @hide */
     public static final int PLAYER_UPID_INVALID = -1;
-    /** @hide */
-    public static final int PLAYER_DEVICEID_INVALID = 0;
 
     // information about the implementation
     /**
@@ -161,11 +158,6 @@
      */
     @SystemApi
     public static final int PLAYER_STATE_STOPPED = 4;
-    /**
-     * @hide
-     * The state used to update device id, does not actually change the state of the player
-     */
-    public static final int PLAYER_UPDATE_DEVICE_ID = 5;
 
     /** @hide */
     @IntDef({
@@ -174,8 +166,7 @@
         PLAYER_STATE_IDLE,
         PLAYER_STATE_STARTED,
         PLAYER_STATE_PAUSED,
-        PLAYER_STATE_STOPPED,
-        PLAYER_UPDATE_DEVICE_ID
+        PLAYER_STATE_STOPPED
     })
     @Retention(RetentionPolicy.SOURCE)
     public @interface PlayerState {}
@@ -193,8 +184,6 @@
     private int mPlayerState;
     private AudioAttributes mPlayerAttr; // never null
 
-    private int mDeviceId;
-
     /**
      * Never use without initializing parameters afterwards
      */
@@ -212,7 +201,6 @@
         mPlayerType = pic.mPlayerType;
         mClientUid = uid;
         mClientPid = pid;
-        mDeviceId = PLAYER_DEVICEID_INVALID;
         mPlayerState = PLAYER_STATE_IDLE;
         mPlayerAttr = pic.mAttributes;
         if ((sPlayerDeathMonitor != null) && (pic.mIPlayer != null)) {
@@ -253,7 +241,6 @@
                         in.mPlayerAttr.getAllowedCapturePolicy() == ALLOW_CAPTURE_BY_ALL
                         ? ALLOW_CAPTURE_BY_ALL : ALLOW_CAPTURE_BY_NONE)
                 .build();
-        anonymCopy.mDeviceId = in.mDeviceId;
         // anonymized data
         anonymCopy.mPlayerType = PLAYER_TYPE_UNKNOWN;
         anonymCopy.mClientUid = PLAYER_UPID_INVALID;
@@ -291,25 +278,6 @@
     }
 
     /**
-     * Returns information about the {@link AudioDeviceInfo} used for this playback.
-     * @return the audio playback device or null if the device is not available at the time of query
-     */
-    public @Nullable AudioDeviceInfo getAudioDevice() {
-        if (mDeviceId == PLAYER_DEVICEID_INVALID) {
-            return null;
-        }
-        // TODO(175802592): change this to AudioManager.getDeviceForPortId() when available
-        AudioDeviceInfo[] devices =
-                AudioManager.getDevicesStatic(AudioManager.GET_DEVICES_OUTPUTS);
-        for (int i = 0; i < devices.length; i++) {
-            if (devices[i].getId() == mDeviceId) {
-                return devices[i];
-            }
-        }
-        return null;
-    }
-
-    /**
      * @hide
      * Return the type of player linked to this configuration.
      * <br>Note that player types not exposed in the system API will be represented as
@@ -391,29 +359,13 @@
      * @hide
      * Handle a player state change
      * @param event
-     * @param deviceId active device id or {@Code PLAYER_DEVICEID_INVALID}
-     * <br>Note device id is valid for {@code PLAYER_UPDATE_DEVICE_ID} or
-     * <br>{@code PLAYER_STATE_STARTED} events, as the device id will be reset to none when
-     * <br>pausing or stopping playback. It will be set to active device when playback starts or
-     * <br>it will be changed when PLAYER_UPDATE_DEVICE_ID is sent. The latter can happen if the
-     * <br>device changes in the middle of playback.
      * @return true if the state changed, false otherwise
      */
-    public boolean handleStateEvent(int event, int deviceId) {
-        boolean changed = false;
+    public boolean handleStateEvent(int event) {
+        final boolean changed;
         synchronized (this) {
-
-            // Do not update if it is only device id update
-            if (event != PLAYER_UPDATE_DEVICE_ID) {
-                changed = (mPlayerState != event);
-                mPlayerState = event;
-            }
-
-            if (event == PLAYER_STATE_STARTED || event == PLAYER_UPDATE_DEVICE_ID) {
-                changed = changed || (mDeviceId != deviceId);
-                mDeviceId = deviceId;
-            }
-
+            changed = (mPlayerState != event);
+            mPlayerState = event;
             if (changed && (event == PLAYER_STATE_RELEASED) && (mIPlayerShell != null)) {
                 mIPlayerShell.release();
                 mIPlayerShell = null;
@@ -484,7 +436,7 @@
 
     @Override
     public int hashCode() {
-        return Objects.hash(mPlayerIId, mDeviceId, mPlayerType, mClientUid, mClientPid);
+        return Objects.hash(mPlayerIId, mPlayerType, mClientUid, mClientPid);
     }
 
     @Override
@@ -495,7 +447,6 @@
     @Override
     public void writeToParcel(Parcel dest, int flags) {
         dest.writeInt(mPlayerIId);
-        dest.writeInt(mDeviceId);
         dest.writeInt(mPlayerType);
         dest.writeInt(mClientUid);
         dest.writeInt(mClientPid);
@@ -510,7 +461,6 @@
 
     private AudioPlaybackConfiguration(Parcel in) {
         mPlayerIId = in.readInt();
-        mDeviceId = in.readInt();
         mPlayerType = in.readInt();
         mClientUid = in.readInt();
         mClientPid = in.readInt();
@@ -528,7 +478,6 @@
         AudioPlaybackConfiguration that = (AudioPlaybackConfiguration) o;
 
         return ((mPlayerIId == that.mPlayerIId)
-                && (mDeviceId == that.mDeviceId)
                 && (mPlayerType == that.mPlayerType)
                 && (mClientUid == that.mClientUid)
                 && (mClientPid == that.mClientPid));
@@ -537,7 +486,6 @@
     @Override
     public String toString() {
         return "AudioPlaybackConfiguration piid:" + mPlayerIId
-                + " deviceId:" + mDeviceId
                 + " type:" + toLogFriendlyPlayerType(mPlayerType)
                 + " u/pid:" + mClientUid + "/" + mClientPid
                 + " state:" + toLogFriendlyPlayerState(mPlayerState)
@@ -623,7 +571,6 @@
             case PLAYER_STATE_STARTED: return "started";
             case PLAYER_STATE_PAUSED: return "paused";
             case PLAYER_STATE_STOPPED: return "stopped";
-            case PLAYER_UPDATE_DEVICE_ID: return "device";
             default:
                 return "unknown player state - FIXME";
         }
diff --git a/media/java/android/media/AudioSystem.java b/media/java/android/media/AudioSystem.java
index 8987a71..164b194 100644
--- a/media/java/android/media/AudioSystem.java
+++ b/media/java/android/media/AudioSystem.java
@@ -1730,7 +1730,7 @@
         int[] types = new int[devices.size()];
         String[] addresses = new String[devices.size()];
         for (int i = 0; i < devices.size(); ++i) {
-            types[i] = AudioDeviceInfo.convertDeviceTypeToInternalDevice(devices.get(i).getType());
+            types[i] = devices.get(i).getInternalType();
             addresses[i] = devices.get(i).getAddress();
         }
         return setDevicesRoleForStrategy(strategy, role, types, addresses);
diff --git a/media/java/android/media/AudioTrack.java b/media/java/android/media/AudioTrack.java
index e9a18e9..e3b6fba 100644
--- a/media/java/android/media/AudioTrack.java
+++ b/media/java/android/media/AudioTrack.java
@@ -1824,7 +1824,6 @@
 
     @Override
     protected void finalize() {
-        tryToDisableNativeRoutingCallback();
         baseRelease();
         native_finalize();
     }
@@ -2718,15 +2717,9 @@
     }
 
     private void startImpl() {
-        synchronized (mRoutingChangeListeners) {
-            if (!mEnableSelfRoutingMonitor) {
-                testEnableNativeRoutingCallbacksLocked();
-                mEnableSelfRoutingMonitor = true;
-            }
-        }
         synchronized(mPlayStateLock) {
+            baseStart();
             native_start();
-            baseStart(native_getRoutedDeviceId());
             if (mPlayState == PLAYSTATE_PAUSED_STOPPING) {
                 mPlayState = PLAYSTATE_STOPPING;
             } else {
@@ -2764,7 +2757,6 @@
                 mPlayStateLock.notify();
             }
         }
-        tryToDisableNativeRoutingCallback();
     }
 
     /**
@@ -3504,21 +3496,12 @@
         return null;
     }
 
-    private void tryToDisableNativeRoutingCallback() {
-        synchronized (mRoutingChangeListeners) {
-            if (mEnableSelfRoutingMonitor) {
-                mEnableSelfRoutingMonitor = false;
-                testDisableNativeRoutingCallbacksLocked();
-            }
-        }
-    }
-
     /*
      * Call BEFORE adding a routing callback handler.
      */
     @GuardedBy("mRoutingChangeListeners")
     private void testEnableNativeRoutingCallbacksLocked() {
-        if (mRoutingChangeListeners.size() == 0 && !mEnableSelfRoutingMonitor) {
+        if (mRoutingChangeListeners.size() == 0) {
             native_enableDeviceCallback();
         }
     }
@@ -3528,7 +3511,7 @@
      */
     @GuardedBy("mRoutingChangeListeners")
     private void testDisableNativeRoutingCallbacksLocked() {
-        if (mRoutingChangeListeners.size() == 0 && !mEnableSelfRoutingMonitor) {
+        if (mRoutingChangeListeners.size() == 0) {
             native_disableDeviceCallback();
         }
     }
@@ -3545,9 +3528,6 @@
     private ArrayMap<AudioRouting.OnRoutingChangedListener,
             NativeRoutingEventHandlerDelegate> mRoutingChangeListeners = new ArrayMap<>();
 
-    @GuardedBy("mRoutingChangeListeners")
-    private boolean mEnableSelfRoutingMonitor;
-
    /**
     * Adds an {@link AudioRouting.OnRoutingChangedListener} to receive notifications of routing
     * changes on this AudioTrack.
@@ -3647,7 +3627,6 @@
      */
     private void broadcastRoutingChange() {
         AudioManager.resetAudioPortGeneration();
-        baseUpdateDeviceId(getRoutedDevice());
         synchronized (mRoutingChangeListeners) {
             for (NativeRoutingEventHandlerDelegate delegate : mRoutingChangeListeners.values()) {
                 delegate.notifyClient();
diff --git a/media/java/android/media/ExifInterface.java b/media/java/android/media/ExifInterface.java
index de885f49..8ea380a 100644
--- a/media/java/android/media/ExifInterface.java
+++ b/media/java/android/media/ExifInterface.java
@@ -83,6 +83,10 @@
  * <p>
  * Supported for writing: JPEG, PNG, WebP.
  * <p>
+ * Note: JPEG and HEIF files may contain XMP data either inside the Exif data chunk or outside of
+ * it. This class will search both locations for XMP data, but if XMP data exist both inside and
+ * outside Exif, will favor the XMP data inside Exif over the one outside.
+ * <p>
  * Note: It is recommended to use the <a href="{@docRoot}jetpack/androidx.html">AndroidX</a>
  * <a href="{@docRoot}reference/androidx/exifinterface/media/ExifInterface.html">ExifInterface
  * Library</a> since it is a superset of this class. In addition to the functionalities of this
@@ -3185,6 +3189,24 @@
                 readExifSegment(bytes, IFD_TYPE_PRIMARY);
             }
 
+            String xmpOffsetStr = retriever.extractMetadata(
+                    MediaMetadataRetriever.METADATA_KEY_XMP_OFFSET);
+            String xmpLengthStr = retriever.extractMetadata(
+                    MediaMetadataRetriever.METADATA_KEY_XMP_LENGTH);
+            if (xmpOffsetStr != null && xmpLengthStr != null) {
+                int offset = Integer.parseInt(xmpOffsetStr);
+                int length = Integer.parseInt(xmpLengthStr);
+                in.seek(offset);
+                byte[] xmpBytes = new byte[length];
+                if (in.read(xmpBytes) != length) {
+                    throw new IOException("Failed to read XMP from HEIF");
+                }
+                if (getAttribute(TAG_XMP) == null) {
+                    mAttributes[IFD_TYPE_PRIMARY].put(TAG_XMP, new ExifAttribute(
+                            IFD_FORMAT_BYTE, xmpBytes.length, offset, xmpBytes));
+                }
+            }
+
             if (DEBUG) {
                 Log.d(TAG, "Heif meta: " + width + "x" + height + ", rotation " + rotation);
             }
diff --git a/media/java/android/media/HwAudioSource.java b/media/java/android/media/HwAudioSource.java
index bbf632a..01a02f1 100644
--- a/media/java/android/media/HwAudioSource.java
+++ b/media/java/android/media/HwAudioSource.java
@@ -22,8 +22,6 @@
 
 import com.android.internal.util.Preconditions;
 
-import java.util.ArrayList;
-
 /**
  * The HwAudioSource represents the audio playback directly from a source audio device.
  * It currently supports {@link HwAudioSource#start()} and {@link HwAudioSource#stop()} only
@@ -132,32 +130,10 @@
      */
     public void start() {
         Preconditions.checkState(!isPlaying(), "HwAudioSource is currently playing");
+        baseStart();
         mNativeHandle = AudioSystem.startAudioSource(
                 mAudioDeviceInfo.getPort().activeConfig(),
                 mAudioAttributes);
-        // FIXME: b/174876389 clean up device id reporting
-        baseStart(getDeviceId());
-    }
-
-    private int getDeviceId() {
-        ArrayList<AudioPatch> patches = new ArrayList<AudioPatch>();
-        if (AudioManager.listAudioPatches(patches) != AudioManager.SUCCESS) {
-            return 0;
-        }
-
-        for (int i = 0; i < patches.size(); i++) {
-            AudioPatch patch = patches.get(i);
-            AudioPortConfig[] sources = patch.sources();
-            AudioPortConfig[] sinks = patch.sinks();
-            if ((sources != null) && (sources.length > 0)) {
-                for (int c = 0;  c < sources.length; c++) {
-                    if (sources[c].port().id() == mAudioDeviceInfo.getId()) {
-                        return sinks[c].port().id();
-                    }
-                }
-            }
-        }
-        return 0;
     }
 
     /**
diff --git a/media/java/android/media/IAudioService.aidl b/media/java/android/media/IAudioService.aidl
index 77fde6a..bad0d19 100755
--- a/media/java/android/media/IAudioService.aidl
+++ b/media/java/android/media/IAudioService.aidl
@@ -28,6 +28,7 @@
 import android.media.IAudioRoutesObserver;
 import android.media.IAudioServerStateDispatcher;
 import android.media.ICapturePresetDevicesRoleDispatcher;
+import android.media.ICommunicationDeviceDispatcher;
 import android.media.IPlaybackConfigDispatcher;
 import android.media.IRecordingConfigDispatcher;
 import android.media.IRingtonePlayer;
@@ -62,7 +63,7 @@
 
     oneway void playerAttributes(in int piid, in AudioAttributes attr);
 
-    oneway void playerEvent(in int piid, in int event, in int deviceId);
+    oneway void playerEvent(in int piid, in int event);
 
     oneway void releasePlayer(in int piid);
 
@@ -338,4 +339,13 @@
     boolean isMusicActive(in boolean remotely);
 
     int getDevicesForStream(in int streamType);
+
+    boolean setDeviceForCommunication(IBinder cb, int portId);
+
+    int getDeviceForCommunication();
+
+    void registerCommunicationDeviceDispatcher(ICommunicationDeviceDispatcher dispatcher);
+
+    oneway void unregisterCommunicationDeviceDispatcher(
+            ICommunicationDeviceDispatcher dispatcher);
 }
diff --git a/media/java/android/media/ICommunicationDeviceDispatcher.aidl b/media/java/android/media/ICommunicationDeviceDispatcher.aidl
new file mode 100644
index 0000000..429f934
--- /dev/null
+++ b/media/java/android/media/ICommunicationDeviceDispatcher.aidl
@@ -0,0 +1,28 @@
+/*
+ * 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 android.media;
+
+/**
+ * AIDL for AudioService to signal audio communication device updates.
+ *
+ * {@hide}
+ */
+oneway interface ICommunicationDeviceDispatcher {
+
+    void dispatchCommunicationDeviceChanged(int portId);
+
+}
diff --git a/media/java/android/media/MediaCodecInfo.java b/media/java/android/media/MediaCodecInfo.java
index e7e83eb..9657b25e 100644
--- a/media/java/android/media/MediaCodecInfo.java
+++ b/media/java/android/media/MediaCodecInfo.java
@@ -1865,10 +1865,6 @@
                         && aligned.mMaxMacroBlockRate >= otherAligned.mMaxMacroBlockRate);
             }
 
-            /* package private */ boolean isEqualDimension(@NonNull PerformancePoint other) {
-                return mWidth == other.mWidth && mHeight == other.mHeight;
-            }
-
             private @NonNull Size getCommonBlockSize(@NonNull PerformancePoint other) {
                 return new Size(
                         Math.max(mBlockSize.getWidth(), other.mBlockSize.getWidth()) * 16,
@@ -2010,8 +2006,11 @@
          * codecs are active, should use that highest pixel count, and add the frame rates of
          * each individual codec.
          * <p class=note>
-         * Supported resolution could be further restricted for 32-bit processes due to
-         * the limited virtual memory space.
+         * 32-bit processes will not support resolutions larger than 4096x4096 due to
+         * the limited address space, but performance points will be presented as is.
+         * In other words, even though a component publishes a performance point for
+         * a resolution higher than 4096x4096, it does not mean that the resolution is supported
+         * for 32-bit processes.
          */
         @Nullable
         public List<PerformancePoint> getSupportedPerformancePoints() {
@@ -2215,28 +2214,6 @@
                        (a.getMaxFrameRate() != b.getMaxFrameRate()) ?
                                (a.getMaxFrameRate() < b.getMaxFrameRate() ? -1 : 1) : 0));
 
-            // remove redundant points
-            for (int i = 1; i < ret.size(); ++i) {
-                PerformancePoint a = ret.get(i);
-                for (int j = 0; j < i; ++j) {
-                    PerformancePoint b = ret.get(j);
-                    if (b.isEqualDimension(a) && b.covers(a)) {
-                        ret.set(i, null);
-                        break;
-                    }
-                }
-            }
-            int newSize = 0;
-            for (int i = 0; i < ret.size(); ++i) {
-                PerformancePoint a = ret.get(i);
-                if (a == null) {
-                    continue;
-                }
-                ret.set(newSize, a);
-                ++newSize;
-            }
-            ret.setSize(newSize);
-
             return Collections.unmodifiableList(ret);
         }
 
diff --git a/media/java/android/media/MediaFrameworkInitializer.java b/media/java/android/media/MediaFrameworkPlatformInitializer.java
similarity index 87%
rename from media/java/android/media/MediaFrameworkInitializer.java
rename to media/java/android/media/MediaFrameworkPlatformInitializer.java
index 577442e..e703669 100644
--- a/media/java/android/media/MediaFrameworkInitializer.java
+++ b/media/java/android/media/MediaFrameworkPlatformInitializer.java
@@ -28,11 +28,15 @@
 /**
  * Class for performing registration for all media services
  *
- * TODO (b/160513103): Move this class when moving media service code to APEX
+ * TODO (b/160513103): This class is still needed on platform side until
+ * MEDIA_SESSION_SERVICE is moved onto com.android.media apex.
+ * Once that's done, we can move the code that registers the service onto the
+ * MediaFrameworkInitializer class on the apex.
+ *
  * @hide
  */
-public class MediaFrameworkInitializer {
-    private MediaFrameworkInitializer() {
+public class MediaFrameworkPlatformInitializer {
+    private MediaFrameworkPlatformInitializer() {
     }
 
     private static volatile MediaServiceManager sMediaServiceManager;
diff --git a/media/java/android/media/MediaMetadataRetriever.java b/media/java/android/media/MediaMetadataRetriever.java
index 86d1d15..32a9168 100644
--- a/media/java/android/media/MediaMetadataRetriever.java
+++ b/media/java/android/media/MediaMetadataRetriever.java
@@ -1313,14 +1313,14 @@
     public static final int METADATA_KEY_VIDEO_FRAME_COUNT = 32;
 
     /**
-     * If the media contains EXIF data, this key retrieves the offset value
+     * If the media contains EXIF data, this key retrieves the offset (in bytes)
      * of the data.
      */
     public static final int METADATA_KEY_EXIF_OFFSET = 33;
 
     /**
-     * If the media contains EXIF data, this key retrieves the length of the
-     * data.
+     * If the media contains EXIF data, this key retrieves the length (in bytes)
+     * of the data.
      */
     public static final int METADATA_KEY_EXIF_LENGTH = 34;
 
@@ -1371,5 +1371,21 @@
     @SystemApi(client = MODULE_LIBRARIES)
     public static final int METADATA_KEY_VIDEO_CODEC_MIME_TYPE = 40;
 
+    /**
+     * If the media contains XMP data, this key retrieves the offset (in bytes)
+     * of the data.
+     * @hide
+     */
+    @SystemApi(client = MODULE_LIBRARIES)
+    public static final int METADATA_KEY_XMP_OFFSET = 41;
+
+    /**
+     * If the media contains XMP data, this key retrieves the length (in bytes)
+     * of the data.
+     * @hide
+     */
+    @SystemApi(client = MODULE_LIBRARIES)
+    public static final int METADATA_KEY_XMP_LENGTH = 42;
+
     // Add more here...
 }
diff --git a/media/java/android/media/MediaPlayer.java b/media/java/android/media/MediaPlayer.java
index ceac2c9..f8311cd 100644
--- a/media/java/android/media/MediaPlayer.java
+++ b/media/java/android/media/MediaPlayer.java
@@ -1352,6 +1352,7 @@
     }
 
     private void startImpl() {
+        baseStart();
         stayAwake(true);
         _start();
     }
@@ -1377,6 +1378,7 @@
     public void stop() throws IllegalStateException {
         stayAwake(false);
         _stop();
+        baseStop();
     }
 
     private native void _stop() throws IllegalStateException;
@@ -1390,6 +1392,7 @@
     public void pause() throws IllegalStateException {
         stayAwake(false);
         _pause();
+        basePause();
     }
 
     private native void _pause() throws IllegalStateException;
@@ -1494,60 +1497,13 @@
         return null;
     }
 
-
-    /**
-     * Sends device list change notification to all listeners.
-     */
-    private void broadcastRoutingChange() {
-        AudioManager.resetAudioPortGeneration();
-        synchronized (mRoutingChangeListeners) {
-            // Prevent the case where an event is triggered by registering a routing change
-            // listener via the media player.
-            if (mEnableSelfRoutingMonitor) {
-                baseUpdateDeviceId(getRoutedDevice());
-            }
-            for (NativeRoutingEventHandlerDelegate delegate
-                    : mRoutingChangeListeners.values()) {
-                delegate.notifyClient();
-            }
-        }
-    }
-
     /*
-     * Call BEFORE adding a routing callback handler.
+     * Call BEFORE adding a routing callback handler or AFTER removing a routing callback handler.
      */
     @GuardedBy("mRoutingChangeListeners")
-    private void testEnableNativeRoutingCallbacksLocked() {
-        if (mRoutingChangeListeners.size() == 0 && !mEnableSelfRoutingMonitor) {
-            native_enableDeviceCallback(true);
-        }
-    }
-
-    private void tryToEnableNativeRoutingCallback() {
-        synchronized (mRoutingChangeListeners) {
-            if (!mEnableSelfRoutingMonitor) {
-                testEnableNativeRoutingCallbacksLocked();
-                mEnableSelfRoutingMonitor = true;
-            }
-        }
-    }
-
-    private void tryToDisableNativeRoutingCallback() {
-        synchronized (mRoutingChangeListeners) {
-            if (mEnableSelfRoutingMonitor) {
-                mEnableSelfRoutingMonitor = false;
-                testDisableNativeRoutingCallbacksLocked();
-            }
-        }
-    }
-
-    /*
-     * Call AFTER removing a routing callback handler.
-     */
-    @GuardedBy("mRoutingChangeListeners")
-    private void testDisableNativeRoutingCallbacksLocked() {
-        if (mRoutingChangeListeners.size() == 0 && !mEnableSelfRoutingMonitor) {
-            native_enableDeviceCallback(false);
+    private void enableNativeRoutingCallbacksLocked(boolean enabled) {
+        if (mRoutingChangeListeners.size() == 0) {
+            native_enableDeviceCallback(enabled);
         }
     }
 
@@ -1560,9 +1516,6 @@
     private ArrayMap<AudioRouting.OnRoutingChangedListener,
             NativeRoutingEventHandlerDelegate> mRoutingChangeListeners = new ArrayMap<>();
 
-    @GuardedBy("mRoutingChangeListeners")
-    private boolean mEnableSelfRoutingMonitor;
-
     /**
      * Adds an {@link AudioRouting.OnRoutingChangedListener} to receive notifications of routing
      * changes on this MediaPlayer.
@@ -1576,7 +1529,7 @@
             Handler handler) {
         synchronized (mRoutingChangeListeners) {
             if (listener != null && !mRoutingChangeListeners.containsKey(listener)) {
-                testEnableNativeRoutingCallbacksLocked();
+                enableNativeRoutingCallbacksLocked(true);
                 mRoutingChangeListeners.put(
                         listener, new NativeRoutingEventHandlerDelegate(this, listener,
                                 handler != null ? handler : mEventHandler));
@@ -1595,8 +1548,8 @@
         synchronized (mRoutingChangeListeners) {
             if (mRoutingChangeListeners.containsKey(listener)) {
                 mRoutingChangeListeners.remove(listener);
+                enableNativeRoutingCallbacksLocked(false);
             }
-            testDisableNativeRoutingCallbacksLocked();
         }
     }
 
@@ -3348,7 +3301,6 @@
 
     @Override
     protected void finalize() {
-        tryToDisableNativeRoutingCallback();
         baseRelease();
         native_finalize();
     }
@@ -3463,8 +3415,6 @@
 
             case MEDIA_STOPPED:
                 {
-                    tryToDisableNativeRoutingCallback();
-                    baseStop();
                     TimeProvider timeProvider = mTimeProvider;
                     if (timeProvider != null) {
                         timeProvider.onStopped();
@@ -3473,16 +3423,8 @@
                 break;
 
             case MEDIA_STARTED:
-                {
-                    baseStart(native_getRoutedDeviceId());
-                    tryToEnableNativeRoutingCallback();
-                }
-                // fall through
             case MEDIA_PAUSED:
                 {
-                    if (msg.what == MEDIA_PAUSED) {
-                        basePause();
-                    }
                     TimeProvider timeProvider = mTimeProvider;
                     if (timeProvider != null) {
                         timeProvider.onPaused(msg.what == MEDIA_PAUSED);
@@ -3648,8 +3590,14 @@
                 break;
 
             case MEDIA_AUDIO_ROUTING_CHANGED:
-                    broadcastRoutingChange();
-                    return;
+                AudioManager.resetAudioPortGeneration();
+                synchronized (mRoutingChangeListeners) {
+                    for (NativeRoutingEventHandlerDelegate delegate
+                            : mRoutingChangeListeners.values()) {
+                        delegate.notifyClient();
+                    }
+                }
+                return;
 
             case MEDIA_TIME_DISCONTINUITY:
                 final OnMediaTimeDiscontinuityListener mediaTimeListener;
@@ -3855,7 +3803,6 @@
         @Override
         public void onCompletion(MediaPlayer mp) {
             baseStop();
-            tryToDisableNativeRoutingCallback();
         }
     };
 
diff --git a/media/java/android/media/MediaRouter.java b/media/java/android/media/MediaRouter.java
index 36f7bed..d0304f2 100644
--- a/media/java/android/media/MediaRouter.java
+++ b/media/java/android/media/MediaRouter.java
@@ -23,6 +23,9 @@
 import android.annotation.Nullable;
 import android.annotation.SystemService;
 import android.app.ActivityThread;
+import android.bluetooth.BluetoothA2dp;
+import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothHearingAid;
 import android.compat.annotation.UnsupportedAppUsage;
 import android.content.BroadcastReceiver;
 import android.content.Context;
@@ -99,6 +102,7 @@
 
         RouteInfo mDefaultAudioVideo;
         RouteInfo mBluetoothA2dpRoute;
+        volatile boolean mHasActiveBluetoothDevices;
 
         RouteInfo mSelectedRoute;
 
@@ -172,14 +176,20 @@
                     new IntentFilter(DisplayManager.ACTION_WIFI_DISPLAY_STATUS_CHANGED));
             appContext.registerReceiver(new VolumeChangeReceiver(),
                     new IntentFilter(AudioManager.VOLUME_CHANGED_ACTION));
+            IntentFilter intentFilter = new IntentFilter();
+            intentFilter.addAction(BluetoothA2dp.ACTION_ACTIVE_DEVICE_CHANGED);
+            intentFilter.addAction(BluetoothHearingAid.ACTION_ACTIVE_DEVICE_CHANGED);
+            appContext.registerReceiver(new BluetoothStateChangedReceiver(), intentFilter);
 
             mDisplayService.registerDisplayListener(this, mHandler);
 
             AudioRoutesInfo newAudioRoutes = null;
             try {
                 newAudioRoutes = mAudioService.startWatchingRoutes(mAudioRoutesObserver);
+                mHasActiveBluetoothDevices = mAudioService.isBluetoothA2dpOn();
             } catch (RemoteException e) {
             }
+
             if (newAudioRoutes != null) {
                 // This will select the active BT route if there is one and the current
                 // selected route is the default system route, or if there is no selected
@@ -253,7 +263,8 @@
             }
 
             if (audioRoutesChanged) {
-                Log.v(TAG, "Audio routes updated: " + newRoutes + ", a2dp=" + isBluetoothA2dpOn());
+                Log.v(TAG, "Audio routes updated: " + newRoutes + ", hasActiveBTDevices="
+                        + mHasActiveBluetoothDevices);
                 if (mSelectedRoute == null || mSelectedRoute == mDefaultAudioVideo
                         || mSelectedRoute == mBluetoothA2dpRoute) {
                     if (forceUseDefaultRoute || mBluetoothA2dpRoute == null) {
@@ -277,15 +288,6 @@
             return mStreamVolume.get(streamType);
         }
 
-        boolean isBluetoothA2dpOn() {
-            try {
-                return mBluetoothA2dpRoute != null && mAudioService.isBluetoothA2dpOn();
-            } catch (RemoteException e) {
-                Log.e(TAG, "Error querying Bluetooth A2DP state", e);
-                return false;
-            }
-        }
-
         void updateDiscoveryRequest() {
             // What are we looking for today?
             int routeTypes = 0;
@@ -394,7 +396,7 @@
         }
 
         void updateSelectedRouteForId(String routeId) {
-            RouteInfo selectedRoute = isBluetoothA2dpOn()
+            RouteInfo selectedRoute = sStatic.mHasActiveBluetoothDevices
                     ? mBluetoothA2dpRoute : mDefaultAudioVideo;
             final int count = mRoutes.size();
             for (int i = 0; i < count; i++) {
@@ -1043,7 +1045,7 @@
         Log.v(TAG, "Selecting route: " + route);
         assert(route != null);
         final RouteInfo oldRoute = sStatic.mSelectedRoute;
-        final RouteInfo currentSystemRoute = sStatic.isBluetoothA2dpOn()
+        final RouteInfo currentSystemRoute = sStatic.mHasActiveBluetoothDevices
                 ? sStatic.mBluetoothA2dpRoute : sStatic.mDefaultAudioVideo;
         boolean wasDefaultOrBluetoothRoute = (oldRoute == sStatic.mDefaultAudioVideo
                 || oldRoute == sStatic.mBluetoothA2dpRoute);
@@ -1106,7 +1108,8 @@
 
     static void selectDefaultRouteStatic() {
         // TODO: Be smarter about the route types here; this selects for all valid.
-        if (sStatic.mSelectedRoute != sStatic.mBluetoothA2dpRoute && sStatic.isBluetoothA2dpOn()) {
+        if (sStatic.mSelectedRoute != sStatic.mBluetoothA2dpRoute
+                && sStatic.mHasActiveBluetoothDevices) {
             selectRouteStatic(ROUTE_TYPE_ANY, sStatic.mBluetoothA2dpRoute, false);
         } else {
             selectRouteStatic(ROUTE_TYPE_ANY, sStatic.mDefaultAudioVideo, false);
@@ -1443,13 +1446,8 @@
         if (selectedRoute == sStatic.mBluetoothA2dpRoute ||
                 selectedRoute == sStatic.mDefaultAudioVideo) {
             dispatchRouteVolumeChanged(selectedRoute);
-        } else if (sStatic.mBluetoothA2dpRoute != null) {
-            try {
-                dispatchRouteVolumeChanged(sStatic.mAudioService.isBluetoothA2dpOn() ?
-                        sStatic.mBluetoothA2dpRoute : sStatic.mDefaultAudioVideo);
-            } catch (RemoteException e) {
-                Log.e(TAG, "Error checking Bluetooth A2DP state to report volume change", e);
-            }
+        } else if (sStatic.mHasActiveBluetoothDevices) {
+            dispatchRouteVolumeChanged(sStatic.mBluetoothA2dpRoute);
         } else {
             dispatchRouteVolumeChanged(sStatic.mDefaultAudioVideo);
         }
@@ -3172,4 +3170,17 @@
             }
         }
     }
+
+    static class BluetoothStateChangedReceiver extends BroadcastReceiver {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            switch (intent.getAction()) {
+                case BluetoothA2dp.ACTION_ACTIVE_DEVICE_CHANGED:
+                case BluetoothHearingAid.ACTION_ACTIVE_DEVICE_CHANGED:
+                    sStatic.mHasActiveBluetoothDevices =
+                            intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE) != null;
+                    break;
+            }
+        }
+    }
 }
diff --git a/media/java/android/media/MediaServiceManager.java b/media/java/android/media/MediaServiceManager.java
index 21e2d84..96bff4f 100644
--- a/media/java/android/media/MediaServiceManager.java
+++ b/media/java/android/media/MediaServiceManager.java
@@ -17,6 +17,8 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.SystemApi;
+import android.annotation.SystemApi.Client;
 import android.os.IBinder;
 import android.os.ServiceManager;
 
@@ -27,7 +29,11 @@
  * <p> Only the media mainline module will be able to access an instance of this class.
  * @hide
  */
+@SystemApi(client = Client.MODULE_LIBRARIES)
 public class MediaServiceManager {
+    private static final String MEDIA_SESSION_SERVICE = "media_session";
+    private static final String MEDIA_TRANSCODING_SERVICE = "media.transcoding";
+
     /**
      * @hide
      */
@@ -59,10 +65,18 @@
     }
 
     /**
-     * Returns {@link ServiceRegisterer} for the "media_session" service.
+     * Returns {@link ServiceRegisterer} for MEDIA_SESSION_SERVICE.
      */
     @NonNull
     public ServiceRegisterer getMediaSessionServiceRegisterer() {
-        return new ServiceRegisterer("media_session");
+        return new ServiceRegisterer(MEDIA_SESSION_SERVICE);
+    }
+
+    /**
+     * Returns {@link ServiceRegisterer} for MEDIA_TRANSCODING_SERVICE.
+     */
+    @NonNull
+    public ServiceRegisterer getMediaTranscodingServiceRegisterer() {
+        return new ServiceRegisterer(MEDIA_TRANSCODING_SERVICE);
     }
 }
diff --git a/media/java/android/media/OWNERS b/media/java/android/media/OWNERS
index cbc9ab7..cf06fad 100644
--- a/media/java/android/media/OWNERS
+++ b/media/java/android/media/OWNERS
@@ -6,3 +6,4 @@
 olly@google.com
 andrewlewis@google.com
 sungsoo@google.com
+jmtrivi@google.com
diff --git a/media/java/android/media/PlayerBase.java b/media/java/android/media/PlayerBase.java
index 58ae279..da69c6c 100644
--- a/media/java/android/media/PlayerBase.java
+++ b/media/java/android/media/PlayerBase.java
@@ -90,8 +90,6 @@
     private float mPanMultiplierR = 1.0f;
     @GuardedBy("mLock")
     private float mVolMultiplier = 1.0f;
-    @GuardedBy("mLock")
-    private int mDeviceId;
 
     /**
      * Constructor. Must be given audio attributes, as they are required for AppOps.
@@ -154,35 +152,14 @@
         }
     }
 
-    void baseUpdateDeviceId(@Nullable AudioDeviceInfo deviceInfo) {
-        int deviceId = 0;
-        if (deviceInfo != null) {
-            deviceId = deviceInfo.getId();
-        }
-        int piid;
-        synchronized (mLock) {
-            piid = mPlayerIId;
-            mDeviceId = deviceId;
-        }
-        try {
-            getService().playerEvent(piid,
-                    AudioPlaybackConfiguration.PLAYER_UPDATE_DEVICE_ID, deviceId);
-        } catch (RemoteException e) {
-            Log.e(TAG, "Error talking to audio service, "
-                    + deviceId
-                    + " device id will not be tracked for piid=" + piid, e);
-        }
-    }
-
-    private void updateState(int state, int deviceId) {
+    private void updateState(int state) {
         final int piid;
         synchronized (mLock) {
             mState = state;
             piid = mPlayerIId;
-            mDeviceId = deviceId;
         }
         try {
-            getService().playerEvent(piid, state, deviceId);
+            getService().playerEvent(piid, state);
         } catch (RemoteException e) {
             Log.e(TAG, "Error talking to audio service, "
                     + AudioPlaybackConfiguration.toLogFriendlyPlayerState(state)
@@ -190,11 +167,9 @@
         }
     }
 
-    void baseStart(int deviceId) {
-        if (DEBUG) {
-            Log.v(TAG, "baseStart() piid=" + mPlayerIId + " deviceId=" + deviceId);
-        }
-        updateState(AudioPlaybackConfiguration.PLAYER_STATE_STARTED, deviceId);
+    void baseStart() {
+        if (DEBUG) { Log.v(TAG, "baseStart() piid=" + mPlayerIId); }
+        updateState(AudioPlaybackConfiguration.PLAYER_STATE_STARTED);
         synchronized (mLock) {
             if (isRestricted_sync()) {
                 playerSetVolume(true/*muting*/,0, 0);
@@ -216,12 +191,12 @@
 
     void basePause() {
         if (DEBUG) { Log.v(TAG, "basePause() piid=" + mPlayerIId); }
-        updateState(AudioPlaybackConfiguration.PLAYER_STATE_PAUSED, 0);
+        updateState(AudioPlaybackConfiguration.PLAYER_STATE_PAUSED);
     }
 
     void baseStop() {
         if (DEBUG) { Log.v(TAG, "baseStop() piid=" + mPlayerIId); }
-        updateState(AudioPlaybackConfiguration.PLAYER_STATE_STOPPED, 0);
+        updateState(AudioPlaybackConfiguration.PLAYER_STATE_STOPPED);
     }
 
     void baseSetPan(float pan) {
diff --git a/media/java/android/media/SoundPool.java b/media/java/android/media/SoundPool.java
index 797caf3..3f685a4 100644
--- a/media/java/android/media/SoundPool.java
+++ b/media/java/android/media/SoundPool.java
@@ -303,8 +303,7 @@
      */
     public final int play(int soundID, float leftVolume, float rightVolume,
             int priority, int loop, float rate) {
-        // FIXME: b/174876164 implement device id for soundpool
-        baseStart(0);
+        baseStart();
         return _play(soundID, leftVolume, rightVolume, priority, loop, rate);
     }
 
diff --git a/media/java/android/media/session/MediaSessionManager.java b/media/java/android/media/session/MediaSessionManager.java
index 6af39f8..00ee914 100644
--- a/media/java/android/media/session/MediaSessionManager.java
+++ b/media/java/android/media/session/MediaSessionManager.java
@@ -28,7 +28,7 @@
 import android.content.pm.ParceledListSlice;
 import android.media.AudioManager;
 import android.media.IRemoteVolumeControllerCallback;
-import android.media.MediaFrameworkInitializer;
+import android.media.MediaFrameworkPlatformInitializer;
 import android.media.MediaSession2;
 import android.media.Session2Token;
 import android.os.Bundle;
@@ -122,7 +122,7 @@
         // Consider rewriting like DisplayManagerGlobal
         // Decide if we need context
         mContext = context;
-        mService = ISessionManager.Stub.asInterface(MediaFrameworkInitializer
+        mService = ISessionManager.Stub.asInterface(MediaFrameworkPlatformInitializer
                 .getMediaServiceManager()
                 .getMediaSessionServiceRegisterer()
                 .get());
@@ -180,7 +180,7 @@
      * be provided in priority order with the most important controller at index
      * 0.
      * <p>
-     * This requires the android.Manifest.permission.MEDIA_CONTENT_CONTROL
+     * This requires the {@link android.Manifest.permission#MEDIA_CONTENT_CONTROL}
      * permission be held by the calling app. You may also retrieve this list if
      * your app is an enabled notification listener using the
      * {@link NotificationListenerService} APIs, in which case you must pass the
@@ -196,14 +196,18 @@
     }
 
     /**
-     * Get active sessions for a specific user. To retrieve actions for a user
-     * other than your own you must hold the
-     * {@link android.Manifest.permission#INTERACT_ACROSS_USERS_FULL} permission
-     * in addition to any other requirements. If you are an enabled notification
-     * listener you may only get sessions for the users you are enabled for.
+     * Get active sessions for the given user.
+     * <p>
+     * This requires the {@link android.Manifest.permission#MEDIA_CONTENT_CONTROL} permission be
+     * held by the calling app. You may also retrieve this list if your app is an enabled
+     * notification listener using the {@link NotificationListenerService} APIs, in which case you
+     * must pass the {@link ComponentName} of your enabled listener.
+     * <p>
+     * The calling application needs to hold the
+     * {@link android.Manifest.permission#INTERACT_ACROSS_USERS_FULL} permission in order to
+     * retrieve sessions for user ids that do not belong to current process.
      *
-     * @param notificationListener The enabled notification listener component.
-     *            May be null.
+     * @param notificationListener The enabled notification listener component. May be null.
      * @param userId The user id to fetch sessions for.
      * @return A list of controllers for ongoing sessions.
      * @hide
@@ -248,8 +252,9 @@
      * Gets a list of {@link Session2Token} with type {@link Session2Token#TYPE_SESSION} for the
      * given user.
      * <p>
-     * If you want to get tokens for another user, you must hold the
-     * android.Manifest.permission#INTERACT_ACROSS_USERS_FULL permission.
+     * The calling application needs to hold the
+     * {@link android.Manifest.permission#INTERACT_ACROSS_USERS_FULL} permission in order to
+     * retrieve session tokens for user ids that do not belong to current process.
      *
      * @param userId The user id to fetch sessions for.
      * @return A list of {@link Session2Token}
@@ -267,11 +272,12 @@
     }
 
     /**
-     * Add a listener to be notified when the list of active sessions changes. This requires the
-     * {@link android.Manifest.permission#MEDIA_CONTENT_CONTROL} permission be held by the calling
-     * app. You may also retrieve this list if your app is an enabled notification listener using
-     * the {@link NotificationListenerService} APIs, in which case you must pass the
-     * {@link ComponentName} of your enabled listener.
+     * Add a listener to be notified when the list of active sessions changes.
+     * <p>
+     * This requires the {@link android.Manifest.permission#MEDIA_CONTENT_CONTROL} permission be
+     * held by the calling app. You may also retrieve this list if your app is an enabled
+     * notificationlistener using the {@link NotificationListenerService} APIs, in which case you
+     * must pass the {@link ComponentName} of your enabled listener.
      *
      * @param sessionListener The listener to add.
      * @param notificationListener The enabled notification listener component. May be null.
@@ -283,12 +289,13 @@
     }
 
     /**
-     * Add a listener to be notified when the list of active sessions changes. This requires the
-     * {@link android.Manifest.permission#MEDIA_CONTENT_CONTROL} permission be held by the calling
-     * app. You may also retrieve this list if your app is an enabled notification listener using
-     * the {@link NotificationListenerService} APIs, in which case you must pass the
-     * {@link ComponentName} of your enabled listener. Updates will be posted to the handler
-     * specified or to the caller's thread if the handler is null.
+     * Add a listener to be notified when the list of active sessions changes.
+     * <p>
+     * This requires the {@link android.Manifest.permission#MEDIA_CONTENT_CONTROL} permission be
+     * held by the calling app. You may also retrieve this list if your app is an enabled
+     * notification listener using the {@link NotificationListenerService} APIs, in which case you
+     * must pass the {@link ComponentName} of your enabled listener. Updates will be posted to the
+     * handler specified or to the caller's thread if the handler is null.
      *
      * @param sessionListener The listener to add.
      * @param notificationListener The enabled notification listener component. May be null.
@@ -302,15 +309,17 @@
     }
 
     /**
-     * Add a listener to be notified when the list of active sessions changes for the given user.
-     * The calling app must have the {@link android.Manifest.permission#INTERACT_ACROSS_USERS_FULL}
-     * permission if it wants to call this method for a user that is not running the app.
+     * Add a listener to be notified when the list of active sessions changes.
      * <p>
      * This requires the {@link android.Manifest.permission#MEDIA_CONTENT_CONTROL} permission be
      * held by the calling app. You may also retrieve this list if your app is an enabled
      * notification listener using the {@link NotificationListenerService} APIs, in which case you
      * must pass the {@link ComponentName} of your enabled listener. Updates will be posted to the
      * handler specified or to the caller's thread if the handler is null.
+     * <p>
+     * The calling application needs to hold the
+     * {@link android.Manifest.permission#INTERACT_ACROSS_USERS_FULL} permission in order to
+     * add listeners for user ids that do not belong to current process.
      *
      * @param sessionListener The listener to add.
      * @param notificationListener The enabled notification listener component. May be null.
@@ -407,6 +416,10 @@
      * Library</a> for consistent behavior across all devices.
      * <p>
      * Adds a listener to be notified when the {@link #getSession2Tokens()} changes.
+     * <p>
+     * The calling application needs to hold the
+     * {@link android.Manifest.permission#INTERACT_ACROSS_USERS_FULL} permission in order to
+     * add listeners for user ids that do not belong to current process.
      *
      * @param userId The userId to listen for changes on
      * @param listener The listener to add
@@ -705,8 +718,9 @@
     /**
      * Checks whether the remote user is a trusted app.
      * <p>
-     * An app is trusted if the app holds the android.Manifest.permission.MEDIA_CONTENT_CONTROL
-     * permission or has an enabled notification listener.
+     * An app is trusted if the app holds the
+     * {@link android.Manifest.permission#MEDIA_CONTENT_CONTROL} permission or has an enabled
+     * notification listener.
      *
      * @param userInfo The remote user info from either
      *            {@link MediaSession#getCurrentControllerInfo()} or
diff --git a/media/java/android/media/tv/tuner/dvr/DvrRecorder.java b/media/java/android/media/tv/tuner/dvr/DvrRecorder.java
index 8871167..c4b622d 100644
--- a/media/java/android/media/tv/tuner/dvr/DvrRecorder.java
+++ b/media/java/android/media/tv/tuner/dvr/DvrRecorder.java
@@ -47,6 +47,7 @@
     private static int sInstantId = 0;
     private int mSegmentId = 0;
     private int mOverflow;
+    private Boolean mIsStopped = null;
 
     private native int nativeAttachFilter(Filter filter);
     private native int nativeDetachFilter(Filter filter);
@@ -135,7 +136,13 @@
                 .write(FrameworkStatsLog.TV_TUNER_DVR_STATUS, mUserId,
                     FrameworkStatsLog.TV_TUNER_DVR_STATUS__TYPE__RECORD,
                     FrameworkStatsLog.TV_TUNER_DVR_STATUS__STATE__STARTED, mSegmentId, 0);
-        return nativeStartDvr();
+        synchronized (mIsStopped) {
+            int result = nativeStartDvr();
+            if (result == Tuner.RESULT_SUCCESS) {
+                mIsStopped = false;
+            }
+            return result;
+        }
     }
 
     /**
@@ -152,7 +159,13 @@
                 .write(FrameworkStatsLog.TV_TUNER_DVR_STATUS, mUserId,
                     FrameworkStatsLog.TV_TUNER_DVR_STATUS__TYPE__RECORD,
                     FrameworkStatsLog.TV_TUNER_DVR_STATUS__STATE__STOPPED, mSegmentId, mOverflow);
-        return nativeStopDvr();
+        synchronized (mIsStopped) {
+            int result = nativeStopDvr();
+            if (result == Tuner.RESULT_SUCCESS) {
+                mIsStopped = true;
+            }
+            return result;
+        }
     }
 
     /**
@@ -164,7 +177,13 @@
      */
     @Result
     public int flush() {
-        return nativeFlushDvr();
+        synchronized (mIsStopped) {
+            if (mIsStopped) {
+                return nativeFlushDvr();
+            }
+            Log.w(TAG, "Cannot flush non-stopped Record DVR.");
+            return Tuner.RESULT_INVALID_STATE;
+        }
     }
 
     /**
diff --git a/media/jni/android_media_tv_Tuner.cpp b/media/jni/android_media_tv_Tuner.cpp
index 440d5bc..6fa94f1 100644
--- a/media/jni/android_media_tv_Tuner.cpp
+++ b/media/jni/android_media_tv_Tuner.cpp
@@ -337,8 +337,8 @@
 
 /////////////// MediaEvent ///////////////////////
 
-MediaEvent::MediaEvent(sp<Filter> filter, hidl_handle avHandle,
-        uint64_t dataId, uint64_t dataSize, jobject obj) : mFilter(filter),
+MediaEvent::MediaEvent(sp<FilterClient> filterClient, hidl_handle avHandle,
+        uint64_t dataId, uint64_t dataSize, jobject obj) : mFilterClient(filterClient),
         mDataId(dataId), mDataSize(dataSize), mBuffer(nullptr),
         mDataIdRefCnt(0), mAvHandleRefCnt(0), mIonHandle(nullptr) {
     JNIEnv *env = AndroidRuntime::getJNIEnv();
@@ -359,12 +359,13 @@
     if (pC2Buffer != NULL) {
         pC2Buffer->unregisterOnDestroyNotify(&DestroyCallback, this);
     }
+    mFilterClient = NULL;
 }
 
 void MediaEvent::finalize() {
-    if (mAvHandleRefCnt == 0) {
-        mFilter->mFilterSp->releaseAvHandle(
-                hidl_handle(mAvHandle), mDataIdRefCnt == 0 ? mDataId : 0);
+    if (mAvHandleRefCnt == 0 && mFilterClient != NULL) {
+        mFilterClient->releaseAvHandle(
+                mAvHandle, mDataIdRefCnt == 0 ? mDataId : 0);
         native_handle_close(mAvHandle);
     }
 }
@@ -382,21 +383,25 @@
     int numInts = 0;
     int memIndex;
     int dataSize;
+    SharedHandleInfo info = mFilterClient->getAvSharedHandleInfo();
+    native_handle_t* avSharedHandle = info.sharedHandle;
+    uint64_t avSharedMemSize = info.size;
+
     if (mAvHandle->numFds == 0) {
-        if (mFilter->mAvSharedHandle == NULL) {
+        if (avSharedHandle == NULL) {
             ALOGE("Shared AV memory handle is not initialized.");
             return NULL;
         }
-        if (mFilter->mAvSharedHandle->numFds == 0) {
+        if (avSharedHandle->numFds == 0) {
             ALOGE("Shared AV memory handle is empty.");
             return NULL;
         }
-        fd = mFilter->mAvSharedHandle->data[0];
-        dataSize = mFilter->mAvSharedMemSize;
-        numInts = mFilter->mAvSharedHandle->numInts;
+        fd = avSharedHandle->data[0];
+        dataSize = avSharedMemSize;
+        numInts = avSharedHandle->numInts;
         if (numInts > 0) {
             // If the first int in the shared native handle has value, use it as the index
-            memIndex = mFilter->mAvSharedHandle->data[mFilter->mAvSharedHandle->numFds];
+            memIndex = avSharedHandle->data[avSharedHandle->numFds];
         }
     } else {
         fd = mAvHandle->data[0];
@@ -407,11 +412,11 @@
             // event has value, use it as the index
             memIndex = mAvHandle->data[mAvHandle->numFds];
         } else {
-            if (mFilter->mAvSharedHandle != NULL) {
-                numInts = mFilter->mAvSharedHandle->numInts;
+            if (avSharedHandle != NULL) {
+                numInts = avSharedHandle->numInts;
                 if (numInts > 0) {
                     // If the first int in the shared native handle has value, use it as the index
-                    memIndex = mFilter->mAvSharedHandle->data[mFilter->mAvSharedHandle->numFds];
+                    memIndex = avSharedHandle->data[avSharedHandle->numFds];
                 }
             }
         }
@@ -462,9 +467,9 @@
     return mDataId;
 }
 
-/////////////// FilterCallback ///////////////////////
+/////////////// FilterClientCallbackImpl ///////////////////////
 
-jobjectArray FilterCallback::getSectionEvent(
+jobjectArray FilterClientCallbackImpl::getSectionEvent(
         jobjectArray& arr, const std::vector<DemuxFilterEvent::Event>& events) {
     JNIEnv *env = AndroidRuntime::getJNIEnv();
     jclass eventClazz = env->FindClass("android/media/tv/tuner/filter/SectionEvent");
@@ -486,7 +491,7 @@
     return arr;
 }
 
-jobjectArray FilterCallback::getMediaEvent(
+jobjectArray FilterClientCallbackImpl::getMediaEvent(
         jobjectArray& arr, const std::vector<DemuxFilterEvent::Event>& events) {
     JNIEnv *env = AndroidRuntime::getJNIEnv();
     jclass eventClazz = env->FindClass("android/media/tv/tuner/filter/MediaEvent");
@@ -537,7 +542,7 @@
 
         if (mediaEvent.avMemory.getNativeHandle() != NULL || mediaEvent.avDataId != 0) {
             sp<MediaEvent> mediaEventSp =
-                           new MediaEvent(mFilter, mediaEvent.avMemory,
+                           new MediaEvent(mFilterClient, mediaEvent.avMemory,
                                mediaEvent.avDataId, dataLength + offset, obj);
             mediaEventSp->mAvHandleRefCnt++;
             env->SetLongField(obj, eventContext, (jlong) mediaEventSp.get());
@@ -549,7 +554,7 @@
     return arr;
 }
 
-jobjectArray FilterCallback::getPesEvent(
+jobjectArray FilterClientCallbackImpl::getPesEvent(
         jobjectArray& arr, const std::vector<DemuxFilterEvent::Event>& events) {
     JNIEnv *env = AndroidRuntime::getJNIEnv();
     jclass eventClazz = env->FindClass("android/media/tv/tuner/filter/PesEvent");
@@ -570,7 +575,7 @@
     return arr;
 }
 
-jobjectArray FilterCallback::getTsRecordEvent(
+jobjectArray FilterClientCallbackImpl::getTsRecordEvent(
         jobjectArray& arr, const std::vector<DemuxFilterEvent::Event>& events,
                 const std::vector<DemuxFilterEventExt::Event>& eventsExt) {
     JNIEnv *env = AndroidRuntime::getJNIEnv();
@@ -623,7 +628,7 @@
     return arr;
 }
 
-jobjectArray FilterCallback::getMmtpRecordEvent(
+jobjectArray FilterClientCallbackImpl::getMmtpRecordEvent(
         jobjectArray& arr, const std::vector<DemuxFilterEvent::Event>& events,
                 const std::vector<DemuxFilterEventExt::Event>& eventsExt) {
     JNIEnv *env = AndroidRuntime::getJNIEnv();
@@ -665,7 +670,7 @@
     return arr;
 }
 
-jobjectArray FilterCallback::getDownloadEvent(
+jobjectArray FilterClientCallbackImpl::getDownloadEvent(
         jobjectArray& arr, const std::vector<DemuxFilterEvent::Event>& events) {
     JNIEnv *env = AndroidRuntime::getJNIEnv();
     jclass eventClazz = env->FindClass("android/media/tv/tuner/filter/DownloadEvent");
@@ -689,7 +694,7 @@
     return arr;
 }
 
-jobjectArray FilterCallback::getIpPayloadEvent(
+jobjectArray FilterClientCallbackImpl::getIpPayloadEvent(
         jobjectArray& arr, const std::vector<DemuxFilterEvent::Event>& events) {
     JNIEnv *env = AndroidRuntime::getJNIEnv();
     jclass eventClazz = env->FindClass("android/media/tv/tuner/filter/IpPayloadEvent");
@@ -705,7 +710,7 @@
     return arr;
 }
 
-jobjectArray FilterCallback::getTemiEvent(
+jobjectArray FilterClientCallbackImpl::getTemiEvent(
         jobjectArray& arr, const std::vector<DemuxFilterEvent::Event>& events) {
     JNIEnv *env = AndroidRuntime::getJNIEnv();
     jclass eventClazz = env->FindClass("android/media/tv/tuner/filter/TemiEvent");
@@ -728,7 +733,7 @@
     return arr;
 }
 
-jobjectArray FilterCallback::getScramblingStatusEvent(
+jobjectArray FilterClientCallbackImpl::getScramblingStatusEvent(
         jobjectArray& arr, const std::vector<DemuxFilterEventExt::Event>& eventsExt) {
     JNIEnv *env = AndroidRuntime::getJNIEnv();
     jclass eventClazz = env->FindClass("android/media/tv/tuner/filter/ScramblingStatusEvent");
@@ -740,7 +745,7 @@
     return arr;
 }
 
-jobjectArray FilterCallback::getIpCidChangeEvent(
+jobjectArray FilterClientCallbackImpl::getIpCidChangeEvent(
         jobjectArray& arr, const std::vector<DemuxFilterEventExt::Event>& eventsExt) {
     JNIEnv *env = AndroidRuntime::getJNIEnv();
     jclass eventClazz = env->FindClass("android/media/tv/tuner/filter/IpCidChangeEvent");
@@ -752,7 +757,7 @@
     return arr;
 }
 
-jobjectArray FilterCallback::getRestartEvent(
+jobjectArray FilterClientCallbackImpl::getRestartEvent(
         jobjectArray& arr, const std::vector<DemuxFilterEventExt::Event>& eventsExt) {
     JNIEnv *env = AndroidRuntime::getJNIEnv();
     jclass eventClazz = env->FindClass("android/media/tv/tuner/filter/RestartEvent");
@@ -764,9 +769,9 @@
     return arr;
 }
 
-Return<void> FilterCallback::onFilterEvent_1_1(const DemuxFilterEvent& filterEvent,
+void FilterClientCallbackImpl::onFilterEvent_1_1(const DemuxFilterEvent& filterEvent,
         const DemuxFilterEventExt& filterEventExt) {
-    ALOGD("FilterCallback::onFilterEvent_1_1");
+    ALOGD("FilterClientCallbackImpl::onFilterEvent_1_1");
 
     JNIEnv *env = AndroidRuntime::getJNIEnv();
     jobjectArray array;
@@ -848,14 +853,13 @@
         }
     }
     env->CallVoidMethod(
-            mFilter->mFilterObj,
+            mFilterObj,
             gFields.onFilterEventID,
             array);
-    return Void();
 }
 
-Return<void> FilterCallback::onFilterEvent(const DemuxFilterEvent& filterEvent) {
-    ALOGD("FilterCallback::onFilterEvent");
+void FilterClientCallbackImpl::onFilterEvent(const DemuxFilterEvent& filterEvent) {
+    ALOGD("FilterClientCallbackImpl::onFilterEvent");
     std::vector<DemuxFilterEventExt::Event> emptyEventsExt;
     DemuxFilterEventExt emptyFilterEventExt {
             .events = emptyEventsExt,
@@ -863,49 +867,20 @@
     return onFilterEvent_1_1(filterEvent, emptyFilterEventExt);
 }
 
-Return<void> FilterCallback::onFilterStatus(const DemuxFilterStatus status) {
-    ALOGD("FilterCallback::onFilterStatus");
+void FilterClientCallbackImpl::onFilterStatus(const DemuxFilterStatus status) {
+    ALOGD("FilterClientCallbackImpl::onFilterStatus");
     JNIEnv *env = AndroidRuntime::getJNIEnv();
     env->CallVoidMethod(
-            mFilter->mFilterObj,
+            mFilterObj,
             gFields.onFilterStatusID,
             (jint)status);
-    return Void();
 }
 
-void FilterCallback::setFilter(const sp<Filter> filter) {
-    ALOGD("FilterCallback::setFilter");
-    // JNI Object
-    mFilter = filter;
-}
-
-FilterCallback::~FilterCallback() {}
-
-/////////////// Filter ///////////////////////
-
-Filter::Filter(sp<IFilter> sp, jobject obj) : mFilterSp(sp) {
-    JNIEnv *env = AndroidRuntime::getJNIEnv();
-    mFilterObj = env->NewWeakGlobalRef(obj);
-}
-
-Filter::~Filter() {
-    JNIEnv *env = AndroidRuntime::getJNIEnv();
-
-    env->DeleteWeakGlobalRef(mFilterObj);
-    mFilterObj = NULL;
-    EventFlag::deleteEventFlag(&mFilterMQEventFlag);
-}
-
-int Filter::close() {
-    Result r = mFilterSp->close();
-    if (r == Result::SUCCESS) {
-        EventFlag::deleteEventFlag(&mFilterMQEventFlag);
-    }
-    return (int)r;
-}
-
-sp<IFilter> Filter::getIFilter() {
-    return mFilterSp;
+void FilterClientCallbackImpl::setFilter(jweak filterObj, sp<FilterClient> filterClient) {
+    ALOGD("FilterClientCallbackImpl::setFilter");
+    // Java Object
+    mFilterObj = filterObj;
+    mFilterClient = filterClient;
 }
 
 /////////////// TimeFilter ///////////////////////
@@ -927,22 +902,23 @@
     return mTimeFilterSp;
 }
 
-/////////////// FrontendCallback ///////////////////////
+/////////////// FrontendClientCallbackImpl ///////////////////////
 
-FrontendCallback::FrontendCallback(jweak tunerObj, FrontendId id) : mObject(tunerObj), mId(id) {}
+FrontendClientCallbackImpl::FrontendClientCallbackImpl(
+        jweak tunerObj, FrontendId id) : mObject(tunerObj), mId(id) {}
 
-Return<void> FrontendCallback::onEvent(FrontendEventType frontendEventType) {
-    ALOGD("FrontendCallback::onEvent, type=%d", frontendEventType);
+void FrontendClientCallbackImpl::onEvent(FrontendEventType frontendEventType) {
+    ALOGD("FrontendClientCallbackImpl::onEvent, type=%d", frontendEventType);
     JNIEnv *env = AndroidRuntime::getJNIEnv();
     env->CallVoidMethod(
             mObject,
             gFields.onFrontendEventID,
             (jint)frontendEventType);
-    return Void();
 }
 
-Return<void> FrontendCallback::onScanMessage(FrontendScanMessageType type, const FrontendScanMessage& message) {
-    ALOGD("FrontendCallback::onScanMessage, type=%d", type);
+void FrontendClientCallbackImpl::onScanMessage(
+        FrontendScanMessageType type, const FrontendScanMessage& message) {
+    ALOGD("FrontendClientCallbackImpl::onScanMessage, type=%d", type);
     JNIEnv *env = AndroidRuntime::getJNIEnv();
     jclass clazz = env->FindClass("android/media/tv/tuner/Tuner");
     switch(type) {
@@ -1050,13 +1026,15 @@
                         mObject,
                         env->GetMethodID(clazz, "onDvbsStandard", "(I)V"),
                         standard);
-            } else if (std.getDiscriminator() == FrontendScanMessage::Standard::hidl_discriminator::tStd) {
+            } else if (std.getDiscriminator() ==
+                    FrontendScanMessage::Standard::hidl_discriminator::tStd) {
                 standard = (jint) std.tStd();
                 env->CallVoidMethod(
                         mObject,
                         env->GetMethodID(clazz, "onDvbtStandard", "(I)V"),
                         standard);
-            } else if (std.getDiscriminator() == FrontendScanMessage::Standard::hidl_discriminator::sifStd) {
+            } else if (std.getDiscriminator() ==
+                    FrontendScanMessage::Standard::hidl_discriminator::sifStd) {
                 standard = (jint) std.sifStd();
                 env->CallVoidMethod(
                         mObject,
@@ -1081,17 +1059,17 @@
             }
             env->CallVoidMethod(
                     mObject,
-                    env->GetMethodID(clazz, "onAtsc3PlpInfos", "([Landroid/media/tv/tuner/frontend/Atsc3PlpInfo;)V"),
+                    env->GetMethodID(clazz, "onAtsc3PlpInfos",
+                            "([Landroid/media/tv/tuner/frontend/Atsc3PlpInfo;)V"),
                     array);
             break;
         }
     }
-    return Void();
 }
 
-Return<void> FrontendCallback::onScanMessageExt1_1(FrontendScanMessageTypeExt1_1 type,
+void FrontendClientCallbackImpl::onScanMessageExt1_1(FrontendScanMessageTypeExt1_1 type,
         const FrontendScanMessageExt1_1& message) {
-    ALOGD("FrontendCallback::onScanMessageExt1_1, type=%d", type);
+    ALOGD("FrontendClientCallbackImpl::onScanMessageExt1_1, type=%d", type);
     JNIEnv *env = AndroidRuntime::getJNIEnv();
     jclass clazz = env->FindClass("android/media/tv/tuner/Tuner");
     switch(type) {
@@ -1165,7 +1143,6 @@
         default:
             break;
     }
-    return Void();
 }
 
 /////////////// Tuner ///////////////////////
@@ -1202,7 +1179,11 @@
     env->DeleteWeakGlobalRef(mObject);
     env->DeleteGlobalRef(mClass);
     mTuner = NULL;
+    mFe = NULL;
+    mDemux = NULL;
     mTunerClient = NULL;
+    mFeClient = NULL;
+    mDemuxClient = NULL;
     mClass = NULL;
     mObject = NULL;
 }
@@ -1252,9 +1233,11 @@
     return obj;
 }
 
-jobject JTuner::openFrontendById(int id) {
+jobject JTuner::openFrontendByHandle(int feHandle) {
     sp<IFrontend> fe;
     Result res;
+    uint32_t id = getResourceIdFromHandle(feHandle);
+
     mTuner->openFrontendById(id, [&](Result r, const sp<IFrontend>& frontend) {
         fe = frontend;
         res = r;
@@ -1269,11 +1252,25 @@
     if (mDemux != NULL) {
         mDemux->setFrontendDataSource(mFeId);
     }
-    sp<FrontendCallback> feCb = new FrontendCallback(mObject, id);
-    fe->setCallback(feCb);
 
     jint jId = (jint) id;
 
+    // TODO: Handle reopening frontend with different handle
+    sp<FrontendClient> feClient = mTunerClient->openFrontend(feHandle);
+    if (feClient == NULL) {
+        ALOGE("Failed to open frontend");
+        return NULL;
+    }
+    mFeClient = feClient;
+
+    mFeId = mFeClient->getId();
+    jId = (jint) id;
+    if (mDemuxClient != NULL) {
+        mDemuxClient->setFrontendDataSource(mFeClient);
+    }
+    sp<FrontendClientCallbackImpl> feClientCb = new FrontendClientCallbackImpl(mObject, id);
+    mFeClient->setCallback(feClientCb);
+
     JNIEnv *env = AndroidRuntime::getJNIEnv();
     // TODO: add more fields to frontend
     return env->NewObject(
@@ -1589,30 +1586,19 @@
 }
 
 int JTuner::tune(const FrontendSettings& settings, const FrontendSettingsExt1_1& settingsExt1_1) {
-    if (mFe == NULL) {
+    if (mFeClient == nullptr) {
         ALOGE("frontend is not initialized");
         return (int)Result::INVALID_STATE;
     }
-    Result result;
-    sp<::android::hardware::tv::tuner::V1_1::IFrontend> fe_1_1 =
-            ::android::hardware::tv::tuner::V1_1::IFrontend::castFrom(mFe);
-    if (fe_1_1 == NULL) {
-        ALOGD("1.1 frontend is not found. Using 1.0 instead.");
-        result = mFe->tune(settings);
-        return (int)result;
-    }
-
-    result = fe_1_1->tune_1_1(settings, settingsExt1_1);
-    return (int)result;
+    return (int) mFeClient->tune(settings,settingsExt1_1);
 }
 
 int JTuner::stopTune() {
-    if (mFe == NULL) {
+    if (mFeClient == nullptr) {
         ALOGE("frontend is not initialized");
         return (int)Result::INVALID_STATE;
     }
-    Result result = mFe->stopTune();
-    return (int)result;
+    return (int) mFeClient->stopTune();
 }
 
 int JTuner::scan(const FrontendSettings& settings, FrontendScanType scanType,
@@ -1662,28 +1648,47 @@
 }
 
 Result JTuner::openDemux() {
-    if (mTuner == nullptr) {
+    if (mTuner == nullptr || mTunerClient == nullptr) {
         return Result::NOT_INITIALIZED;
     }
-    if (mDemux != nullptr) {
-        return Result::SUCCESS;
-    }
-    Result res;
-    uint32_t id;
-    sp<IDemux> demuxSp;
-    mTuner->openDemux([&](Result r, uint32_t demuxId, const sp<IDemux>& demux) {
-        demuxSp = demux;
-        id = demuxId;
-        res = r;
-        ALOGD("open demux, id = %d", demuxId);
-    });
-    if (res == Result::SUCCESS) {
-        mDemux = demuxSp;
-        mDemuxId = id;
-        if (mFe != NULL) {
-            mDemux->setFrontendDataSource(mFeId);
+
+    Result res = Result::SUCCESS;
+
+    if (mDemux == nullptr) {
+        uint32_t id;
+        sp<IDemux> demuxSp;
+        mTuner->openDemux([&](Result r, uint32_t demuxId, const sp<IDemux>& demux) {
+            demuxSp = demux;
+            id = demuxId;
+            res = r;
+            ALOGD("open demux, id = %d", demuxId);
+        });
+        if (res == Result::SUCCESS) {
+            mDemux = demuxSp;
+            mDemuxId = id;
+            if (mFe != NULL) {
+                mDemux->setFrontendDataSource(mFeId);
+            }
+        } else {
+            return res;
         }
     }
+
+    // TODO: replace demux opening with mTunerClient->openDemux(handle)
+    // when DemuxClient is fully ready
+    if (mDemuxClient == nullptr) {
+        sp<DemuxClient> demuxClient = new DemuxClient();
+        if (demuxClient == NULL) {
+            ALOGE("Failed to open demux");
+            return Result::UNKNOWN_ERROR;
+        }
+        mDemuxClient = demuxClient;
+        mDemuxClient->setHidlDemux(mDemux);
+        if (mFeClient != NULL) {
+            mDemuxClient->setFrontendDataSource(mFeClient);
+        }
+    }
+
     return res;
 }
 
@@ -1701,23 +1706,31 @@
             return (jint) res;
         }
     }
+
+    if (mFeClient != NULL) {
+        res = mFeClient->close();
+        if (res != Result::SUCCESS) {
+            return (jint) res;
+        }
+        mFeClient = NULL;
+    }
+    if (mDemuxClient != NULL) {
+        res = mDemuxClient->close();
+        if (res != Result::SUCCESS) {
+            return (jint) res;
+        }
+        mDemuxClient = NULL;
+    }
     return (jint) res;
 }
 
-jobject JTuner::getAvSyncHwId(sp<Filter> filter) {
-    if (mDemux == NULL) {
+jobject JTuner::getAvSyncHwId(sp<FilterClient> filterClient) {
+    if (mDemuxClient == NULL) {
         return NULL;
     }
 
-    uint32_t avSyncHwId;
-    Result res;
-    sp<IFilter> iFilterSp = filter->getIFilter();
-    mDemux->getAvSyncHwId(iFilterSp,
-            [&](Result r, uint32_t id) {
-                res = r;
-                avSyncHwId = id;
-            });
-    if (res == Result::SUCCESS) {
+    int avSyncHwId = mDemuxClient->getAvSyncHwId(filterClient);
+    if (avSyncHwId >= 0) {
         JNIEnv *env = AndroidRuntime::getJNIEnv();
         jclass integerClazz = env->FindClass("java/lang/Integer");
         jmethodID intInit = env->GetMethodID(integerClazz, "<init>", "(I)V");
@@ -1727,17 +1740,11 @@
 }
 
 jobject JTuner::getAvSyncTime(jint id) {
-    if (mDemux == NULL) {
+    if (mDemuxClient == NULL) {
         return NULL;
     }
-    uint64_t time;
-    Result res;
-    mDemux->getAvSyncTime(static_cast<uint32_t>(id),
-            [&](Result r, uint64_t ts) {
-                res = r;
-                time = ts;
-            });
-    if (res == Result::SUCCESS) {
+    long time = mDemuxClient->getAvSyncTime((int)id);
+    if (time >= 0) {
         JNIEnv *env = AndroidRuntime::getJNIEnv();
         jclass longClazz = env->FindClass("java/lang/Long");
         jmethodID longInit = env->GetMethodID(longClazz, "<init>", "(J)V");
@@ -1747,13 +1754,13 @@
 }
 
 int JTuner::connectCiCam(jint id) {
-    if (mDemux == NULL) {
+    if (mDemuxClient == NULL) {
         Result r = openDemux();
         if (r != Result::SUCCESS) {
             return (int) r;
         }
     }
-    Result r = mDemux->connectCiCam(static_cast<uint32_t>(id));
+    Result r = mDemuxClient->connectCiCam((int)id);
     return (int) r;
 }
 
@@ -1779,13 +1786,13 @@
 }
 
 int JTuner::disconnectCiCam() {
-    if (mDemux == NULL) {
+    if (mDemuxClient == NULL) {
         Result r = openDemux();
         if (r != Result::SUCCESS) {
             return (int) r;
         }
     }
-    Result r = mDemux->disconnectCiCam();
+    Result r = mDemuxClient->disconnectCiCam();
     return (int) r;
 }
 
@@ -1832,34 +1839,25 @@
 }
 
 jobject JTuner::openFilter(DemuxFilterType type, int bufferSize) {
-    if (mDemux == NULL) {
+    if (mDemux == NULL || mDemuxClient == NULL) {
         if (openDemux() != Result::SUCCESS) {
             return NULL;
         }
     }
 
-    sp<IFilter> iFilterSp;
-    sp<::android::hardware::tv::tuner::V1_1::IFilter> iFilterSp_1_1;
-    sp<FilterCallback> callback = new FilterCallback();
-    Result res;
-    mDemux->openFilter(type, bufferSize, callback,
-            [&](Result r, const sp<IFilter>& filter) {
-                iFilterSp = filter;
-                res = r;
-            });
-    if (res != Result::SUCCESS || iFilterSp == NULL) {
+    sp<FilterClient> filterClient;
+    sp<FilterClientCallbackImpl> callback = new FilterClientCallbackImpl();
+    filterClient = mDemuxClient->openFilter(type, bufferSize, callback);
+    if (filterClient == NULL) {
         ALOGD("Failed to open filter, type = %d", type.mainType);
         return NULL;
     }
     uint64_t fId;
-    iFilterSp->getId([&](Result, uint32_t filterId) {
-        fId = filterId;
-    });
-    iFilterSp_1_1 = ::android::hardware::tv::tuner::V1_1::IFilter::castFrom(iFilterSp);
-    if (iFilterSp_1_1 != NULL) {
-        iFilterSp_1_1->getId64Bit([&](Result, uint64_t filterId64Bit) {
-            fId = filterId64Bit;
-        });
+    Result res = filterClient->getId64Bit(fId);
+    if (res != Result::SUCCESS) {
+        uint32_t id;
+        filterClient->getId(id);
+        fId = static_cast<uint64_t>(id);
     }
 
     JNIEnv *env = AndroidRuntime::getJNIEnv();
@@ -1869,35 +1867,9 @@
                     gFields.filterInitID,
                     (jlong) fId);
 
-    sp<Filter> filterSp = new Filter(iFilterSp, filterObj);
-    filterSp->incStrong(filterObj);
-    env->SetLongField(filterObj, gFields.filterContext, (jlong)filterSp.get());
-    filterSp->mIsMediaFilter = false;
-    filterSp->mAvSharedHandle = NULL;
-    callback->setFilter(filterSp);
-
-    if (type.mainType == DemuxFilterMainType::MMTP) {
-        if (type.subType.mmtpFilterType() == DemuxMmtpFilterType::AUDIO ||
-                type.subType.mmtpFilterType() == DemuxMmtpFilterType::VIDEO) {
-            filterSp->mIsMediaFilter = true;
-        }
-    }
-
-    if (type.mainType == DemuxFilterMainType::TS) {
-        if (type.subType.tsFilterType() == DemuxTsFilterType::AUDIO ||
-                type.subType.tsFilterType() == DemuxTsFilterType::VIDEO) {
-            filterSp->mIsMediaFilter = true;
-        }
-    }
-
-    if (iFilterSp_1_1 != NULL && filterSp->mIsMediaFilter) {
-        iFilterSp_1_1->getAvSharedHandle([&](Result r, hidl_handle avMemory, uint64_t avMemSize) {
-            if (r == Result::SUCCESS) {
-                filterSp->mAvSharedHandle = native_handle_clone(avMemory.getNativeHandle());
-                filterSp->mAvSharedMemSize = avMemSize;
-            }
-        });
-    }
+    filterClient->incStrong(filterObj);
+    env->SetLongField(filterObj, gFields.filterContext, (jlong)filterClient.get());
+    callback->setFilter(env->NewWeakGlobalRef(filterObj), filterClient);
 
     return filterObj;
 }
@@ -2616,6 +2588,15 @@
     if (r == Result::SUCCESS) {
         mFe = NULL;
         mFe_1_1 = NULL;
+    } else {
+        return (jint) r;
+    }
+
+    if (mFeClient != NULL) {
+        r = mFeClient->close();
+    }
+    if (r == Result::SUCCESS) {
+        mFeClient = NULL;
     }
     return (jint) r;
 }
@@ -2627,10 +2608,18 @@
     }
     if (r == Result::SUCCESS) {
         mDemux = NULL;
+    } else {
+        return (jint) r;
+    }
+
+    if (mDemuxClient != NULL) {
+        r = mDemuxClient->close();
+    }
+    if (r == Result::SUCCESS) {
+        mDemuxClient = NULL;
     }
     return (jint) r;
 }
-
 }  // namespace android
 
 ////////////////////////////////////////////////////////////////////////////////
@@ -3271,8 +3260,8 @@
     return settingsExt1_1;
 }
 
-static sp<Filter> getFilter(JNIEnv *env, jobject filter) {
-    return (Filter *)env->GetLongField(filter, gFields.filterContext);
+static sp<FilterClient> getFilterClient(JNIEnv *env, jobject filter) {
+    return (FilterClient *)env->GetLongField(filter, gFields.filterContext);
 }
 
 static DvrSettings getDvrSettings(JNIEnv *env, jobject settings, bool isRecorder) {
@@ -3383,7 +3372,7 @@
 
 static void android_media_tv_Tuner_native_setup(JNIEnv *env, jobject thiz) {
     sp<JTuner> tuner = new JTuner(env, thiz);
-    setTuner(env,thiz, tuner);
+    setTuner(env, thiz, tuner);
 }
 
 static jint android_media_tv_Tuner_native_get_tuner_version(JNIEnv *env, jobject thiz) {
@@ -3399,8 +3388,7 @@
 static jobject android_media_tv_Tuner_open_frontend_by_handle(
         JNIEnv *env, jobject thiz, jint handle) {
     sp<JTuner> tuner = getTuner(env, thiz);
-    uint32_t id = getResourceIdFromHandle(handle);
-    return tuner->openFrontendById(id);
+    return tuner->openFrontendByHandle(handle);
 }
 
 static int android_media_tv_Tuner_tune(JNIEnv *env, jobject thiz, jint type, jobject settings) {
@@ -3446,13 +3434,13 @@
 
 static jobject android_media_tv_Tuner_get_av_sync_hw_id(
         JNIEnv *env, jobject thiz, jobject filter) {
-    sp<Filter> filterSp = getFilter(env, filter);
-    if (filterSp == NULL) {
-        ALOGD("Failed to get sync ID. Filter not found");
+    sp<FilterClient> filterClient = getFilterClient(env, filter);
+    if (filterClient == NULL) {
+        ALOGD("Failed to get sync ID. Filter client not found");
         return NULL;
     }
     sp<JTuner> tuner = getTuner(env, thiz);
-    return tuner->getAvSyncHwId(filterSp);
+    return tuner->getAvSyncHwId(filterClient);
 }
 
 static jobject android_media_tv_Tuner_get_av_sync_time(JNIEnv *env, jobject thiz, jint id) {
@@ -3913,26 +3901,13 @@
 }
 
 static Result configureIpFilterContextId(
-        JNIEnv *env, sp<IFilter> iFilterSp, jobject ipFilterConfigObj) {
+        JNIEnv *env, sp<FilterClient> filterClient, jobject ipFilterConfigObj) {
     jclass clazz = env->FindClass(
             "android/media/tv/tuner/filter/IpFilterConfiguration");
     uint32_t cid = env->GetIntField(ipFilterConfigObj, env->GetFieldID(
             clazz, "mIpFilterContextId", "I"));
-    Result res = Result::SUCCESS;
-    if (cid != static_cast<uint32_t>(Constant::INVALID_IP_FILTER_CONTEXT_ID)) {
-        sp<::android::hardware::tv::tuner::V1_1::IFilter> iFilterSp_1_1;
-        iFilterSp_1_1 = ::android::hardware::tv::tuner::V1_1::IFilter::castFrom(iFilterSp);
 
-        if (iFilterSp_1_1 != NULL) {
-            res = iFilterSp_1_1->configureIpCid(cid);
-            if (res != Result::SUCCESS) {
-                return res;
-            }
-        } else {
-            ALOGW("configureIpCid is not supported with the current HAL implementation.");
-        }
-    }
-    return res;
+    return filterClient->configureIpFilterContextId(cid);
 }
 
 static jint copyData(JNIEnv *env, std::unique_ptr<MQ>& mq, EventFlag* flag, jbyteArray buffer,
@@ -3975,21 +3950,20 @@
 static jint android_media_tv_Tuner_configure_filter(
         JNIEnv *env, jobject filter, int type, int subtype, jobject settings) {
     ALOGD("configure filter type=%d, subtype=%d", type, subtype);
-    sp<Filter> filterSp = getFilter(env, filter);
-    sp<IFilter> iFilterSp = filterSp->getIFilter();
-    if (iFilterSp == NULL) {
+    sp<FilterClient> filterClient = getFilterClient(env, filter);
+    if (filterClient == NULL) {
         ALOGD("Failed to configure filter: filter not found");
         return (jint) Result::NOT_INITIALIZED;
     }
     DemuxFilterSettings filterSettings = getFilterConfiguration(env, type, subtype, settings);
-    Result res = iFilterSp->configure(filterSettings);
+    Result res = filterClient->configure(filterSettings);
 
     if (res != Result::SUCCESS) {
         return (jint) res;
     }
 
     if (static_cast<DemuxFilterMainType>(type) == DemuxFilterMainType::IP) {
-        res = configureIpFilterContextId(env, iFilterSp, settings);
+        res = configureIpFilterContextId(env, filterClient, settings);
         if (res != Result::SUCCESS) {
             return (jint) res;
         }
@@ -3997,49 +3971,19 @@
 
     AvStreamType streamType;
     if (isAvFilterSettings(filterSettings) && getAvStreamType(env, settings, streamType)) {
-        sp<::android::hardware::tv::tuner::V1_1::IFilter> iFilterSp_1_1;
-        iFilterSp_1_1 = ::android::hardware::tv::tuner::V1_1::IFilter::castFrom(iFilterSp);
-        if (iFilterSp_1_1 != NULL) {
-            res = iFilterSp_1_1->configureAvStreamType(streamType);
-        } else {
-            ALOGW("configureAvStreamType is not supported with the current HAL implementation.");
-        }
-        if (res != Result::SUCCESS) {
-            return (jint) res;
-        }
+        res = filterClient->configureAvStreamType(streamType);
     }
-
-    MQDescriptorSync<uint8_t> filterMQDesc;
-    Result getQueueDescResult = Result::UNKNOWN_ERROR;
-    if (filterSp->mFilterMQ == NULL) {
-        iFilterSp->getQueueDesc(
-                [&](Result r, const MQDescriptorSync<uint8_t>& desc) {
-                    filterMQDesc = desc;
-                    getQueueDescResult = r;
-                    ALOGD("getFilterQueueDesc");
-                });
-        if (getQueueDescResult == Result::SUCCESS) {
-            filterSp->mFilterMQ = std::make_unique<MQ>(filterMQDesc, true);
-            EventFlag::createEventFlag(
-                    filterSp->mFilterMQ->getEventFlagWord(), &(filterSp->mFilterMQEventFlag));
-        }
-    }
-    return (jint) getQueueDescResult;
+    return (jint) res;
 }
 
 static jint android_media_tv_Tuner_get_filter_id(JNIEnv* env, jobject filter) {
-    sp<IFilter> iFilterSp = getFilter(env, filter)->getIFilter();
-    if (iFilterSp == NULL) {
-        ALOGD("Failed to get filter ID: filter not found");
+    sp<FilterClient> filterClient = getFilterClient(env, filter);
+    if (filterClient == NULL) {
+        ALOGD("Failed to get filter ID: filter client not found");
         return (int) Result::NOT_INITIALIZED;
     }
-    Result res;
     uint32_t id;
-    iFilterSp->getId(
-            [&](Result r, uint32_t filterId) {
-                res = r;
-                id = filterId;
-            });
+    Result res = filterClient->getId(id);
     if (res != Result::SUCCESS) {
         return (jint) Constant::INVALID_FILTER_ID;
     }
@@ -4047,30 +3991,13 @@
 }
 
 static jlong android_media_tv_Tuner_get_filter_64bit_id(JNIEnv* env, jobject filter) {
-    sp<IFilter> iFilterSp = getFilter(env, filter)->getIFilter();
-    if (iFilterSp == NULL) {
-        ALOGD("Failed to get filter ID: filter not found");
-        return static_cast<jlong>(
-                ::android::hardware::tv::tuner::V1_1::Constant64Bit::INVALID_FILTER_ID_64BIT);
+    sp<FilterClient> filterClient = getFilterClient(env, filter);
+    if (filterClient == NULL) {
+        ALOGD("Failed to get filter ID 64 bit: filter client not found");
+        return (int) Result::NOT_INITIALIZED;
     }
-
-    sp<::android::hardware::tv::tuner::V1_1::IFilter> iFilterSp_1_1;
-    iFilterSp_1_1 = ::android::hardware::tv::tuner::V1_1::IFilter::castFrom(iFilterSp);
-    Result res;
     uint64_t id;
-
-    if (iFilterSp_1_1 != NULL) {
-        iFilterSp_1_1->getId64Bit(
-            [&](Result r, uint64_t filterId64Bit) {
-                res = r;
-                id = filterId64Bit;
-        });
-    } else {
-        ALOGW("getId64Bit is not supported with the current HAL implementation.");
-        return static_cast<jlong>(
-                ::android::hardware::tv::tuner::V1_1::Constant64Bit::INVALID_FILTER_ID_64BIT);
-    }
-
+    Result res = filterClient->getId64Bit(id);
     return (res == Result::SUCCESS) ?
             static_cast<jlong>(id) : static_cast<jlong>(
                     ::android::hardware::tv::tuner::V1_1::Constant64Bit::INVALID_FILTER_ID_64BIT);
@@ -4078,96 +4005,96 @@
 
 static jint android_media_tv_Tuner_configure_monitor_event(
         JNIEnv* env, jobject filter, int monitorEventType) {
-    sp<IFilter> iFilterSp = getFilter(env, filter)->getIFilter();
-    if (iFilterSp == NULL) {
-        ALOGD("Failed to configure scrambling event: filter not found");
-        return (jint) Result::NOT_INITIALIZED;
+    sp<FilterClient> filterClient = getFilterClient(env, filter);
+    if (filterClient == NULL) {
+        ALOGD("Failed to configure scrambling event: filter client not found");
+        return (int) Result::NOT_INITIALIZED;
     }
-
-    sp<::android::hardware::tv::tuner::V1_1::IFilter> iFilterSp_1_1;
-    iFilterSp_1_1 = ::android::hardware::tv::tuner::V1_1::IFilter::castFrom(iFilterSp);
-    Result res;
-
-    if (iFilterSp_1_1 != NULL) {
-        res = iFilterSp_1_1->configureMonitorEvent(monitorEventType);
-    } else {
-        ALOGW("configureScramblingEvent is not supported with the current HAL implementation.");
-        return (jint) Result::INVALID_STATE;
-    }
-
+    Result res = filterClient->configureMonitorEvent(monitorEventType);
     return (jint) res;
 }
 
 static jint android_media_tv_Tuner_set_filter_data_source(
         JNIEnv* env, jobject filter, jobject srcFilter) {
-    sp<IFilter> iFilterSp = getFilter(env, filter)->getIFilter();
-    if (iFilterSp == NULL) {
-        ALOGD("Failed to set filter data source: filter not found");
-        return (jint) Result::NOT_INITIALIZED;
+    sp<FilterClient> filterClient = getFilterClient(env, filter);
+    if (filterClient == NULL) {
+        ALOGD("Failed to set filter data source: filter client not found");
+        return (int) Result::NOT_INITIALIZED;
     }
-    Result r;
+    Result res;
     if (srcFilter == NULL) {
-        r = iFilterSp->setDataSource(NULL);
+        res = filterClient->setDataSource(NULL);
     } else {
-        sp<IFilter> srcSp = getFilter(env, srcFilter)->getIFilter();
-        if (iFilterSp == NULL) {
+        sp<FilterClient> srcClient = getFilterClient(env, srcFilter);
+        if (srcClient == NULL) {
             ALOGD("Failed to set filter data source: src filter not found");
             return (jint) Result::INVALID_ARGUMENT;
         }
-        r = iFilterSp->setDataSource(srcSp);
+        res = filterClient->setDataSource(srcClient);
     }
-    return (jint) r;
+    return (jint) res;
 }
 
 static jint android_media_tv_Tuner_start_filter(JNIEnv *env, jobject filter) {
-    sp<IFilter> iFilterSp = getFilter(env, filter)->getIFilter();
-    if (iFilterSp == NULL) {
-        ALOGD("Failed to start filter: filter not found");
-        return (jint) Result::NOT_INITIALIZED;
+    sp<FilterClient> filterClient = getFilterClient(env, filter);
+    if (filterClient == NULL) {
+        ALOGD("Failed to start filter: filter client not found");
+        return (int) Result::NOT_INITIALIZED;
     }
-    Result r = iFilterSp->start();
-    return (jint) r;
+    return (jint) filterClient->start();
 }
 
 static jint android_media_tv_Tuner_stop_filter(JNIEnv *env, jobject filter) {
-    sp<IFilter> iFilterSp = getFilter(env, filter)->getIFilter();
-    if (iFilterSp == NULL) {
-        ALOGD("Failed to stop filter: filter not found");
-        return (jint) Result::NOT_INITIALIZED;
+    sp<FilterClient> filterClient = getFilterClient(env, filter);
+    if (filterClient == NULL) {
+        ALOGD("Failed to stop filter: filter client not found");
+        return (int) Result::NOT_INITIALIZED;
     }
-    Result r = iFilterSp->stop();
-    return (jint) r;
+    return (jint) filterClient->stop();
 }
 
 static jint android_media_tv_Tuner_flush_filter(JNIEnv *env, jobject filter) {
-    sp<IFilter> iFilterSp = getFilter(env, filter)->getIFilter();
-    if (iFilterSp == NULL) {
-        ALOGD("Failed to flush filter: filter not found");
-        return (jint) Result::NOT_INITIALIZED;
+    sp<FilterClient> filterClient = getFilterClient(env, filter);
+    if (filterClient == NULL) {
+        ALOGD("Failed to flush filter: filter client not found");
+        return (int) Result::NOT_INITIALIZED;
     }
-    Result r = iFilterSp->flush();
-    return (jint) r;
+    return (jint) filterClient->flush();
 }
 
 static jint android_media_tv_Tuner_read_filter_fmq(
         JNIEnv *env, jobject filter, jbyteArray buffer, jlong offset, jlong size) {
-    sp<Filter> filterSp = getFilter(env, filter);
-    if (filterSp == NULL) {
+    sp<FilterClient> filterClient = getFilterClient(env, filter);
+    if (filterClient == NULL) {
         jniThrowException(env, "java/lang/IllegalStateException",
-                "Failed to read filter FMQ: filter not found");
+                "Failed to read filter FMQ: filter client not found");
         return 0;
     }
-    return copyData(env, filterSp->mFilterMQ, filterSp->mFilterMQEventFlag, buffer, offset, size);
+
+    jboolean isCopy;
+    jbyte *dst = env->GetByteArrayElements(buffer, &isCopy);
+    ALOGD("copyData, isCopy=%d", isCopy);
+    if (dst == nullptr) {
+        jniThrowRuntimeException(env, "Failed to GetByteArrayElements");
+        return 0;
+    }
+    int realReadSize = filterClient->read(reinterpret_cast<uint8_t*>(dst) + offset, size);
+    env->ReleaseByteArrayElements(buffer, dst, 0);
+    if (realReadSize < 0) {
+        return (jint) Result::UNKNOWN_ERROR;
+    }
+    return (jint) Result::SUCCESS;
 }
 
 static jint android_media_tv_Tuner_close_filter(JNIEnv *env, jobject filter) {
-    sp<IFilter> iFilterSp = getFilter(env, filter)->getIFilter();
-    if (iFilterSp == NULL) {
-        ALOGD("Failed to close filter: filter not found");
-        return (jint) Result::NOT_INITIALIZED;
+    sp<FilterClient> filterClient = getFilterClient(env, filter);
+    if (filterClient == NULL) {
+        jniThrowException(env, "java/lang/IllegalStateException",
+                "Failed to close filter: filter client not found");
+        return 0;
     }
-    Result r = iFilterSp->close();
-    return (jint) r;
+
+    return (jint) filterClient->close();
 }
 
 static sp<TimeFilter> getTimeFilter(JNIEnv *env, jobject filter) {
@@ -4275,7 +4202,8 @@
     if (descramblerSp == NULL) {
         return (jint) Result::NOT_INITIALIZED;
     }
-    sp<IFilter> iFilterSp = getFilter(env, filter)->getIFilter();
+    // TODO: use filter client once descramblerClient is ready
+    sp<IFilter> iFilterSp = getFilterClient(env, filter)->getHalFilter();
     Result result = descramblerSp->addPid(getDemuxPid((int)pidType, (int)pid), iFilterSp);
     return (jint) result;
 }
@@ -4286,7 +4214,8 @@
     if (descramblerSp == NULL) {
         return (jint) Result::NOT_INITIALIZED;
     }
-    sp<IFilter> iFilterSp = getFilter(env, filter)->getIFilter();
+    // TODO: use filter client once descramblerClient is ready
+    sp<IFilter> iFilterSp = getFilterClient(env, filter)->getHalFilter();
     Result result = descramblerSp->removePid(getDemuxPid((int)pidType, (int)pid), iFilterSp);
     return (jint) result;
 }
@@ -4358,12 +4287,13 @@
     if (dvrSp == NULL) {
         return (jint) Result::NOT_INITIALIZED;
     }
-    sp<Filter> filterSp = getFilter(env, filter);
-    if (filterSp == NULL) {
+    sp<FilterClient> filterClient = getFilterClient(env, filter);
+    if (filterClient == NULL) {
         return (jint) Result::INVALID_ARGUMENT;
     }
     sp<IDvr> iDvrSp = dvrSp->getIDvr();
-    sp<IFilter> iFilterSp = filterSp->getIFilter();
+    // TODO: use filter client once dvrClient is ready
+    sp<IFilter> iFilterSp = filterClient->getHalFilter();
     Result result = iDvrSp->attachFilter(iFilterSp);
     return (jint) result;
 }
@@ -4373,12 +4303,13 @@
     if (dvrSp == NULL) {
         return (jint) Result::NOT_INITIALIZED;
     }
-    sp<Filter> filterSp = getFilter(env, filter);
-    if (filterSp == NULL) {
+    sp<FilterClient> filterClient = getFilterClient(env, filter);
+    if (filterClient == NULL) {
         return (jint) Result::INVALID_ARGUMENT;
     }
     sp<IDvr> iDvrSp = dvrSp->getIDvr();
-    sp<IFilter> iFilterSp = filterSp->getIFilter();
+    // TODO: use filter client once dvrClient is ready
+    sp<IFilter> iFilterSp = filterClient->getHalFilter();
     Result result = iDvrSp->detachFilter(iFilterSp);
     return (jint) result;
 }
diff --git a/media/jni/android_media_tv_Tuner.h b/media/jni/android_media_tv_Tuner.h
index bec834c..4149228 100644
--- a/media/jni/android_media_tv_Tuner.h
+++ b/media/jni/android_media_tv_Tuner.h
@@ -34,6 +34,11 @@
 #include <utils/Mutex.h>
 #include <utils/RefBase.h>
 
+#include "tuner/DemuxClient.h"
+#include "tuner/FilterClient.h"
+#include "tuner/FilterClientCallback.h"
+#include "tuner/FrontendClient.h"
+#include "tuner/FrontendClientCallback.h"
 #include "tuner/TunerClient.h"
 #include "jni.h"
 
@@ -95,6 +100,7 @@
     Lnb(sp<ILnb> sp, jobject obj);
     ~Lnb();
     sp<ILnb> getILnb();
+    // TODO: remove after migrate to client lib
     sp<ILnb> mLnbSp;
     jweak mLnbObj;
 };
@@ -115,6 +121,7 @@
     jint close();
     MQ& getDvrMQ();
     sp<IDvr> getIDvr();
+    // TODO: remove after migrate to client lib
     sp<IDvr> mDvrSp;
     jweak mDvrObj;
     std::unique_ptr<MQ> mDvrMQ;
@@ -123,29 +130,15 @@
     int mFd;
 };
 
-struct Filter : public RefBase {
-    Filter(sp<IFilter> sp, jobject obj);
-    ~Filter();
-    int close();
-    sp<IFilter> getIFilter();
-    sp<IFilter> mFilterSp;
-    std::unique_ptr<MQ> mFilterMQ;
-    EventFlag* mFilterMQEventFlag;
-    jweak mFilterObj;
-    native_handle_t* mAvSharedHandle;
-    uint64_t mAvSharedMemSize;
-    bool mIsMediaFilter;
-};
-
 struct MediaEvent : public RefBase {
-    MediaEvent(sp<Filter> filter, hidl_handle avHandle, uint64_t dataId,
+    MediaEvent(sp<FilterClient> filterClient, hidl_handle avHandle, uint64_t dataId,
         uint64_t dataSize, jobject obj);
     ~MediaEvent();
     jobject getLinearBlock();
     uint64_t getAudioHandle();
     void finalize();
 
-    sp<Filter> mFilter;
+    sp<FilterClient> mFilterClient;
     native_handle_t* mAvHandle;
     uint64_t mDataId;
     uint64_t mDataSize;
@@ -159,16 +152,16 @@
     std::weak_ptr<C2Buffer> mC2Buffer;
 };
 
-struct FilterCallback : public IFilterCallback {
-    ~FilterCallback();
-    virtual Return<void> onFilterEvent_1_1(const DemuxFilterEvent& filterEvent,
+struct FilterClientCallbackImpl : public FilterClientCallback {
+    virtual void onFilterEvent_1_1(const DemuxFilterEvent& filterEvent,
             const DemuxFilterEventExt& filterEventExt);
-    virtual Return<void> onFilterEvent(const DemuxFilterEvent& filterEvent);
-    virtual Return<void> onFilterStatus(const DemuxFilterStatus status);
+    virtual void onFilterEvent(const DemuxFilterEvent& filterEvent);
+    virtual void onFilterStatus(const DemuxFilterStatus status);
 
-    void setFilter(const sp<Filter> filter);
+    void setFilter(jweak filterObj, sp<FilterClient> filterClient);
 private:
-    sp<Filter> mFilter;
+    jweak mFilterObj;
+    sp<FilterClient> mFilterClient;
     jobjectArray getSectionEvent(
             jobjectArray& arr, const std::vector<DemuxFilterEvent::Event>& events);
     jobjectArray getMediaEvent(
@@ -195,13 +188,13 @@
             jobjectArray& arr, const std::vector<DemuxFilterEventExt::Event>& eventsExt);
 };
 
-struct FrontendCallback : public IFrontendCallback {
-    FrontendCallback(jweak tunerObj, FrontendId id);
+struct FrontendClientCallbackImpl : public FrontendClientCallback {
+    FrontendClientCallbackImpl(jweak tunerObj, FrontendId id);
 
-    virtual Return<void> onEvent(FrontendEventType frontendEventType);
-    virtual Return<void> onScanMessage(
+    virtual void onEvent(FrontendEventType frontendEventType);
+    virtual void onScanMessage(
             FrontendScanMessageType type, const FrontendScanMessage& message);
-    virtual Return<void> onScanMessageExt1_1(
+    virtual void onScanMessageExt1_1(
             FrontendScanMessageTypeExt1_1 type, const FrontendScanMessageExt1_1& messageExt);
 
     jweak mObject;
@@ -212,22 +205,24 @@
     TimeFilter(sp<ITimeFilter> sp, jweak obj);
     ~TimeFilter();
     sp<ITimeFilter> getITimeFilter();
+    // TODO: remove after migrate to client lib
     sp<ITimeFilter> mTimeFilterSp;
     jweak mTimeFilterObj;
 };
 
 struct JTuner : public RefBase {
     JTuner(JNIEnv *env, jobject thiz);
+    // TODO: modify after migrate to client lib
     sp<ITuner> getTunerService();
     int getTunerVersion();
-    jobject getAvSyncHwId(sp<Filter> filter);
+    jobject getAvSyncHwId(sp<FilterClient> filter);
     jobject getAvSyncTime(jint id);
     int connectCiCam(jint id);
     int linkCiCam(jint id);
     int disconnectCiCam();
     int unlinkCiCam(jint id);
     jobject getFrontendIds();
-    jobject openFrontendById(int id);
+    jobject openFrontendByHandle(int feHandle);
     jint closeFrontendById(int id);
     jobject getFrontendInfo(int id);
     int tune(const FrontendSettings& settings, const FrontendSettingsExt1_1& settingsExt1_1);
@@ -257,15 +252,22 @@
 private:
     jclass mClass;
     jweak mObject;
+    // TODO: remove after migrate to client lib
     static sp<ITuner> mTuner;
     static sp<::android::hardware::tv::tuner::V1_1::ITuner> mTuner_1_1;
     static sp<TunerClient> mTunerClient;
+    // TODO: remove after migrate to client lib
     sp<IFrontend> mFe;
+    // TODO: remove after migrate to client lib
     sp<::android::hardware::tv::tuner::V1_1::IFrontend> mFe_1_1;
+    sp<FrontendClient> mFeClient;
     int mFeId;
     hidl_vec<LnbId> mLnbIds;
+    // TODO: remove after migrate to client lib
     sp<ILnb> mLnb;
+    // TODO: remove after migrate to client lib
     sp<IDemux> mDemux;
+    sp<DemuxClient> mDemuxClient;
     uint32_t mDemuxId;
     static jobject getAnalogFrontendCaps(JNIEnv *env, FrontendInfo::FrontendCapabilities& caps);
     static jobject getAtsc3FrontendCaps(JNIEnv *env, FrontendInfo::FrontendCapabilities& caps);
@@ -279,6 +281,9 @@
     static jobject getDtmbFrontendCaps(JNIEnv *env, int id);
 
     bool isV1_1ExtendedStatusType(jint type);
+    static uint32_t getResourceIdFromHandle(jint handle) {
+        return (handle & 0x00ff0000) >> 16;
+    }
 };
 
 class C2DataIdInfo : public C2Param {
diff --git a/media/jni/tuner/DemuxClient.cpp b/media/jni/tuner/DemuxClient.cpp
index 11acb5e..b237a24 100644
--- a/media/jni/tuner/DemuxClient.cpp
+++ b/media/jni/tuner/DemuxClient.cpp
@@ -68,14 +68,12 @@
         sp<HidlFilterCallback> callback = new HidlFilterCallback(cb);
         sp<IFilter> hidlFilter = openHidlFilter(type, bufferSize, callback);
         if (hidlFilter != NULL) {
-            sp<FilterClient> filterClient = new FilterClient();
+            sp<FilterClient> filterClient = new FilterClient(type);
             filterClient->setHidlFilter(hidlFilter);
             return filterClient;
         }
     }
 
-    // TODO: handle share av memory handle
-
     return NULL;
 }
 
@@ -141,7 +139,7 @@
 }
 
 Result DemuxClient::close() {
-    // pending aidl interface
+    // TODO: pending aidl interface
 
     if (mDemux != NULL) {
         Result res = mDemux->close();
diff --git a/media/jni/tuner/FilterClient.cpp b/media/jni/tuner/FilterClient.cpp
index a71cae60..0aab5fe 100644
--- a/media/jni/tuner/FilterClient.cpp
+++ b/media/jni/tuner/FilterClient.cpp
@@ -22,6 +22,9 @@
 #include "FilterClient.h"
 
 using ::android::hardware::tv::tuner::V1_0::DemuxQueueNotifyBits;
+using ::android::hardware::tv::tuner::V1_0::DemuxFilterMainType;
+using ::android::hardware::tv::tuner::V1_0::DemuxMmtpFilterType;
+using ::android::hardware::tv::tuner::V1_0::DemuxTsFilterType;
 
 namespace android {
 
@@ -29,20 +32,25 @@
 
 // TODO: pending aidl interface
 // TODO: add filter callback
-FilterClient::FilterClient() {
+FilterClient::FilterClient(DemuxFilterType type) {
     //mTunerFilter = tunerFilter;
+    mAvSharedHandle = NULL;
+    checkIsMediaFilter(type);
 }
 
 FilterClient::~FilterClient() {
     //mTunerFilter = NULL;
     mFilter = NULL;
     mFilter_1_1 = NULL;
+    mAvSharedHandle = NULL;
+    mAvSharedMemSize = 0;
 }
 
 // TODO: remove after migration to Tuner Service is done.
 void FilterClient::setHidlFilter(sp<IFilter> filter) {
     mFilter = filter;
     mFilter_1_1 = ::android::hardware::tv::tuner::V1_1::IFilter::castFrom(mFilter);
+    handleAvShareMemory();
 }
 
 int FilterClient::read(uint8_t* buffer, int size) {
@@ -59,6 +67,22 @@
     return -1;
 }
 
+SharedHandleInfo FilterClient::getAvSharedHandleInfo() {
+    SharedHandleInfo info{
+        .sharedHandle = NULL,
+        .size = 0,
+    };
+
+    // TODO: pending aidl interface
+
+    if (mFilter_1_1 != NULL) {
+        info.sharedHandle = mAvSharedHandle;
+        info.size = mAvSharedMemSize;
+    }
+
+    return info;
+}
+
 Result FilterClient::configure(DemuxFilterSettings configure) {
     // TODO: pending aidl interface
 
@@ -187,7 +211,11 @@
     // TODO: pending aidl interface
 
     if (mFilter != NULL) {
-        return mFilter->close();
+        Result res = mFilter->close();
+        if (res == Result::SUCCESS) {
+            mFilter = NULL;
+        }
+        return res;
     }
 
     return Result::INVALID_STATE;
@@ -261,4 +289,31 @@
 
     return size;
 }
+
+void FilterClient::checkIsMediaFilter(DemuxFilterType type) {
+    if (type.mainType == DemuxFilterMainType::MMTP) {
+        if (type.subType.mmtpFilterType() == DemuxMmtpFilterType::AUDIO ||
+                type.subType.mmtpFilterType() == DemuxMmtpFilterType::VIDEO) {
+            mIsMediaFilter = true;
+        }
+    }
+
+    if (type.mainType == DemuxFilterMainType::TS) {
+        if (type.subType.tsFilterType() == DemuxTsFilterType::AUDIO ||
+                type.subType.tsFilterType() == DemuxTsFilterType::VIDEO) {
+            mIsMediaFilter = true;
+        }
+    }
+}
+
+void FilterClient::handleAvShareMemory() {
+    if (mFilter_1_1 != NULL && mIsMediaFilter) {
+        mFilter_1_1->getAvSharedHandle([&](Result r, hidl_handle avMemory, uint64_t avMemSize) {
+            if (r == Result::SUCCESS) {
+                mAvSharedHandle = native_handle_clone(avMemory.getNativeHandle());
+                mAvSharedMemSize = avMemSize;
+            }
+        });
+    }
+}
 }  // namespace android
diff --git a/media/jni/tuner/FilterClient.h b/media/jni/tuner/FilterClient.h
index 4af74b0..976b2f5 100644
--- a/media/jni/tuner/FilterClient.h
+++ b/media/jni/tuner/FilterClient.h
@@ -34,6 +34,7 @@
 using ::android::hardware::Void;
 using ::android::hardware::hidl_handle;
 using ::android::hardware::tv::tuner::V1_0::DemuxFilterSettings;
+using ::android::hardware::tv::tuner::V1_0::DemuxFilterType;
 using ::android::hardware::tv::tuner::V1_0::IFilter;
 using ::android::hardware::tv::tuner::V1_0::Result;
 using ::android::hardware::tv::tuner::V1_1::AvStreamType;
@@ -45,6 +46,11 @@
 
 namespace android {
 
+struct SharedHandleInfo {
+    native_handle_t* sharedHandle;
+    uint64_t size;
+};
+
 // TODO: pending aidl interface
 /*class TunerFilterCallback : public BnTunerFilterCallback {
 
@@ -75,7 +81,7 @@
 
 public:
     // TODO: pending aidl interface
-    FilterClient();
+    FilterClient(DemuxFilterType type);
     ~FilterClient();
 
     // TODO: remove after migration to Tuner Service is done.
@@ -89,6 +95,11 @@
     int read(uint8_t* buffer, int size);
 
     /**
+     * Get the a/v shared memory handle information
+     */
+    SharedHandleInfo getAvSharedHandleInfo();
+
+    /**
      * Configure the filter.
      */
     Result configure(DemuxFilterSettings configure);
@@ -161,6 +172,8 @@
 private:
     Result getFilterMq();
     int copyData(uint8_t* buffer, int size);
+    void checkIsMediaFilter(DemuxFilterType type);
+    void handleAvShareMemory();
 
     /**
      * An AIDL Tuner Filter Singleton assigned at the first time when the Tuner Client
@@ -189,6 +202,10 @@
     sp<FilterClientCallback> mCallback;
     //shared_ptr<TunerFilterCallback> mAidlCallback;
     sp<HidlFilterCallback> mHidlCallback;
+
+    native_handle_t* mAvSharedHandle;
+    uint64_t mAvSharedMemSize;
+    bool mIsMediaFilter;
 };
 }  // namespace android
 
diff --git a/native/android/Android.bp b/native/android/Android.bp
index 6db4da9..3daaf05 100644
--- a/native/android/Android.bp
+++ b/native/android/Android.bp
@@ -103,7 +103,7 @@
     version_script: "libandroid.map.txt",
     stubs: {
         symbol_file: "libandroid.map.txt",
-        versions: ["29"],
+        versions: ["29", "31"],
     },
 }
 
diff --git a/native/android/OWNERS b/native/android/OWNERS
index 266764a..ac5a895 100644
--- a/native/android/OWNERS
+++ b/native/android/OWNERS
@@ -1,4 +1,3 @@
-set noparent
-
+per-file libandroid_net.map.txt, net.c = set noparent
 per-file libandroid_net.map.txt, net.c = codewiz@google.com, jchalard@google.com, junyulai@google.com
 per-file libandroid_net.map.txt, net.c = lorenzo@google.com, reminv@google.com, satk@google.com
diff --git a/packages/SettingsLib/res/values-af/strings.xml b/packages/SettingsLib/res/values-af/strings.xml
index 438e8b8..c2b26bc 100644
--- a/packages/SettingsLib/res/values-af/strings.xml
+++ b/packages/SettingsLib/res/values-af/strings.xml
@@ -403,7 +403,6 @@
     <string name="transcode_user_control" msgid="6176368544817731314">"Ignoreer kodewisselingverstekke"</string>
     <string name="transcode_enable_all" msgid="2411165920039166710">"Aktiveer kodewisseling"</string>
     <string name="transcode_default" msgid="3784803084573509491">"Aanvaar dat programme moderne formate steun"</string>
-    <string name="transcode_skip_apps" msgid="8249721984597390142">"Aktiveer kodewisseling vir programme"</string>
     <string name="runningservices_settings_title" msgid="6460099290493086515">"Lopende dienste"</string>
     <string name="runningservices_settings_summary" msgid="1046080643262665743">"Sien en beheer dienste wat tans aktief is"</string>
     <string name="select_webview_provider_title" msgid="3917815648099445503">"WebView-implementering"</string>
@@ -566,4 +565,29 @@
     <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Bedraade oorfoon"</string>
     <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Aan"</string>
     <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Af"</string>
+    <string name="carrier_network_change_mode" msgid="4257621815706644026">"Diensverskaffernetwerk verander tans"</string>
+    <string name="data_connection_3g" msgid="931852552688157407">"3G"</string>
+    <string name="data_connection_edge" msgid="4625509456544797637">"EDGE"</string>
+    <string name="data_connection_cdma" msgid="9098161966701934334">"1X"</string>
+    <string name="data_connection_gprs" msgid="1251945769006770189">"GPRS"</string>
+    <string name="data_connection_3_5g" msgid="4298721462047921400">"H"</string>
+    <string name="data_connection_3_5g_plus" msgid="6683055858295918170">"H+"</string>
+    <string name="data_connection_4g" msgid="2581705503356752044">"4G"</string>
+    <string name="data_connection_4g_plus" msgid="5194902328408751020">"4G+"</string>
+    <string name="data_connection_lte" msgid="7675461204366364124">"LTE"</string>
+    <string name="data_connection_lte_plus" msgid="6643158654804916653">"LTE+"</string>
+    <string name="cell_data_off_content_description" msgid="2280700839891636498">"Mobiele data is af"</string>
+    <string name="not_default_data_content_description" msgid="6517068332106592887">"Nie gestel om data te gebruik nie"</string>
+    <string name="accessibility_no_phone" msgid="2687419663127582503">"Geen foon nie."</string>
+    <string name="accessibility_phone_one_bar" msgid="5719721147018970063">"Foon, een staaf."</string>
+    <string name="accessibility_phone_two_bars" msgid="2531458337458953263">"Foon, twee stawe."</string>
+    <string name="accessibility_phone_three_bars" msgid="1523967995996696619">"Foon, drie stawe."</string>
+    <string name="accessibility_phone_signal_full" msgid="4302338883816077134">"Foonsein is vol."</string>
+    <string name="accessibility_no_data" msgid="4563181886936931008">"Geen data nie."</string>
+    <string name="accessibility_data_one_bar" msgid="6892888138070752480">"Data, een staaf."</string>
+    <string name="accessibility_data_two_bars" msgid="9202641507241802499">"Data, twee stawe."</string>
+    <string name="accessibility_data_three_bars" msgid="2813876214466722413">"Data, drie stawe."</string>
+    <string name="accessibility_data_signal_full" msgid="1808301899314382337">"Datasein vol."</string>
+    <string name="accessibility_ethernet_disconnected" msgid="2832501530856497489">"Ethernet is ontkoppel."</string>
+    <string name="accessibility_ethernet_connected" msgid="2093872142317190618">"Ethernet gekoppel."</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-am/strings.xml b/packages/SettingsLib/res/values-am/strings.xml
index fd5777d..65ce6e0 100644
--- a/packages/SettingsLib/res/values-am/strings.xml
+++ b/packages/SettingsLib/res/values-am/strings.xml
@@ -403,7 +403,6 @@
     <string name="transcode_user_control" msgid="6176368544817731314">"የትራንስኮዲንግ ነባሪዎችን ሻር"</string>
     <string name="transcode_enable_all" msgid="2411165920039166710">"ትራንስኮዲንግን ያንቁ"</string>
     <string name="transcode_default" msgid="3784803084573509491">"መተግበሪያዎች ዘመናዊ ቅርጸቶችን እንደሚደግፉ አድርገው ይቁጠሩ"</string>
-    <string name="transcode_skip_apps" msgid="8249721984597390142">"ለመተግበሪያዎች ትራንስኮዲንግን ያንቁ"</string>
     <string name="runningservices_settings_title" msgid="6460099290493086515">"አሂድ አገልግሎቶች"</string>
     <string name="runningservices_settings_summary" msgid="1046080643262665743">"በአሁኑጊዜ እየሄዱ ያሉ አገልግሎቶችን ተቆጣጠር እና እይ"</string>
     <string name="select_webview_provider_title" msgid="3917815648099445503">"የWebView ትግበራ"</string>
@@ -566,4 +565,29 @@
     <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"ባለገመድ ጆሮ ማዳመጫ"</string>
     <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"አብራ"</string>
     <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"አጥፋ"</string>
+    <string name="carrier_network_change_mode" msgid="4257621815706644026">"የአገልግሎት አቅራቢ አውታረ መረብን በመቀየር ላይ"</string>
+    <string name="data_connection_3g" msgid="931852552688157407">"3ጂ"</string>
+    <string name="data_connection_edge" msgid="4625509456544797637">"ኤጅ"</string>
+    <string name="data_connection_cdma" msgid="9098161966701934334">"1X"</string>
+    <string name="data_connection_gprs" msgid="1251945769006770189">"ጂፒአርኤስ"</string>
+    <string name="data_connection_3_5g" msgid="4298721462047921400">"ሰ"</string>
+    <string name="data_connection_3_5g_plus" msgid="6683055858295918170">"ሰ+"</string>
+    <string name="data_connection_4g" msgid="2581705503356752044">"4ጂ"</string>
+    <string name="data_connection_4g_plus" msgid="5194902328408751020">"4G+"</string>
+    <string name="data_connection_lte" msgid="7675461204366364124">"LTE"</string>
+    <string name="data_connection_lte_plus" msgid="6643158654804916653">"LTE+"</string>
+    <string name="cell_data_off_content_description" msgid="2280700839891636498">"የተንቀሳቃሽ ስልክ ውሂብ ጠፍቷል"</string>
+    <string name="not_default_data_content_description" msgid="6517068332106592887">"ውሂብን ለመጠቀም አልተቀናበረም"</string>
+    <string name="accessibility_no_phone" msgid="2687419663127582503">"ምንም ስልክ የለም።"</string>
+    <string name="accessibility_phone_one_bar" msgid="5719721147018970063">"የስልክ አንድ አሞሌ"</string>
+    <string name="accessibility_phone_two_bars" msgid="2531458337458953263">"የስልክ ሁለት አሞሌ"</string>
+    <string name="accessibility_phone_three_bars" msgid="1523967995996696619">"የስልክ ሦስት አሞሌ"</string>
+    <string name="accessibility_phone_signal_full" msgid="4302338883816077134">"የስልክ አመልካች ሙሉ ነው።"</string>
+    <string name="accessibility_no_data" msgid="4563181886936931008">"ምንም ውሂብ የለም።"</string>
+    <string name="accessibility_data_one_bar" msgid="6892888138070752480">"የውሂብ አንድ አሞሌ"</string>
+    <string name="accessibility_data_two_bars" msgid="9202641507241802499">"የውሂብ ሁለት አሞሌዎች።"</string>
+    <string name="accessibility_data_three_bars" msgid="2813876214466722413">"የውሂብ ሦስት አሞሌዎች።"</string>
+    <string name="accessibility_data_signal_full" msgid="1808301899314382337">"የውሂብ አመልካች ሙሉ ነው።"</string>
+    <string name="accessibility_ethernet_disconnected" msgid="2832501530856497489">"ኤተርኔት ተነቅሏል።"</string>
+    <string name="accessibility_ethernet_connected" msgid="2093872142317190618">"ኤተርኔት ተገናኝቷል።"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-ar/strings.xml b/packages/SettingsLib/res/values-ar/strings.xml
index b81031e..3ea96c7 100644
--- a/packages/SettingsLib/res/values-ar/strings.xml
+++ b/packages/SettingsLib/res/values-ar/strings.xml
@@ -403,7 +403,6 @@
     <string name="transcode_user_control" msgid="6176368544817731314">"إلغاء الإعدادات التلقائية لتحويل الترميز"</string>
     <string name="transcode_enable_all" msgid="2411165920039166710">"تفعيل تحويل الترميز"</string>
     <string name="transcode_default" msgid="3784803084573509491">"افتراض أن التطبيق يتوافق مع التنسيقات الحديثة"</string>
-    <string name="transcode_skip_apps" msgid="8249721984597390142">"تفعيل تحويل الترميز للتطبيقات"</string>
     <string name="runningservices_settings_title" msgid="6460099290493086515">"الخدمات قيد التشغيل"</string>
     <string name="runningservices_settings_summary" msgid="1046080643262665743">"عرض الخدمات قيد التشغيل في الوقت الحالي والتحكم فيها"</string>
     <string name="select_webview_provider_title" msgid="3917815648099445503">"‏تطبيق WebView"</string>
@@ -570,4 +569,29 @@
     <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"سمّاعة سلكية"</string>
     <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"تفعيل"</string>
     <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"إيقاف"</string>
+    <string name="carrier_network_change_mode" msgid="4257621815706644026">"جارٍ تغيير شبكة مشغِّل شبكة الجوّال."</string>
+    <string name="data_connection_3g" msgid="931852552688157407">"شبكة الجيل الثالث"</string>
+    <string name="data_connection_edge" msgid="4625509456544797637">"‏شبكة EDGE"</string>
+    <string name="data_connection_cdma" msgid="9098161966701934334">"1X"</string>
+    <string name="data_connection_gprs" msgid="1251945769006770189">"‏شبكة GPRS"</string>
+    <string name="data_connection_3_5g" msgid="4298721462047921400">"H"</string>
+    <string name="data_connection_3_5g_plus" msgid="6683055858295918170">"H+‎"</string>
+    <string name="data_connection_4g" msgid="2581705503356752044">"شبكة الجيل الرابع"</string>
+    <string name="data_connection_4g_plus" msgid="5194902328408751020">"شبكة الجيل الرابع أو أحدث"</string>
+    <string name="data_connection_lte" msgid="7675461204366364124">"LTE"</string>
+    <string name="data_connection_lte_plus" msgid="6643158654804916653">"LTE+‎"</string>
+    <string name="cell_data_off_content_description" msgid="2280700839891636498">"تم إيقاف بيانات الجوال"</string>
+    <string name="not_default_data_content_description" msgid="6517068332106592887">"لم يتم الضبط على استخدام البيانات"</string>
+    <string name="accessibility_no_phone" msgid="2687419663127582503">"ليست هناك إشارة بالهاتف."</string>
+    <string name="accessibility_phone_one_bar" msgid="5719721147018970063">"إشارة الهاتف تتكون من شريط واحد."</string>
+    <string name="accessibility_phone_two_bars" msgid="2531458337458953263">"إشارة الهاتف تتكون من شريطين."</string>
+    <string name="accessibility_phone_three_bars" msgid="1523967995996696619">"إشارة الهاتف تتكون من ثلاثة أشرطة."</string>
+    <string name="accessibility_phone_signal_full" msgid="4302338883816077134">"إشارة الهاتف كاملة."</string>
+    <string name="accessibility_no_data" msgid="4563181886936931008">"لا تتوفر بيانات."</string>
+    <string name="accessibility_data_one_bar" msgid="6892888138070752480">"إشارة البيانات تتكون من شريط واحد."</string>
+    <string name="accessibility_data_two_bars" msgid="9202641507241802499">"إشارة البيانات تتكون من شريطين."</string>
+    <string name="accessibility_data_three_bars" msgid="2813876214466722413">"إشارة البيانات تتكون من ثلاثة أشرطة."</string>
+    <string name="accessibility_data_signal_full" msgid="1808301899314382337">"إشارة البيانات كاملة."</string>
+    <string name="accessibility_ethernet_disconnected" msgid="2832501530856497489">"‏تم قطع اتصال Ethernet."</string>
+    <string name="accessibility_ethernet_connected" msgid="2093872142317190618">"‏تم إنشاء اتصال Ethernet."</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-as/strings.xml b/packages/SettingsLib/res/values-as/strings.xml
index e482329..a259687 100644
--- a/packages/SettingsLib/res/values-as/strings.xml
+++ b/packages/SettingsLib/res/values-as/strings.xml
@@ -403,7 +403,6 @@
     <string name="transcode_user_control" msgid="6176368544817731314">"ট্ৰেন্সক’ডিং ডিফ’ল্ট অ’ভাৰৰাইড কৰক"</string>
     <string name="transcode_enable_all" msgid="2411165920039166710">"ট্ৰেন্সক’ডিং সক্ষম কৰক"</string>
     <string name="transcode_default" msgid="3784803084573509491">"এপে আধুনিক ফৰ্মেট সমৰ্থন কৰে বুলি ধৰি লওক"</string>
-    <string name="transcode_skip_apps" msgid="8249721984597390142">"এপৰ বাবে ট্ৰান্সক\'ডিং সক্ষম কৰক"</string>
     <string name="runningservices_settings_title" msgid="6460099290493086515">"চলিত সেৱা"</string>
     <string name="runningservices_settings_summary" msgid="1046080643262665743">"বৰ্তমান চলি থকা সেৱাসমূহ চাওক আৰু নিয়ন্ত্ৰণ কৰক"</string>
     <string name="select_webview_provider_title" msgid="3917815648099445503">"ৱেবভিউ প্ৰয়োগ"</string>
@@ -566,4 +565,29 @@
     <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"তাঁৰযুক্ত হেডফ\'ন"</string>
     <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"অন"</string>
     <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"অফ"</string>
+    <string name="carrier_network_change_mode" msgid="4257621815706644026">"বাহক নেটৱৰ্কৰ পৰিৱৰ্তন"</string>
+    <string name="data_connection_3g" msgid="931852552688157407">"3G"</string>
+    <string name="data_connection_edge" msgid="4625509456544797637">"EDGE"</string>
+    <string name="data_connection_cdma" msgid="9098161966701934334">"1X"</string>
+    <string name="data_connection_gprs" msgid="1251945769006770189">"জিপিআৰএছ"</string>
+    <string name="data_connection_3_5g" msgid="4298721462047921400">"H"</string>
+    <string name="data_connection_3_5g_plus" msgid="6683055858295918170">"H+"</string>
+    <string name="data_connection_4g" msgid="2581705503356752044">"4G"</string>
+    <string name="data_connection_4g_plus" msgid="5194902328408751020">"4G+"</string>
+    <string name="data_connection_lte" msgid="7675461204366364124">"এলটিই"</string>
+    <string name="data_connection_lte_plus" msgid="6643158654804916653">"এলটিই+"</string>
+    <string name="cell_data_off_content_description" msgid="2280700839891636498">"ম’বাইল ডেটা অফ অৱস্থাত আছে"</string>
+    <string name="not_default_data_content_description" msgid="6517068332106592887">"ডেটা ব্যৱহাৰ কৰিবলৈ ছেট কৰা নাই"</string>
+    <string name="accessibility_no_phone" msgid="2687419663127582503">"ফ\'নত ছিগনেল নাই৷"</string>
+    <string name="accessibility_phone_one_bar" msgid="5719721147018970063">"ফ\'ন ছিগনেলৰ এডাল দণ্ড।"</string>
+    <string name="accessibility_phone_two_bars" msgid="2531458337458953263">"ফ\'ন ছিগনেলৰ দুডাল দণ্ড।"</string>
+    <string name="accessibility_phone_three_bars" msgid="1523967995996696619">"ফ\'নৰ ছিগনেলৰ তিনিডাল দণ্ড আছে।"</string>
+    <string name="accessibility_phone_signal_full" msgid="4302338883816077134">"ফ\'নৰ ছিগনেল পূৰা আছে৷"</string>
+    <string name="accessibility_no_data" msgid="4563181886936931008">"কোনো ডেটা নাই।"</string>
+    <string name="accessibility_data_one_bar" msgid="6892888138070752480">"ডেটা ছিগনেলৰ এডাল দণ্ড।"</string>
+    <string name="accessibility_data_two_bars" msgid="9202641507241802499">"ডেটা ছংনেলৰ তিনিডাল দণ্ড।"</string>
+    <string name="accessibility_data_three_bars" msgid="2813876214466722413">"ডেটা ছিংগনেলত তিনিডাল দণ্ড আছে।"</string>
+    <string name="accessibility_data_signal_full" msgid="1808301899314382337">"ডেটা ছিগনেল পূৰা আছে।"</string>
+    <string name="accessibility_ethernet_disconnected" msgid="2832501530856497489">"ইথাৰনেট সংযোগ বিচ্ছিন্ন হৈছে।"</string>
+    <string name="accessibility_ethernet_connected" msgid="2093872142317190618">"ইথাৰনেট সংযোগ হৈছে।"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-az/strings.xml b/packages/SettingsLib/res/values-az/strings.xml
index 637785d..2cbd681 100644
--- a/packages/SettingsLib/res/values-az/strings.xml
+++ b/packages/SettingsLib/res/values-az/strings.xml
@@ -403,7 +403,6 @@
     <string name="transcode_user_control" msgid="6176368544817731314">"Yenidən kodlaşdırma defoltlarını əvəzləyin"</string>
     <string name="transcode_enable_all" msgid="2411165920039166710">"Yenidən kodlaşdırmanı aktiv edin"</string>
     <string name="transcode_default" msgid="3784803084573509491">"Tətbiqlərin müasir formatları dəstəklədiyini qəbul edin"</string>
-    <string name="transcode_skip_apps" msgid="8249721984597390142">"Tətbiqlər üçün yenidən kodlaşdırmanı aktiv edin"</string>
     <string name="runningservices_settings_title" msgid="6460099290493086515">"İşləyən xidmətlər"</string>
     <string name="runningservices_settings_summary" msgid="1046080643262665743">"Hazırda prosesdə olan xidmətləri görüntüləyin və onlara nəzarət edin"</string>
     <string name="select_webview_provider_title" msgid="3917815648099445503">"WebView icrası"</string>
@@ -566,4 +565,29 @@
     <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Simli qulaqlıq"</string>
     <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Aktiv"</string>
     <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Deaktiv"</string>
+    <string name="carrier_network_change_mode" msgid="4257621815706644026">"Operator şəbəkəsinin dəyişilməsi"</string>
+    <string name="data_connection_3g" msgid="931852552688157407">"3G"</string>
+    <string name="data_connection_edge" msgid="4625509456544797637">"EDGE"</string>
+    <string name="data_connection_cdma" msgid="9098161966701934334">"1X"</string>
+    <string name="data_connection_gprs" msgid="1251945769006770189">"GPRS"</string>
+    <string name="data_connection_3_5g" msgid="4298721462047921400">"H"</string>
+    <string name="data_connection_3_5g_plus" msgid="6683055858295918170">"H+"</string>
+    <string name="data_connection_4g" msgid="2581705503356752044">"4G"</string>
+    <string name="data_connection_4g_plus" msgid="5194902328408751020">"4G+"</string>
+    <string name="data_connection_lte" msgid="7675461204366364124">"LTE"</string>
+    <string name="data_connection_lte_plus" msgid="6643158654804916653">"LTE+"</string>
+    <string name="cell_data_off_content_description" msgid="2280700839891636498">"Mobil data deaktivdir"</string>
+    <string name="not_default_data_content_description" msgid="6517068332106592887">"Data istifadə etmək üçün ayarlanmayıb"</string>
+    <string name="accessibility_no_phone" msgid="2687419663127582503">"Telefon yoxdur."</string>
+    <string name="accessibility_phone_one_bar" msgid="5719721147018970063">"Şəbəkə bir xətdir."</string>
+    <string name="accessibility_phone_two_bars" msgid="2531458337458953263">"Şəbəkə iki xətdir."</string>
+    <string name="accessibility_phone_three_bars" msgid="1523967995996696619">"Şəbəkə üç xətdir."</string>
+    <string name="accessibility_phone_signal_full" msgid="4302338883816077134">"Tam şəbəkə."</string>
+    <string name="accessibility_no_data" msgid="4563181886936931008">"Məlumat yoxdur."</string>
+    <string name="accessibility_data_one_bar" msgid="6892888138070752480">"Data bir xətdir."</string>
+    <string name="accessibility_data_two_bars" msgid="9202641507241802499">"Data iki xətdir."</string>
+    <string name="accessibility_data_three_bars" msgid="2813876214466722413">"Data üç xətdir."</string>
+    <string name="accessibility_data_signal_full" msgid="1808301899314382337">"Data siqnalı tamdır."</string>
+    <string name="accessibility_ethernet_disconnected" msgid="2832501530856497489">"Ethernet bağlantısı kəsilib."</string>
+    <string name="accessibility_ethernet_connected" msgid="2093872142317190618">"Ethernet qoşuludur."</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-b+sr+Latn/strings.xml b/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
index 219d5a0..4d8e348 100644
--- a/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
+++ b/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
@@ -403,7 +403,6 @@
     <string name="transcode_user_control" msgid="6176368544817731314">"Zameni podrazumevana podešavanja transkodiranja"</string>
     <string name="transcode_enable_all" msgid="2411165920039166710">"Omogući transkodiranje"</string>
     <string name="transcode_default" msgid="3784803084573509491">"Podrazumevaj da aplikacije podržavaju moderne formate"</string>
-    <string name="transcode_skip_apps" msgid="8249721984597390142">"Omogućite transkodiranje za aplikacije"</string>
     <string name="runningservices_settings_title" msgid="6460099290493086515">"Pokrenute usluge"</string>
     <string name="runningservices_settings_summary" msgid="1046080643262665743">"Prikaz i kontrola trenutno pokrenutih usluga"</string>
     <string name="select_webview_provider_title" msgid="3917815648099445503">"Primena WebView-a"</string>
@@ -567,4 +566,29 @@
     <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Žičane slušalice"</string>
     <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Uključeno"</string>
     <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Isključeno"</string>
+    <string name="carrier_network_change_mode" msgid="4257621815706644026">"Promena mreže mobilnog operatera"</string>
+    <string name="data_connection_3g" msgid="931852552688157407">"3G"</string>
+    <string name="data_connection_edge" msgid="4625509456544797637">"EDGE"</string>
+    <string name="data_connection_cdma" msgid="9098161966701934334">"1X"</string>
+    <string name="data_connection_gprs" msgid="1251945769006770189">"GPRS"</string>
+    <string name="data_connection_3_5g" msgid="4298721462047921400">"H"</string>
+    <string name="data_connection_3_5g_plus" msgid="6683055858295918170">"H+"</string>
+    <string name="data_connection_4g" msgid="2581705503356752044">"4G"</string>
+    <string name="data_connection_4g_plus" msgid="5194902328408751020">"4G+"</string>
+    <string name="data_connection_lte" msgid="7675461204366364124">"LTE"</string>
+    <string name="data_connection_lte_plus" msgid="6643158654804916653">"LTE+"</string>
+    <string name="cell_data_off_content_description" msgid="2280700839891636498">"Mobilni podaci su isključeni"</string>
+    <string name="not_default_data_content_description" msgid="6517068332106592887">"Nije podešeno za korišćenje podataka"</string>
+    <string name="accessibility_no_phone" msgid="2687419663127582503">"Nema telefona."</string>
+    <string name="accessibility_phone_one_bar" msgid="5719721147018970063">"Signal telefona ima jednu crtu."</string>
+    <string name="accessibility_phone_two_bars" msgid="2531458337458953263">"Signal telefona od dve crte."</string>
+    <string name="accessibility_phone_three_bars" msgid="1523967995996696619">"Signal telefona od tri crte."</string>
+    <string name="accessibility_phone_signal_full" msgid="4302338883816077134">"Signal telefona je pun."</string>
+    <string name="accessibility_no_data" msgid="4563181886936931008">"Nema podataka."</string>
+    <string name="accessibility_data_one_bar" msgid="6892888138070752480">"Signal za podatke ima jednu crtu."</string>
+    <string name="accessibility_data_two_bars" msgid="9202641507241802499">"Signal za podatke od dve crte."</string>
+    <string name="accessibility_data_three_bars" msgid="2813876214466722413">"Signal za podatke od tri crte."</string>
+    <string name="accessibility_data_signal_full" msgid="1808301899314382337">"Signal za podatke je najjači."</string>
+    <string name="accessibility_ethernet_disconnected" msgid="2832501530856497489">"Veza sa eternetom je prekinuta."</string>
+    <string name="accessibility_ethernet_connected" msgid="2093872142317190618">"Eternet je povezan."</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-be/strings.xml b/packages/SettingsLib/res/values-be/strings.xml
index 4772e03..4d6f3ac 100644
--- a/packages/SettingsLib/res/values-be/strings.xml
+++ b/packages/SettingsLib/res/values-be/strings.xml
@@ -400,13 +400,9 @@
     <string name="inactive_app_active_summary" msgid="8047630990208722344">"Актыўная. Краніце, каб пераключыць."</string>
     <string name="standby_bucket_summary" msgid="5128193447550429600">"Стан праграмы ў рэжыме чакання: <xliff:g id="BUCKET"> %s</xliff:g>"</string>
     <string name="transcode_settings_title" msgid="2581975870429850549">"Налады перакадзіравання мультымедыя"</string>
-    <!-- no translation found for transcode_user_control (6176368544817731314) -->
-    <skip />
-    <!-- no translation found for transcode_enable_all (2411165920039166710) -->
-    <skip />
-    <!-- no translation found for transcode_default (3784803084573509491) -->
-    <skip />
-    <string name="transcode_skip_apps" msgid="8249721984597390142">"Уключыць перакадзіраванне для праграм"</string>
+    <string name="transcode_user_control" msgid="6176368544817731314">"Перавызначыць стандартныя налады перакадзіравання"</string>
+    <string name="transcode_enable_all" msgid="2411165920039166710">"Уключыць перакадзіраванне"</string>
+    <string name="transcode_default" msgid="3784803084573509491">"Лічыца, што праграмы падтрымліваюць сучасныя фарматы"</string>
     <string name="runningservices_settings_title" msgid="6460099290493086515">"Запушчаныя службы"</string>
     <string name="runningservices_settings_summary" msgid="1046080643262665743">"Прагляд запушчаных службаў i кіраванне iмi"</string>
     <string name="select_webview_provider_title" msgid="3917815648099445503">"Рэалізацыя WebView"</string>
@@ -571,4 +567,29 @@
     <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Правадныя навушнікі"</string>
     <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Уключана"</string>
     <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Выключана"</string>
+    <string name="carrier_network_change_mode" msgid="4257621815706644026">"Змяненне аператара сеткі"</string>
+    <string name="data_connection_3g" msgid="931852552688157407">"3G"</string>
+    <string name="data_connection_edge" msgid="4625509456544797637">"EDGE"</string>
+    <string name="data_connection_cdma" msgid="9098161966701934334">"1X"</string>
+    <string name="data_connection_gprs" msgid="1251945769006770189">"GPRS"</string>
+    <string name="data_connection_3_5g" msgid="4298721462047921400">"H"</string>
+    <string name="data_connection_3_5g_plus" msgid="6683055858295918170">"H+"</string>
+    <string name="data_connection_4g" msgid="2581705503356752044">"4G"</string>
+    <string name="data_connection_4g_plus" msgid="5194902328408751020">"4G+"</string>
+    <string name="data_connection_lte" msgid="7675461204366364124">"LTE"</string>
+    <string name="data_connection_lte_plus" msgid="6643158654804916653">"LTE+"</string>
+    <string name="cell_data_off_content_description" msgid="2280700839891636498">"Мабільная перадача даных выключана"</string>
+    <string name="not_default_data_content_description" msgid="6517068332106592887">"Не зададзена для выкарыстання даных"</string>
+    <string name="accessibility_no_phone" msgid="2687419663127582503">"Няма тэлефона."</string>
+    <string name="accessibility_phone_one_bar" msgid="5719721147018970063">"Адна планка на тэлефоне."</string>
+    <string name="accessibility_phone_two_bars" msgid="2531458337458953263">"2 планкі тэлефона."</string>
+    <string name="accessibility_phone_three_bars" msgid="1523967995996696619">"3 планкі тэлефона."</string>
+    <string name="accessibility_phone_signal_full" msgid="4302338883816077134">"Поўны сігнал тэлефона."</string>
+    <string name="accessibility_no_data" msgid="4563181886936931008">"Няма дадзеных."</string>
+    <string name="accessibility_data_one_bar" msgid="6892888138070752480">"Адна планка дадзеных."</string>
+    <string name="accessibility_data_two_bars" msgid="9202641507241802499">"2 планкі дадзеных."</string>
+    <string name="accessibility_data_three_bars" msgid="2813876214466722413">"3 планкі дадзеных."</string>
+    <string name="accessibility_data_signal_full" msgid="1808301899314382337">"Поўны сігнал перадачы дадзеных."</string>
+    <string name="accessibility_ethernet_disconnected" msgid="2832501530856497489">"Ethernet адлучаны."</string>
+    <string name="accessibility_ethernet_connected" msgid="2093872142317190618">"Ethernet падлучаны."</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-bg/strings.xml b/packages/SettingsLib/res/values-bg/strings.xml
index 75d1eeb..ef0412b 100644
--- a/packages/SettingsLib/res/values-bg/strings.xml
+++ b/packages/SettingsLib/res/values-bg/strings.xml
@@ -403,7 +403,6 @@
     <string name="transcode_user_control" msgid="6176368544817731314">"Отмяна на стандартните настройки за прекодирането"</string>
     <string name="transcode_enable_all" msgid="2411165920039166710">"Активиране на прекодирането"</string>
     <string name="transcode_default" msgid="3784803084573509491">"Предполагане, че приложенията поддържат съвременни формати"</string>
-    <string name="transcode_skip_apps" msgid="8249721984597390142">"Активиране на прекодирането за приложения"</string>
     <string name="runningservices_settings_title" msgid="6460099290493086515">"Изпълнявани услуги"</string>
     <string name="runningservices_settings_summary" msgid="1046080643262665743">"Преглед и контрол върху изпълняващите се понастоящем услуги"</string>
     <string name="select_webview_provider_title" msgid="3917815648099445503">"Внедряване на WebView"</string>
@@ -566,4 +565,29 @@
     <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Слушалки с кабел"</string>
     <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Включване"</string>
     <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Изключване"</string>
+    <string name="carrier_network_change_mode" msgid="4257621815706644026">"Промяна на мрежата на оператора"</string>
+    <string name="data_connection_3g" msgid="931852552688157407">"3G"</string>
+    <string name="data_connection_edge" msgid="4625509456544797637">"EDGE"</string>
+    <string name="data_connection_cdma" msgid="9098161966701934334">"1X"</string>
+    <string name="data_connection_gprs" msgid="1251945769006770189">"GPRS"</string>
+    <string name="data_connection_3_5g" msgid="4298721462047921400">"H"</string>
+    <string name="data_connection_3_5g_plus" msgid="6683055858295918170">"H+"</string>
+    <string name="data_connection_4g" msgid="2581705503356752044">"4G"</string>
+    <string name="data_connection_4g_plus" msgid="5194902328408751020">"4G+"</string>
+    <string name="data_connection_lte" msgid="7675461204366364124">"LTE"</string>
+    <string name="data_connection_lte_plus" msgid="6643158654804916653">"LTE+"</string>
+    <string name="cell_data_off_content_description" msgid="2280700839891636498">"Мобилните данни са изключени"</string>
+    <string name="not_default_data_content_description" msgid="6517068332106592887">"Не е зададено да използва данни"</string>
+    <string name="accessibility_no_phone" msgid="2687419663127582503">"Няма телефон."</string>
+    <string name="accessibility_phone_one_bar" msgid="5719721147018970063">"Телефонът е с една чертичка."</string>
+    <string name="accessibility_phone_two_bars" msgid="2531458337458953263">"Телефонът е с две чертички."</string>
+    <string name="accessibility_phone_three_bars" msgid="1523967995996696619">"Телефонът е с три чертички."</string>
+    <string name="accessibility_phone_signal_full" msgid="4302338883816077134">"Сигналът за телефона е пълен."</string>
+    <string name="accessibility_no_data" msgid="4563181886936931008">"Няма данни."</string>
+    <string name="accessibility_data_one_bar" msgid="6892888138070752480">"Данните са с една чертичка."</string>
+    <string name="accessibility_data_two_bars" msgid="9202641507241802499">"Данните са с две чертички."</string>
+    <string name="accessibility_data_three_bars" msgid="2813876214466722413">"Данните са с три чертички."</string>
+    <string name="accessibility_data_signal_full" msgid="1808301899314382337">"Сигналът за данни е пълен."</string>
+    <string name="accessibility_ethernet_disconnected" msgid="2832501530856497489">"Връзката с Ethernet е прекратена."</string>
+    <string name="accessibility_ethernet_connected" msgid="2093872142317190618">"Установена е връзка с Ethernet."</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-bn/strings.xml b/packages/SettingsLib/res/values-bn/strings.xml
index 325f2bd..5b95399 100644
--- a/packages/SettingsLib/res/values-bn/strings.xml
+++ b/packages/SettingsLib/res/values-bn/strings.xml
@@ -400,13 +400,9 @@
     <string name="inactive_app_active_summary" msgid="8047630990208722344">"সক্রিয় রয়েছে৷ টগল করতে আলতো চাপুন৷"</string>
     <string name="standby_bucket_summary" msgid="5128193447550429600">"অ্যাপ স্ট্যান্ডবাই-এর অবস্থা:<xliff:g id="BUCKET"> %s</xliff:g>"</string>
     <string name="transcode_settings_title" msgid="2581975870429850549">"মিডিয়া ট্রান্সকোডিং সেটিংস"</string>
-    <!-- no translation found for transcode_user_control (6176368544817731314) -->
-    <skip />
-    <!-- no translation found for transcode_enable_all (2411165920039166710) -->
-    <skip />
-    <!-- no translation found for transcode_default (3784803084573509491) -->
-    <skip />
-    <string name="transcode_skip_apps" msgid="8249721984597390142">"অ্যাপের জন্য ট্রান্সকোডিং চালু করুন"</string>
+    <string name="transcode_user_control" msgid="6176368544817731314">"ট্রান্সকোডিং ডিফল্ট সেটিংস ওভাররাইড করুন"</string>
+    <string name="transcode_enable_all" msgid="2411165920039166710">"ট্রান্সকোডিং চালু করুন"</string>
+    <string name="transcode_default" msgid="3784803084573509491">"অ্যাপ মর্ডার্ন ফর্ম্যাটে কাজ করবে বলে ধরে নিন"</string>
     <string name="runningservices_settings_title" msgid="6460099290493086515">"এখন চলছে যে পরিষেবাগুলি"</string>
     <string name="runningservices_settings_summary" msgid="1046080643262665743">"বর্তমান চলমান পরিষেবাগুলি দেখুন এবং নিয়ন্ত্রণ করুন"</string>
     <string name="select_webview_provider_title" msgid="3917815648099445503">"ওয়েবভিউ প্রয়োগ"</string>
@@ -569,4 +565,29 @@
     <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"তার যুক্ত হেডফোন"</string>
     <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"চালু আছে"</string>
     <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"বন্ধ আছে"</string>
+    <string name="carrier_network_change_mode" msgid="4257621815706644026">"পরিষেবা প্রদানকারীর নেটওয়ার্ক পরিবর্তন করা হচ্ছে"</string>
+    <string name="data_connection_3g" msgid="931852552688157407">"3G"</string>
+    <string name="data_connection_edge" msgid="4625509456544797637">"EDGE"</string>
+    <string name="data_connection_cdma" msgid="9098161966701934334">"1X"</string>
+    <string name="data_connection_gprs" msgid="1251945769006770189">"GPRS"</string>
+    <string name="data_connection_3_5g" msgid="4298721462047921400">"H"</string>
+    <string name="data_connection_3_5g_plus" msgid="6683055858295918170">"H+"</string>
+    <string name="data_connection_4g" msgid="2581705503356752044">"4G"</string>
+    <string name="data_connection_4g_plus" msgid="5194902328408751020">"4G+"</string>
+    <string name="data_connection_lte" msgid="7675461204366364124">"LTE"</string>
+    <string name="data_connection_lte_plus" msgid="6643158654804916653">"LTE+"</string>
+    <string name="cell_data_off_content_description" msgid="2280700839891636498">"মোবাইল ডেটা বন্ধ করা হয়েছে"</string>
+    <string name="not_default_data_content_description" msgid="6517068332106592887">"ডেটা ব্যবহার করার জন্য সেট করা নেই"</string>
+    <string name="accessibility_no_phone" msgid="2687419663127582503">"কোনো ফোনের সংকেত নেই৷"</string>
+    <string name="accessibility_phone_one_bar" msgid="5719721147018970063">"এক দন্ড ফোনের সংকেত রয়েছে৷"</string>
+    <string name="accessibility_phone_two_bars" msgid="2531458337458953263">"দুই দন্ড ফোনের সংকেত রয়েছে৷"</string>
+    <string name="accessibility_phone_three_bars" msgid="1523967995996696619">"তিন দন্ড ফোনের সংকেত রয়েছে৷"</string>
+    <string name="accessibility_phone_signal_full" msgid="4302338883816077134">"ফোনের সংকেত পূর্ণ রয়েছে৷"</string>
+    <string name="accessibility_no_data" msgid="4563181886936931008">"কোনো ডেটা নেই৷"</string>
+    <string name="accessibility_data_one_bar" msgid="6892888138070752480">"এক দন্ড ডেটার সংকেত৷"</string>
+    <string name="accessibility_data_two_bars" msgid="9202641507241802499">"দুই দন্ড ডেটার সংকেত রয়েছে৷"</string>
+    <string name="accessibility_data_three_bars" msgid="2813876214466722413">"তিন দন্ড ডেটার সংকেত৷"</string>
+    <string name="accessibility_data_signal_full" msgid="1808301899314382337">"পূর্ণ ডেটার সংকেত রয়েছে৷"</string>
+    <string name="accessibility_ethernet_disconnected" msgid="2832501530856497489">"ইথারনেটের সংযোগ বিচ্ছিন্ন হয়েছে৷"</string>
+    <string name="accessibility_ethernet_connected" msgid="2093872142317190618">"ইথারনেট সংযুক্ত হয়েছে৷"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-bs/strings.xml b/packages/SettingsLib/res/values-bs/strings.xml
index ab4ac14..00d8087 100644
--- a/packages/SettingsLib/res/values-bs/strings.xml
+++ b/packages/SettingsLib/res/values-bs/strings.xml
@@ -403,7 +403,6 @@
     <string name="transcode_user_control" msgid="6176368544817731314">"Zaobiđi zadane postavke transkodiranja"</string>
     <string name="transcode_enable_all" msgid="2411165920039166710">"Omogući transkodiranje"</string>
     <string name="transcode_default" msgid="3784803084573509491">"Pretpostavi da aplikacije podržavaju moderne formate"</string>
-    <string name="transcode_skip_apps" msgid="8249721984597390142">"Omogućite transkodiranje za aplikacije"</string>
     <string name="runningservices_settings_title" msgid="6460099290493086515">"Pokrenute usluge"</string>
     <string name="runningservices_settings_summary" msgid="1046080643262665743">"Prikaz i kontrola trenutno pokrenutih usluga"</string>
     <string name="select_webview_provider_title" msgid="3917815648099445503">"Postavljanje WebViewa"</string>
@@ -567,4 +566,29 @@
     <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Žičane slušalice"</string>
     <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Uključi"</string>
     <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Isključi"</string>
+    <string name="carrier_network_change_mode" msgid="4257621815706644026">"Promjena mreže mobilnog operatera"</string>
+    <string name="data_connection_3g" msgid="931852552688157407">"3G"</string>
+    <string name="data_connection_edge" msgid="4625509456544797637">"EDGE"</string>
+    <string name="data_connection_cdma" msgid="9098161966701934334">"1X"</string>
+    <string name="data_connection_gprs" msgid="1251945769006770189">"GPRS"</string>
+    <string name="data_connection_3_5g" msgid="4298721462047921400">"H"</string>
+    <string name="data_connection_3_5g_plus" msgid="6683055858295918170">"H+"</string>
+    <string name="data_connection_4g" msgid="2581705503356752044">"4G"</string>
+    <string name="data_connection_4g_plus" msgid="5194902328408751020">"4G+"</string>
+    <string name="data_connection_lte" msgid="7675461204366364124">"LTE"</string>
+    <string name="data_connection_lte_plus" msgid="6643158654804916653">"LTE+"</string>
+    <string name="cell_data_off_content_description" msgid="2280700839891636498">"Prijenos podataka na mobilnoj mreži je isključen"</string>
+    <string name="not_default_data_content_description" msgid="6517068332106592887">"Nije postavljeno za korištenje podataka"</string>
+    <string name="accessibility_no_phone" msgid="2687419663127582503">"Nema telefonskog signala."</string>
+    <string name="accessibility_phone_one_bar" msgid="5719721147018970063">"Telefonski signal na jednoj crtici."</string>
+    <string name="accessibility_phone_two_bars" msgid="2531458337458953263">"Telefonski signal na dvije crtice."</string>
+    <string name="accessibility_phone_three_bars" msgid="1523967995996696619">"Telefonski signal na tri crtice."</string>
+    <string name="accessibility_phone_signal_full" msgid="4302338883816077134">"Telefonski signal pun."</string>
+    <string name="accessibility_no_data" msgid="4563181886936931008">"Nema podataka."</string>
+    <string name="accessibility_data_one_bar" msgid="6892888138070752480">"Prijenos podataka na jednoj crtici."</string>
+    <string name="accessibility_data_two_bars" msgid="9202641507241802499">"Prijenos podataka na dvije crtice."</string>
+    <string name="accessibility_data_three_bars" msgid="2813876214466722413">"Prijenos podataka na tri crtice."</string>
+    <string name="accessibility_data_signal_full" msgid="1808301899314382337">"Signal za prijenos podataka pun."</string>
+    <string name="accessibility_ethernet_disconnected" msgid="2832501530856497489">"Veza sa Ethernetom je prekinuta."</string>
+    <string name="accessibility_ethernet_connected" msgid="2093872142317190618">"Ethernet je spojen."</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-ca/strings.xml b/packages/SettingsLib/res/values-ca/strings.xml
index 9bb919f..300b475 100644
--- a/packages/SettingsLib/res/values-ca/strings.xml
+++ b/packages/SettingsLib/res/values-ca/strings.xml
@@ -403,7 +403,6 @@
     <string name="transcode_user_control" msgid="6176368544817731314">"Substitueix els valors predeterminats de la transcodificació"</string>
     <string name="transcode_enable_all" msgid="2411165920039166710">"Activa la transcodificació"</string>
     <string name="transcode_default" msgid="3784803084573509491">"Assumeix que les aplicacions són compatibles amb formats moderns"</string>
-    <string name="transcode_skip_apps" msgid="8249721984597390142">"Activa la transcodificació per a les aplicacions"</string>
     <string name="runningservices_settings_title" msgid="6460099290493086515">"Serveis en execució"</string>
     <string name="runningservices_settings_summary" msgid="1046080643262665743">"Visualitza i controla els serveis en execució"</string>
     <string name="select_webview_provider_title" msgid="3917815648099445503">"Implementació de WebView"</string>
@@ -566,4 +565,29 @@
     <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Auriculars amb cable"</string>
     <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Activa"</string>
     <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Desactiva"</string>
+    <string name="carrier_network_change_mode" msgid="4257621815706644026">"S\'està canviant la xarxa de l\'operador de telefonia mòbil"</string>
+    <string name="data_connection_3g" msgid="931852552688157407">"3G"</string>
+    <string name="data_connection_edge" msgid="4625509456544797637">"EDGE"</string>
+    <string name="data_connection_cdma" msgid="9098161966701934334">"1X"</string>
+    <string name="data_connection_gprs" msgid="1251945769006770189">"GPRS"</string>
+    <string name="data_connection_3_5g" msgid="4298721462047921400">"H"</string>
+    <string name="data_connection_3_5g_plus" msgid="6683055858295918170">"H+"</string>
+    <string name="data_connection_4g" msgid="2581705503356752044">"4G"</string>
+    <string name="data_connection_4g_plus" msgid="5194902328408751020">"4G+"</string>
+    <string name="data_connection_lte" msgid="7675461204366364124">"LTE"</string>
+    <string name="data_connection_lte_plus" msgid="6643158654804916653">"LTE+"</string>
+    <string name="cell_data_off_content_description" msgid="2280700839891636498">"S\'han desactivat les dades mòbils"</string>
+    <string name="not_default_data_content_description" msgid="6517068332106592887">"No s\'ha definit per utilitzar dades"</string>
+    <string name="accessibility_no_phone" msgid="2687419663127582503">"No hi ha senyal de telèfon."</string>
+    <string name="accessibility_phone_one_bar" msgid="5719721147018970063">"Senyal de telèfon: una barra"</string>
+    <string name="accessibility_phone_two_bars" msgid="2531458337458953263">"Senyal de telèfon: dues barres."</string>
+    <string name="accessibility_phone_three_bars" msgid="1523967995996696619">"Senyal de telèfon: tres barres."</string>
+    <string name="accessibility_phone_signal_full" msgid="4302338883816077134">"Senyal de telèfon: complet."</string>
+    <string name="accessibility_no_data" msgid="4563181886936931008">"Senyal de dades: no n\'hi ha"</string>
+    <string name="accessibility_data_one_bar" msgid="6892888138070752480">"Senyal de dades: una barra."</string>
+    <string name="accessibility_data_two_bars" msgid="9202641507241802499">"Senyal de dades: dues barres."</string>
+    <string name="accessibility_data_three_bars" msgid="2813876214466722413">"Senyal de dades: tres barres."</string>
+    <string name="accessibility_data_signal_full" msgid="1808301899314382337">"Senyal de dades: complet."</string>
+    <string name="accessibility_ethernet_disconnected" msgid="2832501530856497489">"S\'ha desconnectat l\'Ethernet."</string>
+    <string name="accessibility_ethernet_connected" msgid="2093872142317190618">"Ethernet connectada"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-cs/strings.xml b/packages/SettingsLib/res/values-cs/strings.xml
index 5f2e005..a9a5f48 100644
--- a/packages/SettingsLib/res/values-cs/strings.xml
+++ b/packages/SettingsLib/res/values-cs/strings.xml
@@ -403,7 +403,6 @@
     <string name="transcode_user_control" msgid="6176368544817731314">"Přepsat výchozí nastavení překódování"</string>
     <string name="transcode_enable_all" msgid="2411165920039166710">"Povolit překódování"</string>
     <string name="transcode_default" msgid="3784803084573509491">"Předpokládat, že aplikace podporují moderní formáty"</string>
-    <string name="transcode_skip_apps" msgid="8249721984597390142">"Povolit překódování pro aplikace"</string>
     <string name="runningservices_settings_title" msgid="6460099290493086515">"Spuštěné služby"</string>
     <string name="runningservices_settings_summary" msgid="1046080643262665743">"Umožňuje zobrazit a ovládat aktuálně spuštěné služby"</string>
     <string name="select_webview_provider_title" msgid="3917815648099445503">"Implementace WebView"</string>
@@ -568,4 +567,29 @@
     <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Kabelová sluchátka"</string>
     <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Zapnout"</string>
     <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Vypnout"</string>
+    <string name="carrier_network_change_mode" msgid="4257621815706644026">"Probíhá změna sítě operátora"</string>
+    <string name="data_connection_3g" msgid="931852552688157407">"3G"</string>
+    <string name="data_connection_edge" msgid="4625509456544797637">"EDGE"</string>
+    <string name="data_connection_cdma" msgid="9098161966701934334">"1X"</string>
+    <string name="data_connection_gprs" msgid="1251945769006770189">"GPRS"</string>
+    <string name="data_connection_3_5g" msgid="4298721462047921400">"H"</string>
+    <string name="data_connection_3_5g_plus" msgid="6683055858295918170">"H+"</string>
+    <string name="data_connection_4g" msgid="2581705503356752044">"4G"</string>
+    <string name="data_connection_4g_plus" msgid="5194902328408751020">"4G+"</string>
+    <string name="data_connection_lte" msgid="7675461204366364124">"LTE"</string>
+    <string name="data_connection_lte_plus" msgid="6643158654804916653">"LTE+"</string>
+    <string name="cell_data_off_content_description" msgid="2280700839891636498">"Mobilní data jsou vypnuta"</string>
+    <string name="not_default_data_content_description" msgid="6517068332106592887">"Nenastaveno k využití dat"</string>
+    <string name="accessibility_no_phone" msgid="2687419663127582503">"Žádná telefonní síť."</string>
+    <string name="accessibility_phone_one_bar" msgid="5719721147018970063">"Jedna čárka signálu telefonní sítě."</string>
+    <string name="accessibility_phone_two_bars" msgid="2531458337458953263">"Dvě čárky signálu telefonní sítě."</string>
+    <string name="accessibility_phone_three_bars" msgid="1523967995996696619">"Tři čárky signálu telefonní sítě."</string>
+    <string name="accessibility_phone_signal_full" msgid="4302338883816077134">"Plný signál telefonní sítě."</string>
+    <string name="accessibility_no_data" msgid="4563181886936931008">"Žádné datové připojení."</string>
+    <string name="accessibility_data_one_bar" msgid="6892888138070752480">"Jedna čárka signálu datové sítě."</string>
+    <string name="accessibility_data_two_bars" msgid="9202641507241802499">"Dvě čárky signálu datové sítě."</string>
+    <string name="accessibility_data_three_bars" msgid="2813876214466722413">"Tři čárky signálu datové sítě."</string>
+    <string name="accessibility_data_signal_full" msgid="1808301899314382337">"Plný signál datové sítě."</string>
+    <string name="accessibility_ethernet_disconnected" msgid="2832501530856497489">"Síť ethernet je odpojena."</string>
+    <string name="accessibility_ethernet_connected" msgid="2093872142317190618">"Síť ethernet je připojena."</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-da/strings.xml b/packages/SettingsLib/res/values-da/strings.xml
index f4f4650..738ed3c 100644
--- a/packages/SettingsLib/res/values-da/strings.xml
+++ b/packages/SettingsLib/res/values-da/strings.xml
@@ -403,7 +403,6 @@
     <string name="transcode_user_control" msgid="6176368544817731314">"Tilsidesæt standardindstillingerne for omkodning"</string>
     <string name="transcode_enable_all" msgid="2411165920039166710">"Aktivér omkodning"</string>
     <string name="transcode_default" msgid="3784803084573509491">"Gå ud fra, at apps understøtter moderne formater"</string>
-    <string name="transcode_skip_apps" msgid="8249721984597390142">"Aktivér omkodning for apps"</string>
     <string name="runningservices_settings_title" msgid="6460099290493086515">"Kørende tjenester"</string>
     <string name="runningservices_settings_summary" msgid="1046080643262665743">"Vis og administrer kørende tjenester"</string>
     <string name="select_webview_provider_title" msgid="3917815648099445503">"WebView-implementering"</string>
@@ -566,4 +565,29 @@
     <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Høretelefoner med ledning"</string>
     <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Til"</string>
     <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Fra"</string>
+    <string name="carrier_network_change_mode" msgid="4257621815706644026">"Skift af mobilnetværk"</string>
+    <string name="data_connection_3g" msgid="931852552688157407">"3G"</string>
+    <string name="data_connection_edge" msgid="4625509456544797637">"EDGE"</string>
+    <string name="data_connection_cdma" msgid="9098161966701934334">"1X"</string>
+    <string name="data_connection_gprs" msgid="1251945769006770189">"GPRS"</string>
+    <string name="data_connection_3_5g" msgid="4298721462047921400">"H"</string>
+    <string name="data_connection_3_5g_plus" msgid="6683055858295918170">"H+"</string>
+    <string name="data_connection_4g" msgid="2581705503356752044">"4G"</string>
+    <string name="data_connection_4g_plus" msgid="5194902328408751020">"4G+"</string>
+    <string name="data_connection_lte" msgid="7675461204366364124">"LTE"</string>
+    <string name="data_connection_lte_plus" msgid="6643158654804916653">"LTE+"</string>
+    <string name="cell_data_off_content_description" msgid="2280700839891636498">"Mobildata er deaktiveret"</string>
+    <string name="not_default_data_content_description" msgid="6517068332106592887">"Ikke indstillet til at anvende data"</string>
+    <string name="accessibility_no_phone" msgid="2687419663127582503">"Ingen telefon."</string>
+    <string name="accessibility_phone_one_bar" msgid="5719721147018970063">"Telefon en bjælke."</string>
+    <string name="accessibility_phone_two_bars" msgid="2531458337458953263">"Telefon to bjælker."</string>
+    <string name="accessibility_phone_three_bars" msgid="1523967995996696619">"Telefon tre bjælker."</string>
+    <string name="accessibility_phone_signal_full" msgid="4302338883816077134">"Telefonsignal fuldt."</string>
+    <string name="accessibility_no_data" msgid="4563181886936931008">"Ingen data."</string>
+    <string name="accessibility_data_one_bar" msgid="6892888138070752480">"Data en bjælke."</string>
+    <string name="accessibility_data_two_bars" msgid="9202641507241802499">"Data to bjælker."</string>
+    <string name="accessibility_data_three_bars" msgid="2813876214466722413">"Data tre bjælker."</string>
+    <string name="accessibility_data_signal_full" msgid="1808301899314382337">"Datasignal fuldt."</string>
+    <string name="accessibility_ethernet_disconnected" msgid="2832501530856497489">"Ethernet er ikke tilsluttet."</string>
+    <string name="accessibility_ethernet_connected" msgid="2093872142317190618">"Ethernet er tilsluttet."</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-de/strings.xml b/packages/SettingsLib/res/values-de/strings.xml
index 1d6894b..e274d63 100644
--- a/packages/SettingsLib/res/values-de/strings.xml
+++ b/packages/SettingsLib/res/values-de/strings.xml
@@ -400,13 +400,9 @@
     <string name="inactive_app_active_summary" msgid="8047630990208722344">"Aktiv. Zum Wechseln tippen."</string>
     <string name="standby_bucket_summary" msgid="5128193447550429600">"Standby-Status der App:<xliff:g id="BUCKET"> %s</xliff:g>"</string>
     <string name="transcode_settings_title" msgid="2581975870429850549">"Einstellungen für Medientranscodierung"</string>
-    <!-- no translation found for transcode_user_control (6176368544817731314) -->
-    <skip />
-    <!-- no translation found for transcode_enable_all (2411165920039166710) -->
-    <skip />
-    <!-- no translation found for transcode_default (3784803084573509491) -->
-    <skip />
-    <string name="transcode_skip_apps" msgid="8249721984597390142">"Transcodierung für Apps aktivieren"</string>
+    <string name="transcode_user_control" msgid="6176368544817731314">"Standardeinstellungen für Transcodierung überschreiben"</string>
+    <string name="transcode_enable_all" msgid="2411165920039166710">"Transcodierung aktivieren"</string>
+    <string name="transcode_default" msgid="3784803084573509491">"Voraussetzen, dass Apps moderne Formate unterstützen"</string>
     <string name="runningservices_settings_title" msgid="6460099290493086515">"Aktive Dienste"</string>
     <string name="runningservices_settings_summary" msgid="1046080643262665743">"Momentan ausgeführte Dienste anzeigen und steuern"</string>
     <string name="select_webview_provider_title" msgid="3917815648099445503">"WebView-Implementierung"</string>
@@ -569,4 +565,29 @@
     <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Kabelgebundene Kopfhörer"</string>
     <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"An"</string>
     <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Aus"</string>
+    <string name="carrier_network_change_mode" msgid="4257621815706644026">"Mobilfunknetzwerk wird gewechselt"</string>
+    <string name="data_connection_3g" msgid="931852552688157407">"3G"</string>
+    <string name="data_connection_edge" msgid="4625509456544797637">"EDGE"</string>
+    <string name="data_connection_cdma" msgid="9098161966701934334">"1X"</string>
+    <string name="data_connection_gprs" msgid="1251945769006770189">"GPRS"</string>
+    <string name="data_connection_3_5g" msgid="4298721462047921400">"H"</string>
+    <string name="data_connection_3_5g_plus" msgid="6683055858295918170">"H+"</string>
+    <string name="data_connection_4g" msgid="2581705503356752044">"4G"</string>
+    <string name="data_connection_4g_plus" msgid="5194902328408751020">"4G+"</string>
+    <string name="data_connection_lte" msgid="7675461204366364124">"LTE"</string>
+    <string name="data_connection_lte_plus" msgid="6643158654804916653">"LTE+"</string>
+    <string name="cell_data_off_content_description" msgid="2280700839891636498">"Mobile Daten deaktiviert"</string>
+    <string name="not_default_data_content_description" msgid="6517068332106592887">"Nicht für Datennutzung konfiguriert"</string>
+    <string name="accessibility_no_phone" msgid="2687419663127582503">"Kein Telefon"</string>
+    <string name="accessibility_phone_one_bar" msgid="5719721147018970063">"Telefonsignal - ein Balken"</string>
+    <string name="accessibility_phone_two_bars" msgid="2531458337458953263">"Telefonsignal - zwei Balken"</string>
+    <string name="accessibility_phone_three_bars" msgid="1523967995996696619">"Telefonsignal - drei Balken"</string>
+    <string name="accessibility_phone_signal_full" msgid="4302338883816077134">"Volle Telefonsignalstärke"</string>
+    <string name="accessibility_no_data" msgid="4563181886936931008">"Keine Daten"</string>
+    <string name="accessibility_data_one_bar" msgid="6892888138070752480">"Datensignal - ein Balken"</string>
+    <string name="accessibility_data_two_bars" msgid="9202641507241802499">"Datensignal - zwei Balken"</string>
+    <string name="accessibility_data_three_bars" msgid="2813876214466722413">"Datensignal - drei Balken"</string>
+    <string name="accessibility_data_signal_full" msgid="1808301899314382337">"Volle Datensignalstärke"</string>
+    <string name="accessibility_ethernet_disconnected" msgid="2832501530856497489">"Ethernet nicht verbunden"</string>
+    <string name="accessibility_ethernet_connected" msgid="2093872142317190618">"Ethernet verbunden"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-el/strings.xml b/packages/SettingsLib/res/values-el/strings.xml
index 3affbce..66244eb 100644
--- a/packages/SettingsLib/res/values-el/strings.xml
+++ b/packages/SettingsLib/res/values-el/strings.xml
@@ -403,7 +403,6 @@
     <string name="transcode_user_control" msgid="6176368544817731314">"Παράκαμψη προεπιλογών διακωδικοποίησης"</string>
     <string name="transcode_enable_all" msgid="2411165920039166710">"Ενεργοποίηση διακωδικοποίησης"</string>
     <string name="transcode_default" msgid="3784803084573509491">"Να θεωρείται ότι οι εφαρμογές χρησιμοποιούν σύγχρονες μορφές"</string>
-    <string name="transcode_skip_apps" msgid="8249721984597390142">"Ενεργοποίηση διακωδικοποίησης για εφαρμογές"</string>
     <string name="runningservices_settings_title" msgid="6460099290493086515">"Υπηρεσίες που εκτελούνται"</string>
     <string name="runningservices_settings_summary" msgid="1046080643262665743">"Προβολή και έλεγχος των εφαρμογών που εκτελούνται αυτή τη στιγμή"</string>
     <string name="select_webview_provider_title" msgid="3917815648099445503">"Υλοποίηση WebView"</string>
@@ -566,4 +565,29 @@
     <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Ενσύρματα ακουστικά"</string>
     <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Ενεργό"</string>
     <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Ανενεργό"</string>
+    <string name="carrier_network_change_mode" msgid="4257621815706644026">"Αλλαγή δικτύου εταιρείας κινητής τηλεφωνίας"</string>
+    <string name="data_connection_3g" msgid="931852552688157407">"3G"</string>
+    <string name="data_connection_edge" msgid="4625509456544797637">"EDGE"</string>
+    <string name="data_connection_cdma" msgid="9098161966701934334">"1X"</string>
+    <string name="data_connection_gprs" msgid="1251945769006770189">"GPRS"</string>
+    <string name="data_connection_3_5g" msgid="4298721462047921400">"H"</string>
+    <string name="data_connection_3_5g_plus" msgid="6683055858295918170">"H+"</string>
+    <string name="data_connection_4g" msgid="2581705503356752044">"4G"</string>
+    <string name="data_connection_4g_plus" msgid="5194902328408751020">"4G+"</string>
+    <string name="data_connection_lte" msgid="7675461204366364124">"LTE"</string>
+    <string name="data_connection_lte_plus" msgid="6643158654804916653">"LTE+"</string>
+    <string name="cell_data_off_content_description" msgid="2280700839891636498">"Τα δεδομένα κινητής τηλεφωνίας απενεργοποιήθηκαν"</string>
+    <string name="not_default_data_content_description" msgid="6517068332106592887">"Δεν ρυθμίστηκε ώστε να χρησιμοποιεί δεδομένα"</string>
+    <string name="accessibility_no_phone" msgid="2687419663127582503">"Δεν υπάρχει τηλέφωνο."</string>
+    <string name="accessibility_phone_one_bar" msgid="5719721147018970063">"Μία γραμμή τηλεφώνου."</string>
+    <string name="accessibility_phone_two_bars" msgid="2531458337458953263">"Δύο γραμμές τηλεφώνου."</string>
+    <string name="accessibility_phone_three_bars" msgid="1523967995996696619">"Τρεις γραμμές μπαταρίας."</string>
+    <string name="accessibility_phone_signal_full" msgid="4302338883816077134">"Πλήρες σήμα τηλεφώνου."</string>
+    <string name="accessibility_no_data" msgid="4563181886936931008">"Δεν υπάρχουν δεδομένα."</string>
+    <string name="accessibility_data_one_bar" msgid="6892888138070752480">"Μία γραμμή δεδομένων."</string>
+    <string name="accessibility_data_two_bars" msgid="9202641507241802499">"Δύο γραμμές δεδομένων."</string>
+    <string name="accessibility_data_three_bars" msgid="2813876214466722413">"Τρεις γραμμές δεδομένων."</string>
+    <string name="accessibility_data_signal_full" msgid="1808301899314382337">"Πλήρες σήμα δεδομένων."</string>
+    <string name="accessibility_ethernet_disconnected" msgid="2832501530856497489">"Το Ethernet αποσυνδέθηκε."</string>
+    <string name="accessibility_ethernet_connected" msgid="2093872142317190618">"Το Ethernet συνδέθηκε."</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-en-rAU/strings.xml b/packages/SettingsLib/res/values-en-rAU/strings.xml
index 9d5debb..f5a0e2c 100644
--- a/packages/SettingsLib/res/values-en-rAU/strings.xml
+++ b/packages/SettingsLib/res/values-en-rAU/strings.xml
@@ -403,7 +403,6 @@
     <string name="transcode_user_control" msgid="6176368544817731314">"Override transcoding defaults"</string>
     <string name="transcode_enable_all" msgid="2411165920039166710">"Enable transcoding"</string>
     <string name="transcode_default" msgid="3784803084573509491">"Assume apps support modern formats"</string>
-    <string name="transcode_skip_apps" msgid="8249721984597390142">"Enable transcoding for apps"</string>
     <string name="runningservices_settings_title" msgid="6460099290493086515">"Running services"</string>
     <string name="runningservices_settings_summary" msgid="1046080643262665743">"View and control currently running services"</string>
     <string name="select_webview_provider_title" msgid="3917815648099445503">"WebView implementation"</string>
@@ -566,4 +565,29 @@
     <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Wired headphones"</string>
     <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"On"</string>
     <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Off"</string>
+    <string name="carrier_network_change_mode" msgid="4257621815706644026">"Operator network changing"</string>
+    <string name="data_connection_3g" msgid="931852552688157407">"3G"</string>
+    <string name="data_connection_edge" msgid="4625509456544797637">"EDGE"</string>
+    <string name="data_connection_cdma" msgid="9098161966701934334">"1X"</string>
+    <string name="data_connection_gprs" msgid="1251945769006770189">"GPRS"</string>
+    <string name="data_connection_3_5g" msgid="4298721462047921400">"H"</string>
+    <string name="data_connection_3_5g_plus" msgid="6683055858295918170">"H+"</string>
+    <string name="data_connection_4g" msgid="2581705503356752044">"4G"</string>
+    <string name="data_connection_4g_plus" msgid="5194902328408751020">"4G+"</string>
+    <string name="data_connection_lte" msgid="7675461204366364124">"LTE"</string>
+    <string name="data_connection_lte_plus" msgid="6643158654804916653">"LTE+"</string>
+    <string name="cell_data_off_content_description" msgid="2280700839891636498">"Mobile data off"</string>
+    <string name="not_default_data_content_description" msgid="6517068332106592887">"Not set to use data"</string>
+    <string name="accessibility_no_phone" msgid="2687419663127582503">"No phone."</string>
+    <string name="accessibility_phone_one_bar" msgid="5719721147018970063">"Phone one bar."</string>
+    <string name="accessibility_phone_two_bars" msgid="2531458337458953263">"Phone two bars."</string>
+    <string name="accessibility_phone_three_bars" msgid="1523967995996696619">"Phone three bars."</string>
+    <string name="accessibility_phone_signal_full" msgid="4302338883816077134">"Phone signal full."</string>
+    <string name="accessibility_no_data" msgid="4563181886936931008">"No data."</string>
+    <string name="accessibility_data_one_bar" msgid="6892888138070752480">"Data one bar."</string>
+    <string name="accessibility_data_two_bars" msgid="9202641507241802499">"Data two bars."</string>
+    <string name="accessibility_data_three_bars" msgid="2813876214466722413">"Data three bars."</string>
+    <string name="accessibility_data_signal_full" msgid="1808301899314382337">"Data signal full."</string>
+    <string name="accessibility_ethernet_disconnected" msgid="2832501530856497489">"Ethernet disconnected."</string>
+    <string name="accessibility_ethernet_connected" msgid="2093872142317190618">"Ethernet connected."</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-en-rCA/strings.xml b/packages/SettingsLib/res/values-en-rCA/strings.xml
index b0190a2..6f11e80 100644
--- a/packages/SettingsLib/res/values-en-rCA/strings.xml
+++ b/packages/SettingsLib/res/values-en-rCA/strings.xml
@@ -403,7 +403,6 @@
     <string name="transcode_user_control" msgid="6176368544817731314">"Override transcoding defaults"</string>
     <string name="transcode_enable_all" msgid="2411165920039166710">"Enable transcoding"</string>
     <string name="transcode_default" msgid="3784803084573509491">"Assume apps support modern formats"</string>
-    <string name="transcode_skip_apps" msgid="8249721984597390142">"Enable transcoding for apps"</string>
     <string name="runningservices_settings_title" msgid="6460099290493086515">"Running services"</string>
     <string name="runningservices_settings_summary" msgid="1046080643262665743">"View and control currently running services"</string>
     <string name="select_webview_provider_title" msgid="3917815648099445503">"WebView implementation"</string>
@@ -566,4 +565,29 @@
     <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Wired headphones"</string>
     <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"On"</string>
     <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Off"</string>
+    <string name="carrier_network_change_mode" msgid="4257621815706644026">"Operator network changing"</string>
+    <string name="data_connection_3g" msgid="931852552688157407">"3G"</string>
+    <string name="data_connection_edge" msgid="4625509456544797637">"EDGE"</string>
+    <string name="data_connection_cdma" msgid="9098161966701934334">"1X"</string>
+    <string name="data_connection_gprs" msgid="1251945769006770189">"GPRS"</string>
+    <string name="data_connection_3_5g" msgid="4298721462047921400">"H"</string>
+    <string name="data_connection_3_5g_plus" msgid="6683055858295918170">"H+"</string>
+    <string name="data_connection_4g" msgid="2581705503356752044">"4G"</string>
+    <string name="data_connection_4g_plus" msgid="5194902328408751020">"4G+"</string>
+    <string name="data_connection_lte" msgid="7675461204366364124">"LTE"</string>
+    <string name="data_connection_lte_plus" msgid="6643158654804916653">"LTE+"</string>
+    <string name="cell_data_off_content_description" msgid="2280700839891636498">"Mobile data off"</string>
+    <string name="not_default_data_content_description" msgid="6517068332106592887">"Not set to use data"</string>
+    <string name="accessibility_no_phone" msgid="2687419663127582503">"No phone."</string>
+    <string name="accessibility_phone_one_bar" msgid="5719721147018970063">"Phone one bar."</string>
+    <string name="accessibility_phone_two_bars" msgid="2531458337458953263">"Phone two bars."</string>
+    <string name="accessibility_phone_three_bars" msgid="1523967995996696619">"Phone three bars."</string>
+    <string name="accessibility_phone_signal_full" msgid="4302338883816077134">"Phone signal full."</string>
+    <string name="accessibility_no_data" msgid="4563181886936931008">"No data."</string>
+    <string name="accessibility_data_one_bar" msgid="6892888138070752480">"Data one bar."</string>
+    <string name="accessibility_data_two_bars" msgid="9202641507241802499">"Data two bars."</string>
+    <string name="accessibility_data_three_bars" msgid="2813876214466722413">"Data three bars."</string>
+    <string name="accessibility_data_signal_full" msgid="1808301899314382337">"Data signal full."</string>
+    <string name="accessibility_ethernet_disconnected" msgid="2832501530856497489">"Ethernet disconnected."</string>
+    <string name="accessibility_ethernet_connected" msgid="2093872142317190618">"Ethernet connected."</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-en-rGB/strings.xml b/packages/SettingsLib/res/values-en-rGB/strings.xml
index 9d5debb..f5a0e2c 100644
--- a/packages/SettingsLib/res/values-en-rGB/strings.xml
+++ b/packages/SettingsLib/res/values-en-rGB/strings.xml
@@ -403,7 +403,6 @@
     <string name="transcode_user_control" msgid="6176368544817731314">"Override transcoding defaults"</string>
     <string name="transcode_enable_all" msgid="2411165920039166710">"Enable transcoding"</string>
     <string name="transcode_default" msgid="3784803084573509491">"Assume apps support modern formats"</string>
-    <string name="transcode_skip_apps" msgid="8249721984597390142">"Enable transcoding for apps"</string>
     <string name="runningservices_settings_title" msgid="6460099290493086515">"Running services"</string>
     <string name="runningservices_settings_summary" msgid="1046080643262665743">"View and control currently running services"</string>
     <string name="select_webview_provider_title" msgid="3917815648099445503">"WebView implementation"</string>
@@ -566,4 +565,29 @@
     <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Wired headphones"</string>
     <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"On"</string>
     <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Off"</string>
+    <string name="carrier_network_change_mode" msgid="4257621815706644026">"Operator network changing"</string>
+    <string name="data_connection_3g" msgid="931852552688157407">"3G"</string>
+    <string name="data_connection_edge" msgid="4625509456544797637">"EDGE"</string>
+    <string name="data_connection_cdma" msgid="9098161966701934334">"1X"</string>
+    <string name="data_connection_gprs" msgid="1251945769006770189">"GPRS"</string>
+    <string name="data_connection_3_5g" msgid="4298721462047921400">"H"</string>
+    <string name="data_connection_3_5g_plus" msgid="6683055858295918170">"H+"</string>
+    <string name="data_connection_4g" msgid="2581705503356752044">"4G"</string>
+    <string name="data_connection_4g_plus" msgid="5194902328408751020">"4G+"</string>
+    <string name="data_connection_lte" msgid="7675461204366364124">"LTE"</string>
+    <string name="data_connection_lte_plus" msgid="6643158654804916653">"LTE+"</string>
+    <string name="cell_data_off_content_description" msgid="2280700839891636498">"Mobile data off"</string>
+    <string name="not_default_data_content_description" msgid="6517068332106592887">"Not set to use data"</string>
+    <string name="accessibility_no_phone" msgid="2687419663127582503">"No phone."</string>
+    <string name="accessibility_phone_one_bar" msgid="5719721147018970063">"Phone one bar."</string>
+    <string name="accessibility_phone_two_bars" msgid="2531458337458953263">"Phone two bars."</string>
+    <string name="accessibility_phone_three_bars" msgid="1523967995996696619">"Phone three bars."</string>
+    <string name="accessibility_phone_signal_full" msgid="4302338883816077134">"Phone signal full."</string>
+    <string name="accessibility_no_data" msgid="4563181886936931008">"No data."</string>
+    <string name="accessibility_data_one_bar" msgid="6892888138070752480">"Data one bar."</string>
+    <string name="accessibility_data_two_bars" msgid="9202641507241802499">"Data two bars."</string>
+    <string name="accessibility_data_three_bars" msgid="2813876214466722413">"Data three bars."</string>
+    <string name="accessibility_data_signal_full" msgid="1808301899314382337">"Data signal full."</string>
+    <string name="accessibility_ethernet_disconnected" msgid="2832501530856497489">"Ethernet disconnected."</string>
+    <string name="accessibility_ethernet_connected" msgid="2093872142317190618">"Ethernet connected."</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-en-rIN/strings.xml b/packages/SettingsLib/res/values-en-rIN/strings.xml
index 9d5debb..f5a0e2c 100644
--- a/packages/SettingsLib/res/values-en-rIN/strings.xml
+++ b/packages/SettingsLib/res/values-en-rIN/strings.xml
@@ -403,7 +403,6 @@
     <string name="transcode_user_control" msgid="6176368544817731314">"Override transcoding defaults"</string>
     <string name="transcode_enable_all" msgid="2411165920039166710">"Enable transcoding"</string>
     <string name="transcode_default" msgid="3784803084573509491">"Assume apps support modern formats"</string>
-    <string name="transcode_skip_apps" msgid="8249721984597390142">"Enable transcoding for apps"</string>
     <string name="runningservices_settings_title" msgid="6460099290493086515">"Running services"</string>
     <string name="runningservices_settings_summary" msgid="1046080643262665743">"View and control currently running services"</string>
     <string name="select_webview_provider_title" msgid="3917815648099445503">"WebView implementation"</string>
@@ -566,4 +565,29 @@
     <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Wired headphones"</string>
     <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"On"</string>
     <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Off"</string>
+    <string name="carrier_network_change_mode" msgid="4257621815706644026">"Operator network changing"</string>
+    <string name="data_connection_3g" msgid="931852552688157407">"3G"</string>
+    <string name="data_connection_edge" msgid="4625509456544797637">"EDGE"</string>
+    <string name="data_connection_cdma" msgid="9098161966701934334">"1X"</string>
+    <string name="data_connection_gprs" msgid="1251945769006770189">"GPRS"</string>
+    <string name="data_connection_3_5g" msgid="4298721462047921400">"H"</string>
+    <string name="data_connection_3_5g_plus" msgid="6683055858295918170">"H+"</string>
+    <string name="data_connection_4g" msgid="2581705503356752044">"4G"</string>
+    <string name="data_connection_4g_plus" msgid="5194902328408751020">"4G+"</string>
+    <string name="data_connection_lte" msgid="7675461204366364124">"LTE"</string>
+    <string name="data_connection_lte_plus" msgid="6643158654804916653">"LTE+"</string>
+    <string name="cell_data_off_content_description" msgid="2280700839891636498">"Mobile data off"</string>
+    <string name="not_default_data_content_description" msgid="6517068332106592887">"Not set to use data"</string>
+    <string name="accessibility_no_phone" msgid="2687419663127582503">"No phone."</string>
+    <string name="accessibility_phone_one_bar" msgid="5719721147018970063">"Phone one bar."</string>
+    <string name="accessibility_phone_two_bars" msgid="2531458337458953263">"Phone two bars."</string>
+    <string name="accessibility_phone_three_bars" msgid="1523967995996696619">"Phone three bars."</string>
+    <string name="accessibility_phone_signal_full" msgid="4302338883816077134">"Phone signal full."</string>
+    <string name="accessibility_no_data" msgid="4563181886936931008">"No data."</string>
+    <string name="accessibility_data_one_bar" msgid="6892888138070752480">"Data one bar."</string>
+    <string name="accessibility_data_two_bars" msgid="9202641507241802499">"Data two bars."</string>
+    <string name="accessibility_data_three_bars" msgid="2813876214466722413">"Data three bars."</string>
+    <string name="accessibility_data_signal_full" msgid="1808301899314382337">"Data signal full."</string>
+    <string name="accessibility_ethernet_disconnected" msgid="2832501530856497489">"Ethernet disconnected."</string>
+    <string name="accessibility_ethernet_connected" msgid="2093872142317190618">"Ethernet connected."</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-en-rXC/strings.xml b/packages/SettingsLib/res/values-en-rXC/strings.xml
index 9296a59..bfca1095 100644
--- a/packages/SettingsLib/res/values-en-rXC/strings.xml
+++ b/packages/SettingsLib/res/values-en-rXC/strings.xml
@@ -403,7 +403,6 @@
     <string name="transcode_user_control" msgid="6176368544817731314">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‎‏‎‏‎‏‏‎‏‏‎‏‏‎‏‏‎‏‏‏‏‎‎‏‏‏‎‏‏‏‏‎‏‏‏‎‏‏‏‏‎‎‎‎‎‏‏‏‎‏‎‏‏‎‏‏‏‏‎‎‏‎‎Override transcoding defaults‎‏‎‎‏‎"</string>
     <string name="transcode_enable_all" msgid="2411165920039166710">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‎‏‎‎‎‎‏‎‏‏‏‎‏‏‎‎‎‏‎‏‏‏‎‏‎‏‎‎‎‎‏‎‎‎‏‏‏‏‎‎‏‏‏‎‏‏‎‎‏‏‎‎‎‏‎‏‏‏‏‎‏‏‎‎Enable transcoding‎‏‎‎‏‎"</string>
     <string name="transcode_default" msgid="3784803084573509491">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‎‏‏‎‏‎‎‏‎‎‎‎‏‏‎‎‏‎‏‎‎‏‎‎‏‎‏‏‎‏‎‎‏‎‎‏‎‎‎‏‏‎‎‏‏‏‎‏‎‎‎‎‏‏‏‎‏‏‏‎‎‏‏‎Assume apps support modern formats‎‏‎‎‏‎"</string>
-    <string name="transcode_skip_apps" msgid="8249721984597390142">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‏‏‎‎‏‎‎‏‏‏‏‏‎‎‏‏‏‎‎‏‏‎‎‏‏‎‏‏‏‏‏‎‏‎‎‎‏‏‏‎‏‎‏‎‎‎‎‏‏‏‎‎‏‏‎‎‏‏‏‏‏‎‎Enable transcoding for apps‎‏‎‎‏‎"</string>
     <string name="runningservices_settings_title" msgid="6460099290493086515">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‎‏‏‎‎‏‏‎‏‎‎‏‏‎‏‏‏‎‎‎‏‎‎‎‎‏‎‎‏‏‏‏‎‏‏‏‏‏‏‎‎‏‎‏‏‏‏‏‏‎‏‎‏‏‎‎‏‏‎‎‏‏‎Running services‎‏‎‎‏‎"</string>
     <string name="runningservices_settings_summary" msgid="1046080643262665743">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‎‎‏‏‏‎‏‎‎‎‎‏‎‎‎‏‏‎‏‏‎‎‏‏‎‎‏‏‎‏‎‏‏‏‏‏‎‎‎‎‎‏‎‏‎‏‎‏‎‏‎‏‎‎‎‎‎‎‏‏‏‏‎View and control currently running services‎‏‎‎‏‎"</string>
     <string name="select_webview_provider_title" msgid="3917815648099445503">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‎‏‏‎‏‏‎‎‏‎‏‏‏‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‏‏‎‎‎‏‎‎‎‎‎‏‏‎‏‏‏‏‎‎‏‎‏‎‏‎‏‏‏‏‏‏‏‏‎WebView implementation‎‏‎‎‏‎"</string>
@@ -566,4 +565,29 @@
     <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‏‎‏‎‏‎‏‏‎‏‏‎‎‎‏‏‎‏‏‎‎‎‎‎‎‎‎‏‏‏‎‎‏‏‎‎‏‏‎‎‎‏‎‏‎‎‎‏‏‎‏‏‏‏‏‎‎‏‎‏‏‏‎Wired headphone‎‏‎‎‏‎"</string>
     <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‎‏‏‎‎‎‏‎‎‏‎‎‎‏‏‎‎‏‎‏‏‏‏‎‏‎‎‎‎‏‎‏‎‎‎‎‎‎‎‏‎‏‎‎‏‏‎‎‏‎‏‎‏‏‎On‎‏‎‎‏‎"</string>
     <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‏‎‎‏‎‎‏‎‎‎‏‏‎‏‎‏‏‎‏‏‎‏‎‎‎‎‎‏‏‎‏‏‎‎‏‏‎‏‏‎‏‎‏‏‎‏‏‏‏‏‏‏‏‏‎‎‎‏‎‏‎‎‎Off‎‏‎‎‏‎"</string>
+    <string name="carrier_network_change_mode" msgid="4257621815706644026">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‎‏‏‏‎‏‏‎‎‎‏‎‏‏‎‎‎‎‏‏‏‎‎‎‏‏‏‏‎‏‏‏‏‎‎‏‎‎‏‎‎‏‎‎‏‎‏‏‏‏‎‏‏‏‎‎‎‏‏‏‎‏‎‎Carrier network changing‎‏‎‎‏‎"</string>
+    <string name="data_connection_3g" msgid="931852552688157407">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‎‎‏‏‎‎‏‏‏‎‏‏‏‎‏‎‎‏‏‎‏‎‏‏‏‏‎‏‎‏‏‎‏‎‎‎‏‎‎‎‎‎‎‏‎‎‏‏‎‎‎‎‏‎‏‏‎‏‏‏‏‏‎3G‎‏‎‎‏‎"</string>
+    <string name="data_connection_edge" msgid="4625509456544797637">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‎‎‎‎‎‎‎‎‏‏‎‎‎‏‎‎‎‏‏‏‎‎‎‏‎‏‎‏‏‏‏‏‏‏‏‏‏‎‏‎‎‏‎‎‎‎‎‎‎‏‎‎‏‏‏‏‎‎‎‏‎‏‎EDGE‎‏‎‎‏‎"</string>
+    <string name="data_connection_cdma" msgid="9098161966701934334">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‏‏‏‏‏‎‎‏‎‎‎‎‏‏‎‎‏‎‏‎‏‎‎‎‎‏‏‎‏‎‏‏‎‎‎‏‏‎‎‎‏‏‏‏‎‎‏‏‏‏‎‏‏‎‏‏‏‏‏‏‏‎‎1X‎‏‎‎‏‎"</string>
+    <string name="data_connection_gprs" msgid="1251945769006770189">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‎‏‏‎‎‎‏‎‏‎‏‏‏‏‏‏‏‎‎‏‏‏‎‎‎‎‎‏‎‏‏‎‎‏‏‎‏‏‏‏‎‏‏‎‎‏‏‏‎‏‎‏‎‎‎‎‎‎‎‏‏‎‏‎GPRS‎‏‎‎‏‎"</string>
+    <string name="data_connection_3_5g" msgid="4298721462047921400">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‎‏‏‏‎‏‏‏‎‏‎‏‎‎‎‎‎‏‎‎‎‎‎‎‏‏‎‎‏‎‎‏‏‏‎‎‏‎‏‏‎‏‏‎‏‏‎‏‏‎‏‎‏‎‎‏‏‏‏‏‎‎‎‎H‎‏‎‎‏‎"</string>
+    <string name="data_connection_3_5g_plus" msgid="6683055858295918170">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‎‏‏‏‎‎‏‎‏‏‏‏‏‎‏‏‏‏‏‎‏‏‏‏‏‎‎‏‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‏‎‎‏‎‎‏‏‏‎‎‏‎‏‏‎‏‎‎H+‎‏‎‎‏‎"</string>
+    <string name="data_connection_4g" msgid="2581705503356752044">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‎‏‎‎‎‏‏‏‏‎‏‎‏‎‎‎‎‎‎‏‏‏‏‎‏‏‏‏‎‏‎‎‎‎‏‎‎‏‎‎‏‎‎‎‎‎‎‎‎‎‏‎‎‎‎‏‎‏‎‏‏‎‎‎4G‎‏‎‎‏‎"</string>
+    <string name="data_connection_4g_plus" msgid="5194902328408751020">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‎‎‏‎‎‎‎‎‎‏‏‎‎‎‎‎‎‎‎‎‎‎‎‎‏‎‎‏‎‎‏‏‎‏‎‏‏‏‏‎‏‎‎‏‏‏‎‎‏‏‏‎‏‏‏‎‏‎‏‏‎‎‎4G+‎‏‎‎‏‎"</string>
+    <string name="data_connection_lte" msgid="7675461204366364124">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‏‎‏‎‏‎‏‎‎‎‎‏‎‎‏‎‏‏‎‏‏‏‎‏‎‎‏‏‎‎‏‎‎‎‏‏‎‏‏‎‎‎‏‏‎‎‏‎‎‎‏‏‎‏‏‏‎‏‏‏‎‎‎LTE‎‏‎‎‏‎"</string>
+    <string name="data_connection_lte_plus" msgid="6643158654804916653">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‎‏‏‏‎‎‎‎‏‏‎‎‎‏‎‎‏‏‏‏‎‏‏‎‎‏‏‎‎‏‎‏‏‏‏‏‏‎‎‎‏‏‎‏‎‏‎‏‏‏‏‎‎‏‏‎‏‎‏‏‎‏‎LTE+‎‏‎‎‏‎"</string>
+    <string name="cell_data_off_content_description" msgid="2280700839891636498">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‎‏‏‏‏‏‏‏‎‏‎‎‏‏‎‏‎‏‎‏‏‎‏‎‏‎‏‎‏‎‎‏‎‎‎‏‎‎‎‏‎‏‎‏‏‎‏‎‎‎‏‎‎‎‏‎‎‎‏‎‎‏‎‎Mobile data off‎‏‎‎‏‎"</string>
+    <string name="not_default_data_content_description" msgid="6517068332106592887">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‎‏‏‎‏‎‎‏‏‏‎‎‎‏‎‏‎‎‎‏‏‏‎‎‎‏‏‏‏‎‏‎‎‎‎‎‎‎‎‎‏‎‏‎‎‏‎‎‏‏‎‎‏‎‎‏‏‏‎‏‏‏‎Not set to use data‎‏‎‎‏‎"</string>
+    <string name="accessibility_no_phone" msgid="2687419663127582503">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‎‏‎‎‏‎‏‎‏‎‎‏‎‏‏‏‎‏‎‎‎‎‏‏‏‏‏‎‎‎‏‏‏‏‎‏‏‏‏‎‎‎‏‏‏‏‎‏‎‎‏‎‏‏‏‎‎‏‎‎‏‏‏‎No phone.‎‏‎‎‏‎"</string>
+    <string name="accessibility_phone_one_bar" msgid="5719721147018970063">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‎‎‏‏‏‏‎‏‏‎‎‎‎‎‏‎‎‎‏‎‎‎‎‎‎‏‎‏‎‎‎‎‏‎‏‏‏‎‎‏‎‏‏‎‏‏‎‎‎‎‎‎‏‏‏‏‎‎‏‏‏‏‎Phone one bar.‎‏‎‎‏‎"</string>
+    <string name="accessibility_phone_two_bars" msgid="2531458337458953263">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‎‏‎‎‎‏‏‎‎‏‎‎‎‎‏‏‎‎‎‏‎‏‏‏‏‏‏‎‎‏‎‎‎‎‏‎‏‏‏‏‏‏‏‎‎‎‏‎‎‎‏‏‏‎‎‎‎‏‎‏‏‏‏‎Phone two bars.‎‏‎‎‏‎"</string>
+    <string name="accessibility_phone_three_bars" msgid="1523967995996696619">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‎‏‏‎‏‎‏‎‎‏‎‎‏‏‎‎‎‏‏‏‎‎‎‏‏‎‏‎‎‎‏‎‏‏‎‏‎‏‎‎‏‏‏‎‎‏‎‎‏‏‏‎‎‎‎‎‎‏‎‏‎‏‏‎Phone three bars.‎‏‎‎‏‎"</string>
+    <string name="accessibility_phone_signal_full" msgid="4302338883816077134">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‎‏‏‏‎‏‏‏‎‏‏‎‏‎‎‏‏‏‏‏‎‏‎‎‏‏‎‏‎‏‏‏‎‎‎‏‎‎‏‎‎‏‏‎‏‎‏‎‎‏‏‎‏‏‏‎‏‎‎‏‏‏‎‎Phone signal full.‎‏‎‎‏‎"</string>
+    <string name="accessibility_no_data" msgid="4563181886936931008">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‎‏‏‏‏‏‏‎‏‎‏‎‎‏‏‏‎‏‎‏‏‎‏‏‎‏‏‏‏‏‏‏‏‎‏‏‎‎‎‎‏‎‏‏‏‏‏‎‏‎‏‏‎‏‎‏‏‎‎‎‎‎‎‎No data.‎‏‎‎‏‎"</string>
+    <string name="accessibility_data_one_bar" msgid="6892888138070752480">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‎‏‏‏‏‏‏‎‏‎‏‎‎‎‎‏‏‏‎‏‎‏‎‎‏‏‏‏‎‏‏‏‎‏‎‎‏‎‎‎‏‏‎‏‎‏‏‏‏‏‏‏‎‎‏‏‏‎‎‎‎‎‎Data one bar.‎‏‎‎‏‎"</string>
+    <string name="accessibility_data_two_bars" msgid="9202641507241802499">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‏‏‏‏‏‏‏‎‏‏‎‏‏‎‎‏‎‏‏‎‎‏‏‎‏‏‎‎‎‏‎‏‏‏‎‎‏‎‎‏‏‎‏‎‎‏‏‎‏‏‏‎‏‏‎‎‎‎‎‎‏‏‎Data two bars.‎‏‎‎‏‎"</string>
+    <string name="accessibility_data_three_bars" msgid="2813876214466722413">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‎‏‎‎‏‏‏‎‎‎‎‏‏‎‎‏‏‏‎‎‏‎‏‏‎‎‎‎‎‏‎‎‎‏‎‏‏‎‏‎‎‏‏‎‏‎‏‏‎‏‏‏‎‏‎‎‏‏‎‏‏‎‏‎Data three bars.‎‏‎‎‏‎"</string>
+    <string name="accessibility_data_signal_full" msgid="1808301899314382337">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‎‏‏‏‎‎‏‎‎‎‏‏‎‎‎‎‏‏‎‎‎‎‎‏‏‏‏‏‏‏‏‎‎‏‎‎‎‏‏‎‏‎‎‏‏‎‎‎‏‎‎‎‏‏‎‎‎‎‎‎‎‎‏‎Data signal full.‎‏‎‎‏‎"</string>
+    <string name="accessibility_ethernet_disconnected" msgid="2832501530856497489">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‎‏‎‎‏‏‏‎‏‎‎‏‏‏‏‎‎‎‏‎‎‎‏‎‎‏‎‎‎‏‎‏‎‎‏‎‏‎‎‎‏‏‏‎‎‏‏‏‎‏‎‎‎‎‏‎‏‎‏‎‎‎‏‎Ethernet disconnected.‎‏‎‎‏‎"</string>
+    <string name="accessibility_ethernet_connected" msgid="2093872142317190618">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‎‏‏‏‏‎‏‎‎‎‎‏‏‏‎‏‏‏‎‏‏‎‏‏‎‎‏‏‏‏‎‏‎‎‏‏‏‏‏‏‏‏‎‎‏‏‎‏‏‏‏‏‏‎‏‏‏‎‏‏‎‏‎‎Ethernet connected.‎‏‎‎‏‎"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-es-rUS/strings.xml b/packages/SettingsLib/res/values-es-rUS/strings.xml
index 41466be..44ae8c2 100644
--- a/packages/SettingsLib/res/values-es-rUS/strings.xml
+++ b/packages/SettingsLib/res/values-es-rUS/strings.xml
@@ -403,7 +403,6 @@
     <string name="transcode_user_control" msgid="6176368544817731314">"Anular los valores predeterminados de transcodificación"</string>
     <string name="transcode_enable_all" msgid="2411165920039166710">"Habilitar la transcodificación"</string>
     <string name="transcode_default" msgid="3784803084573509491">"Suponer que las apps admiten formatos modernos"</string>
-    <string name="transcode_skip_apps" msgid="8249721984597390142">"Habilitar transcodificación en apps"</string>
     <string name="runningservices_settings_title" msgid="6460099290493086515">"En ejecución"</string>
     <string name="runningservices_settings_summary" msgid="1046080643262665743">"Ver y controlar servicios actuales en ejecución"</string>
     <string name="select_webview_provider_title" msgid="3917815648099445503">"Implementación de WebView"</string>
@@ -566,4 +565,29 @@
     <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Auriculares con cable"</string>
     <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Activar"</string>
     <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Desactivar"</string>
+    <string name="carrier_network_change_mode" msgid="4257621815706644026">"Cambio de proveedor de red"</string>
+    <string name="data_connection_3g" msgid="931852552688157407">"3G"</string>
+    <string name="data_connection_edge" msgid="4625509456544797637">"EDGE"</string>
+    <string name="data_connection_cdma" msgid="9098161966701934334">"1X"</string>
+    <string name="data_connection_gprs" msgid="1251945769006770189">"GPRS"</string>
+    <string name="data_connection_3_5g" msgid="4298721462047921400">"H"</string>
+    <string name="data_connection_3_5g_plus" msgid="6683055858295918170">"H+"</string>
+    <string name="data_connection_4g" msgid="2581705503356752044">"4G"</string>
+    <string name="data_connection_4g_plus" msgid="5194902328408751020">"4G+"</string>
+    <string name="data_connection_lte" msgid="7675461204366364124">"LTE"</string>
+    <string name="data_connection_lte_plus" msgid="6643158654804916653">"LTE+"</string>
+    <string name="cell_data_off_content_description" msgid="2280700839891636498">"Datos móviles desactivados"</string>
+    <string name="not_default_data_content_description" msgid="6517068332106592887">"No se configuró para usar datos"</string>
+    <string name="accessibility_no_phone" msgid="2687419663127582503">"Sin teléfono"</string>
+    <string name="accessibility_phone_one_bar" msgid="5719721147018970063">"Una barra de teléfono"</string>
+    <string name="accessibility_phone_two_bars" msgid="2531458337458953263">"Dos barras de teléfono"</string>
+    <string name="accessibility_phone_three_bars" msgid="1523967995996696619">"Tres barras de teléfono"</string>
+    <string name="accessibility_phone_signal_full" msgid="4302338883816077134">"Señal de teléfono completa"</string>
+    <string name="accessibility_no_data" msgid="4563181886936931008">"No hay datos."</string>
+    <string name="accessibility_data_one_bar" msgid="6892888138070752480">"Una barra de datos"</string>
+    <string name="accessibility_data_two_bars" msgid="9202641507241802499">"Dos barras de datos"</string>
+    <string name="accessibility_data_three_bars" msgid="2813876214466722413">"Tres barras de datos"</string>
+    <string name="accessibility_data_signal_full" msgid="1808301899314382337">"Señal de datos completa"</string>
+    <string name="accessibility_ethernet_disconnected" msgid="2832501530856497489">"Ethernet desconectada"</string>
+    <string name="accessibility_ethernet_connected" msgid="2093872142317190618">"Ethernet conectada"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-es/strings.xml b/packages/SettingsLib/res/values-es/strings.xml
index 8a0a123..236394c 100644
--- a/packages/SettingsLib/res/values-es/strings.xml
+++ b/packages/SettingsLib/res/values-es/strings.xml
@@ -403,7 +403,6 @@
     <string name="transcode_user_control" msgid="6176368544817731314">"Anular valores predeterminados de transcodificación"</string>
     <string name="transcode_enable_all" msgid="2411165920039166710">"Habilitar transcodificación"</string>
     <string name="transcode_default" msgid="3784803084573509491">"Considerar que las aplicaciones admiten formatos modernos"</string>
-    <string name="transcode_skip_apps" msgid="8249721984597390142">"Habilitar transcodificación en las aplicaciones"</string>
     <string name="runningservices_settings_title" msgid="6460099290493086515">"Servicios en ejecución"</string>
     <string name="runningservices_settings_summary" msgid="1046080643262665743">"Ver y controlar los servicios en ejecución"</string>
     <string name="select_webview_provider_title" msgid="3917815648099445503">"Implementación de WebView"</string>
@@ -566,4 +565,29 @@
     <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Auriculares con cable"</string>
     <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Activado"</string>
     <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Desactivado"</string>
+    <string name="carrier_network_change_mode" msgid="4257621815706644026">"Cambiando la red del operador"</string>
+    <string name="data_connection_3g" msgid="931852552688157407">"3G"</string>
+    <string name="data_connection_edge" msgid="4625509456544797637">"EDGE"</string>
+    <string name="data_connection_cdma" msgid="9098161966701934334">"1X"</string>
+    <string name="data_connection_gprs" msgid="1251945769006770189">"GPRS"</string>
+    <string name="data_connection_3_5g" msgid="4298721462047921400">"H"</string>
+    <string name="data_connection_3_5g_plus" msgid="6683055858295918170">"H+"</string>
+    <string name="data_connection_4g" msgid="2581705503356752044">"4G"</string>
+    <string name="data_connection_4g_plus" msgid="5194902328408751020">"4G+"</string>
+    <string name="data_connection_lte" msgid="7675461204366364124">"LTE"</string>
+    <string name="data_connection_lte_plus" msgid="6643158654804916653">"LTE+"</string>
+    <string name="cell_data_off_content_description" msgid="2280700839891636498">"Datos desactiv."</string>
+    <string name="not_default_data_content_description" msgid="6517068332106592887">"No está establecido para usar los datos"</string>
+    <string name="accessibility_no_phone" msgid="2687419663127582503">"Sin teléfono"</string>
+    <string name="accessibility_phone_one_bar" msgid="5719721147018970063">"Una barra de cobertura"</string>
+    <string name="accessibility_phone_two_bars" msgid="2531458337458953263">"Dos barras de cobertura"</string>
+    <string name="accessibility_phone_three_bars" msgid="1523967995996696619">"Tres barras de cobertura"</string>
+    <string name="accessibility_phone_signal_full" msgid="4302338883816077134">"Cobertura al máximo"</string>
+    <string name="accessibility_no_data" msgid="4563181886936931008">"Sin datos"</string>
+    <string name="accessibility_data_one_bar" msgid="6892888138070752480">"Una barra de datos"</string>
+    <string name="accessibility_data_two_bars" msgid="9202641507241802499">"Dos barras de datos"</string>
+    <string name="accessibility_data_three_bars" msgid="2813876214466722413">"Tres barras de datos"</string>
+    <string name="accessibility_data_signal_full" msgid="1808301899314382337">"Señal de datos al máximo"</string>
+    <string name="accessibility_ethernet_disconnected" msgid="2832501530856497489">"Conexión Ethernet desconectada."</string>
+    <string name="accessibility_ethernet_connected" msgid="2093872142317190618">"Conexión Ethernet conectada."</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-et/strings.xml b/packages/SettingsLib/res/values-et/strings.xml
index 4b82c08..c8fd94f 100644
--- a/packages/SettingsLib/res/values-et/strings.xml
+++ b/packages/SettingsLib/res/values-et/strings.xml
@@ -403,7 +403,6 @@
     <string name="transcode_user_control" msgid="6176368544817731314">"Alista transkodeerimise vaikeseaded"</string>
     <string name="transcode_enable_all" msgid="2411165920039166710">"Luba transkodeerimine"</string>
     <string name="transcode_default" msgid="3784803084573509491">"Oleta, et rakendused toetavad kaasaegseid vorminguid"</string>
-    <string name="transcode_skip_apps" msgid="8249721984597390142">"Luba rakenduste puhul transkodeerimine"</string>
     <string name="runningservices_settings_title" msgid="6460099290493086515">"Käitatud teenused"</string>
     <string name="runningservices_settings_summary" msgid="1046080643262665743">"Praegu käitatud teenuste vaatamine ja juhtimine"</string>
     <string name="select_webview_provider_title" msgid="3917815648099445503">"WebView\' rakendamine"</string>
@@ -566,4 +565,29 @@
     <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Juhtmega kõrvaklapid"</string>
     <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Sees"</string>
     <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Väljas"</string>
+    <string name="carrier_network_change_mode" msgid="4257621815706644026">"Operaatori võrku muudetakse"</string>
+    <string name="data_connection_3g" msgid="931852552688157407">"3G"</string>
+    <string name="data_connection_edge" msgid="4625509456544797637">"EDGE"</string>
+    <string name="data_connection_cdma" msgid="9098161966701934334">"1X"</string>
+    <string name="data_connection_gprs" msgid="1251945769006770189">"GPRS"</string>
+    <string name="data_connection_3_5g" msgid="4298721462047921400">"H"</string>
+    <string name="data_connection_3_5g_plus" msgid="6683055858295918170">"H+"</string>
+    <string name="data_connection_4g" msgid="2581705503356752044">"4G"</string>
+    <string name="data_connection_4g_plus" msgid="5194902328408751020">"4G+"</string>
+    <string name="data_connection_lte" msgid="7675461204366364124">"LTE"</string>
+    <string name="data_connection_lte_plus" msgid="6643158654804916653">"LTE+"</string>
+    <string name="cell_data_off_content_description" msgid="2280700839891636498">"Mobiilne andmeside on väljas"</string>
+    <string name="not_default_data_content_description" msgid="6517068332106592887">"Ei ole andmeside kasutamiseks seadistatud"</string>
+    <string name="accessibility_no_phone" msgid="2687419663127582503">"Telefonisignaal puudub"</string>
+    <string name="accessibility_phone_one_bar" msgid="5719721147018970063">"Telefonisignaal: üks pulk."</string>
+    <string name="accessibility_phone_two_bars" msgid="2531458337458953263">"Telefonisignaal: kaks pulka."</string>
+    <string name="accessibility_phone_three_bars" msgid="1523967995996696619">"Telefonisignaal: kolm pulka."</string>
+    <string name="accessibility_phone_signal_full" msgid="4302338883816077134">"Telefonisignaal on tugev."</string>
+    <string name="accessibility_no_data" msgid="4563181886936931008">"Andmed puuduvad."</string>
+    <string name="accessibility_data_one_bar" msgid="6892888138070752480">"Andmesignaal: üks pulk."</string>
+    <string name="accessibility_data_two_bars" msgid="9202641507241802499">"Andmeside: kaks pulka."</string>
+    <string name="accessibility_data_three_bars" msgid="2813876214466722413">"Andmeside: kolm pulka."</string>
+    <string name="accessibility_data_signal_full" msgid="1808301899314382337">"Andmesignaal on tugev."</string>
+    <string name="accessibility_ethernet_disconnected" msgid="2832501530856497489">"Etherneti-ühendus on katkestatud."</string>
+    <string name="accessibility_ethernet_connected" msgid="2093872142317190618">"Etherneti-ühendus on loodud."</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-eu/strings.xml b/packages/SettingsLib/res/values-eu/strings.xml
index 37c1fd8..226ffba 100644
--- a/packages/SettingsLib/res/values-eu/strings.xml
+++ b/packages/SettingsLib/res/values-eu/strings.xml
@@ -403,7 +403,6 @@
     <string name="transcode_user_control" msgid="6176368544817731314">"Ez erabili transkodetzearen balio lehenetsiak"</string>
     <string name="transcode_enable_all" msgid="2411165920039166710">"Gaitu transkodetzea"</string>
     <string name="transcode_default" msgid="3784803084573509491">"Arduratu aplikazioek formatu modernoak onartzeaz"</string>
-    <string name="transcode_skip_apps" msgid="8249721984597390142">"Gaitu aplikazioak transkodetzeko aukera"</string>
     <string name="runningservices_settings_title" msgid="6460099290493086515">"Abian diren zerbitzuak"</string>
     <string name="runningservices_settings_summary" msgid="1046080643262665743">"Ikusi eta kontrolatu une honetan abian diren zerbitzuak"</string>
     <string name="select_webview_provider_title" msgid="3917815648099445503">"WebView inplementazioa"</string>
@@ -566,4 +565,29 @@
     <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Entzungailu kableduna"</string>
     <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Aktibatu"</string>
     <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Desaktibatu"</string>
+    <string name="carrier_network_change_mode" msgid="4257621815706644026">"Operadorearen sarea aldatzen"</string>
+    <string name="data_connection_3g" msgid="931852552688157407">"3G"</string>
+    <string name="data_connection_edge" msgid="4625509456544797637">"EDGE"</string>
+    <string name="data_connection_cdma" msgid="9098161966701934334">"1X"</string>
+    <string name="data_connection_gprs" msgid="1251945769006770189">"GPRS"</string>
+    <string name="data_connection_3_5g" msgid="4298721462047921400">"H"</string>
+    <string name="data_connection_3_5g_plus" msgid="6683055858295918170">"H+"</string>
+    <string name="data_connection_4g" msgid="2581705503356752044">"4G"</string>
+    <string name="data_connection_4g_plus" msgid="5194902328408751020">"4G+"</string>
+    <string name="data_connection_lte" msgid="7675461204366364124">"LTE"</string>
+    <string name="data_connection_lte_plus" msgid="6643158654804916653">"LTE+"</string>
+    <string name="cell_data_off_content_description" msgid="2280700839891636498">"Desaktibatuta dago datu-konexioa"</string>
+    <string name="not_default_data_content_description" msgid="6517068332106592887">"Ez dago ezarrita datuak erabiltzeko"</string>
+    <string name="accessibility_no_phone" msgid="2687419663127582503">"Ez dago telefono-zenbakirik."</string>
+    <string name="accessibility_phone_one_bar" msgid="5719721147018970063">"Telefono-seinaleak barra bat du."</string>
+    <string name="accessibility_phone_two_bars" msgid="2531458337458953263">"Telefono-seinaleak bi barra ditu."</string>
+    <string name="accessibility_phone_three_bars" msgid="1523967995996696619">"Telefono-seinaleak hiru barra ditu."</string>
+    <string name="accessibility_phone_signal_full" msgid="4302338883816077134">"Telefono-seinale osoa."</string>
+    <string name="accessibility_no_data" msgid="4563181886936931008">"Ez dago daturik."</string>
+    <string name="accessibility_data_one_bar" msgid="6892888138070752480">"Datu-seinaleak barra bat du."</string>
+    <string name="accessibility_data_two_bars" msgid="9202641507241802499">"Datu-seinaleak bi barra ditu."</string>
+    <string name="accessibility_data_three_bars" msgid="2813876214466722413">"Datu-seinaleak hiru barra ditu."</string>
+    <string name="accessibility_data_signal_full" msgid="1808301899314382337">"Datu-seinale osoa."</string>
+    <string name="accessibility_ethernet_disconnected" msgid="2832501530856497489">"Ethernet bidezko konexioa eten da."</string>
+    <string name="accessibility_ethernet_connected" msgid="2093872142317190618">"Ethernet bidez konektatu da."</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-fa/strings.xml b/packages/SettingsLib/res/values-fa/strings.xml
index 7d20aaf..917a637 100644
--- a/packages/SettingsLib/res/values-fa/strings.xml
+++ b/packages/SettingsLib/res/values-fa/strings.xml
@@ -403,7 +403,6 @@
     <string name="transcode_user_control" msgid="6176368544817731314">"ملغی کردن پیش‌فرض‌های تراتبدیل"</string>
     <string name="transcode_enable_all" msgid="2411165920039166710">"فعال کردن تراتبدیل"</string>
     <string name="transcode_default" msgid="3784803084573509491">"فرض شود برنامه‌ها از قالب‌های مدرن پشتیبانی می‌کنند"</string>
-    <string name="transcode_skip_apps" msgid="8249721984597390142">"فعال کردن تراتبدیل برای برنامه‌ها"</string>
     <string name="runningservices_settings_title" msgid="6460099290493086515">"سرویس‌های در حال اجرا"</string>
     <string name="runningservices_settings_summary" msgid="1046080643262665743">"مشاهده و کنترل سرویس‌های در حال اجرای فعلی"</string>
     <string name="select_webview_provider_title" msgid="3917815648099445503">"اجرای وب‌نما"</string>
@@ -566,4 +565,29 @@
     <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"هدفون سیمی"</string>
     <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"روشن"</string>
     <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"خاموش"</string>
+    <string name="carrier_network_change_mode" msgid="4257621815706644026">"تغییر شبکه شرکت مخابراتی"</string>
+    <string name="data_connection_3g" msgid="931852552688157407">"3G"</string>
+    <string name="data_connection_edge" msgid="4625509456544797637">"EDGE"</string>
+    <string name="data_connection_cdma" msgid="9098161966701934334">"1X"</string>
+    <string name="data_connection_gprs" msgid="1251945769006770189">"GPRS"</string>
+    <string name="data_connection_3_5g" msgid="4298721462047921400">"H"</string>
+    <string name="data_connection_3_5g_plus" msgid="6683055858295918170">"H+‎"</string>
+    <string name="data_connection_4g" msgid="2581705503356752044">"4G"</string>
+    <string name="data_connection_4g_plus" msgid="5194902328408751020">"4G+‎"</string>
+    <string name="data_connection_lte" msgid="7675461204366364124">"LTE"</string>
+    <string name="data_connection_lte_plus" msgid="6643158654804916653">"LTE+‎"</string>
+    <string name="cell_data_off_content_description" msgid="2280700839891636498">"داده تلفن همراه خاموش است"</string>
+    <string name="not_default_data_content_description" msgid="6517068332106592887">"برای استفاده از داده تنظیم نشده است"</string>
+    <string name="accessibility_no_phone" msgid="2687419663127582503">"بدون تلفن."</string>
+    <string name="accessibility_phone_one_bar" msgid="5719721147018970063">"یک نوار برای تلفن."</string>
+    <string name="accessibility_phone_two_bars" msgid="2531458337458953263">"دو نوار برای تلفن."</string>
+    <string name="accessibility_phone_three_bars" msgid="1523967995996696619">"سه نوار برای تلفن."</string>
+    <string name="accessibility_phone_signal_full" msgid="4302338883816077134">"قدرت امواج تلفن همراه کامل است."</string>
+    <string name="accessibility_no_data" msgid="4563181886936931008">"داده‌ای وجود ندارد."</string>
+    <string name="accessibility_data_one_bar" msgid="6892888138070752480">"یک نوار برای داده."</string>
+    <string name="accessibility_data_two_bars" msgid="9202641507241802499">"دو نوار برای داده."</string>
+    <string name="accessibility_data_three_bars" msgid="2813876214466722413">"سه نوار برای داده."</string>
+    <string name="accessibility_data_signal_full" msgid="1808301899314382337">"قدرت سیگنال داده کامل است."</string>
+    <string name="accessibility_ethernet_disconnected" msgid="2832501530856497489">"اترنت قطع شد."</string>
+    <string name="accessibility_ethernet_connected" msgid="2093872142317190618">"اترنت متصل شد."</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-fi/strings.xml b/packages/SettingsLib/res/values-fi/strings.xml
index a43c5d7..6081b2a 100644
--- a/packages/SettingsLib/res/values-fi/strings.xml
+++ b/packages/SettingsLib/res/values-fi/strings.xml
@@ -403,7 +403,6 @@
     <string name="transcode_user_control" msgid="6176368544817731314">"Ohita transkoodauksen oletukset"</string>
     <string name="transcode_enable_all" msgid="2411165920039166710">"Salli transkoodaus"</string>
     <string name="transcode_default" msgid="3784803084573509491">"Oleta, että sovellukset tukevat nykyaikaisia formaatteja"</string>
-    <string name="transcode_skip_apps" msgid="8249721984597390142">"Ota sovellusten transkoodaus käyttöön"</string>
     <string name="runningservices_settings_title" msgid="6460099290493086515">"Käynnissä olevat palvelut"</string>
     <string name="runningservices_settings_summary" msgid="1046080643262665743">"Tarkastele ja hallitse käynnissä olevia palveluita."</string>
     <string name="select_webview_provider_title" msgid="3917815648099445503">"WebView-käyttöönotto"</string>
@@ -566,4 +565,29 @@
     <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Langalliset kuulokkeet"</string>
     <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Päällä"</string>
     <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Poissa päältä"</string>
+    <string name="carrier_network_change_mode" msgid="4257621815706644026">"Operaattorin verkko muuttuu"</string>
+    <string name="data_connection_3g" msgid="931852552688157407">"3G"</string>
+    <string name="data_connection_edge" msgid="4625509456544797637">"EDGE"</string>
+    <string name="data_connection_cdma" msgid="9098161966701934334">"1X"</string>
+    <string name="data_connection_gprs" msgid="1251945769006770189">"GPRS"</string>
+    <string name="data_connection_3_5g" msgid="4298721462047921400">"H"</string>
+    <string name="data_connection_3_5g_plus" msgid="6683055858295918170">"H+"</string>
+    <string name="data_connection_4g" msgid="2581705503356752044">"4G"</string>
+    <string name="data_connection_4g_plus" msgid="5194902328408751020">"4G+"</string>
+    <string name="data_connection_lte" msgid="7675461204366364124">"LTE"</string>
+    <string name="data_connection_lte_plus" msgid="6643158654804916653">"LTE+"</string>
+    <string name="cell_data_off_content_description" msgid="2280700839891636498">"Mobiilidata poistettu käytöstä"</string>
+    <string name="not_default_data_content_description" msgid="6517068332106592887">"Ei käytä dataa"</string>
+    <string name="accessibility_no_phone" msgid="2687419663127582503">"Ei puhelinverkkoyhteyttä."</string>
+    <string name="accessibility_phone_one_bar" msgid="5719721147018970063">"Puhelinverkkosignaali - yksi palkki."</string>
+    <string name="accessibility_phone_two_bars" msgid="2531458337458953263">"Puhelinverkkosignaali - kaksi palkkia."</string>
+    <string name="accessibility_phone_three_bars" msgid="1523967995996696619">"Puhelinverkkosignaali - kolme palkkia."</string>
+    <string name="accessibility_phone_signal_full" msgid="4302338883816077134">"Vahva puhelinverkkosignaali."</string>
+    <string name="accessibility_no_data" msgid="4563181886936931008">"Ei datasignaalia."</string>
+    <string name="accessibility_data_one_bar" msgid="6892888138070752480">"Datasignaali - yksi palkki."</string>
+    <string name="accessibility_data_two_bars" msgid="9202641507241802499">"Datasignaali - kaksi palkkia."</string>
+    <string name="accessibility_data_three_bars" msgid="2813876214466722413">"Datasignaali - kolme palkkia"</string>
+    <string name="accessibility_data_signal_full" msgid="1808301899314382337">"Vahva kuuluvuus."</string>
+    <string name="accessibility_ethernet_disconnected" msgid="2832501530856497489">"Ethernet on irrotettu."</string>
+    <string name="accessibility_ethernet_connected" msgid="2093872142317190618">"Ethernet on yhdistetty."</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-fr-rCA/strings.xml b/packages/SettingsLib/res/values-fr-rCA/strings.xml
index 0cb7b17..91d14d4 100644
--- a/packages/SettingsLib/res/values-fr-rCA/strings.xml
+++ b/packages/SettingsLib/res/values-fr-rCA/strings.xml
@@ -403,7 +403,6 @@
     <string name="transcode_user_control" msgid="6176368544817731314">"Remplacer les valeurs par défaut de transcodage"</string>
     <string name="transcode_enable_all" msgid="2411165920039166710">"Activer le transcodage"</string>
     <string name="transcode_default" msgid="3784803084573509491">"Présumer que les applications prennent en charge les formats modernes"</string>
-    <string name="transcode_skip_apps" msgid="8249721984597390142">"Activer le transcodage pour les applications"</string>
     <string name="runningservices_settings_title" msgid="6460099290493086515">"Services en cours d\'exécution"</string>
     <string name="runningservices_settings_summary" msgid="1046080643262665743">"Afficher et contrôler les services en cours d\'exécution"</string>
     <string name="select_webview_provider_title" msgid="3917815648099445503">"Mise en œuvre WebView"</string>
@@ -494,7 +493,6 @@
     <string name="wifi_status_mac_randomized" msgid="466382542497832189">"Les adresses MAC sont randomisées"</string>
     <plurals name="wifi_tether_connected_summary" formatted="false" msgid="6317236306047306139">
       <item quantity="one">%1$d appareil connecté</item>
-      <item quantity="many">%1$d devices connected</item>
       <item quantity="other">%1$d appareils connectés</item>
     </plurals>
     <string name="accessibility_manual_zen_more_time" msgid="5141801092071134235">"Plus longtemps."</string>
@@ -567,4 +565,29 @@
     <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Écouteurs filaires"</string>
     <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Activé"</string>
     <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Désactivé"</string>
+    <string name="carrier_network_change_mode" msgid="4257621815706644026">"Changer de réseau de fournisseur de services"</string>
+    <string name="data_connection_3g" msgid="931852552688157407">"3G"</string>
+    <string name="data_connection_edge" msgid="4625509456544797637">"EDGE"</string>
+    <string name="data_connection_cdma" msgid="9098161966701934334">"1X"</string>
+    <string name="data_connection_gprs" msgid="1251945769006770189">"GPRS"</string>
+    <string name="data_connection_3_5g" msgid="4298721462047921400">"H"</string>
+    <string name="data_connection_3_5g_plus" msgid="6683055858295918170">"H+"</string>
+    <string name="data_connection_4g" msgid="2581705503356752044">"4G"</string>
+    <string name="data_connection_4g_plus" msgid="5194902328408751020">"4G+"</string>
+    <string name="data_connection_lte" msgid="7675461204366364124">"LTE"</string>
+    <string name="data_connection_lte_plus" msgid="6643158654804916653">"LTE+"</string>
+    <string name="cell_data_off_content_description" msgid="2280700839891636498">"Désactivées"</string>
+    <string name="not_default_data_content_description" msgid="6517068332106592887">"Non configuré pour l\'utilisation des données cellulaires"</string>
+    <string name="accessibility_no_phone" msgid="2687419663127582503">"Aucun signal"</string>
+    <string name="accessibility_phone_one_bar" msgid="5719721147018970063">"Signal : faible"</string>
+    <string name="accessibility_phone_two_bars" msgid="2531458337458953263">"Signal : moyen"</string>
+    <string name="accessibility_phone_three_bars" msgid="1523967995996696619">"Signal : bon"</string>
+    <string name="accessibility_phone_signal_full" msgid="4302338883816077134">"Signal excellent"</string>
+    <string name="accessibility_no_data" msgid="4563181886936931008">"Aucun signal"</string>
+    <string name="accessibility_data_one_bar" msgid="6892888138070752480">"Signal faible"</string>
+    <string name="accessibility_data_two_bars" msgid="9202641507241802499">"Signal moyen"</string>
+    <string name="accessibility_data_three_bars" msgid="2813876214466722413">"Signal bon"</string>
+    <string name="accessibility_data_signal_full" msgid="1808301899314382337">"Signal excellent"</string>
+    <string name="accessibility_ethernet_disconnected" msgid="2832501530856497489">"Ethernet déconnecté."</string>
+    <string name="accessibility_ethernet_connected" msgid="2093872142317190618">"Ethernet connecté."</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-fr/strings.xml b/packages/SettingsLib/res/values-fr/strings.xml
index e928a48..2518fe1 100644
--- a/packages/SettingsLib/res/values-fr/strings.xml
+++ b/packages/SettingsLib/res/values-fr/strings.xml
@@ -251,7 +251,7 @@
     <string name="wifi_display_certification" msgid="1805579519992520381">"Certification affichage sans fil"</string>
     <string name="wifi_verbose_logging" msgid="1785910450009679371">"Autoriser l\'enregistrement d\'infos Wi-Fi détaillées"</string>
     <string name="wifi_scan_throttling" msgid="2985624788509913617">"Limiter la recherche Wi‑Fi"</string>
-    <string name="wifi_enhanced_mac_randomization" msgid="5437378364995776979">"Chgt aléatoire d\'adresse MAC en Wi-Fi"</string>
+    <string name="wifi_enhanced_mac_randomization" msgid="5437378364995776979">"Changement aléatoire d\'adresse MAC en Wi-Fi"</string>
     <string name="mobile_data_always_on" msgid="8275958101875563572">"Données mobiles toujours actives"</string>
     <string name="tethering_hardware_offload" msgid="4116053719006939161">"Accélération matérielle pour le partage de connexion"</string>
     <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Afficher les appareils Bluetooth sans nom"</string>
@@ -403,7 +403,6 @@
     <string name="transcode_user_control" msgid="6176368544817731314">"Ignorer les paramètres de transcodage par défaut"</string>
     <string name="transcode_enable_all" msgid="2411165920039166710">"Activer le transcodage"</string>
     <string name="transcode_default" msgid="3784803084573509491">"Supposer que les applications sont compatibles avec les formats modernes"</string>
-    <string name="transcode_skip_apps" msgid="8249721984597390142">"Activer le transcodage pour les applications"</string>
     <string name="runningservices_settings_title" msgid="6460099290493086515">"Services en cours d\'exécution"</string>
     <string name="runningservices_settings_summary" msgid="1046080643262665743">"Afficher et contrôler les services en cours d\'exécution"</string>
     <string name="select_webview_provider_title" msgid="3917815648099445503">"Mise en œuvre WebView"</string>
@@ -494,7 +493,6 @@
     <string name="wifi_status_mac_randomized" msgid="466382542497832189">"La sélection des adresses MAC est aléatoire"</string>
     <plurals name="wifi_tether_connected_summary" formatted="false" msgid="6317236306047306139">
       <item quantity="one">%1$d appareil connecté</item>
-      <item quantity="many">%1$d devices connected</item>
       <item quantity="other">%1$d appareils connectés</item>
     </plurals>
     <string name="accessibility_manual_zen_more_time" msgid="5141801092071134235">"Plus longtemps."</string>
@@ -567,4 +565,29 @@
     <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Casque filaire"</string>
     <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Allumé"</string>
     <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Éteint"</string>
+    <string name="carrier_network_change_mode" msgid="4257621815706644026">"Modification du réseau de l\'opérateur"</string>
+    <string name="data_connection_3g" msgid="931852552688157407">"3G"</string>
+    <string name="data_connection_edge" msgid="4625509456544797637">"EDGE"</string>
+    <string name="data_connection_cdma" msgid="9098161966701934334">"1X"</string>
+    <string name="data_connection_gprs" msgid="1251945769006770189">"GPRS"</string>
+    <string name="data_connection_3_5g" msgid="4298721462047921400">"H"</string>
+    <string name="data_connection_3_5g_plus" msgid="6683055858295918170">"H+"</string>
+    <string name="data_connection_4g" msgid="2581705503356752044">"4G"</string>
+    <string name="data_connection_4g_plus" msgid="5194902328408751020">"4G+"</string>
+    <string name="data_connection_lte" msgid="7675461204366364124">"LTE"</string>
+    <string name="data_connection_lte_plus" msgid="6643158654804916653">"LTE+"</string>
+    <string name="cell_data_off_content_description" msgid="2280700839891636498">"Désactivées"</string>
+    <string name="not_default_data_content_description" msgid="6517068332106592887">"Non configuré pour utiliser les données"</string>
+    <string name="accessibility_no_phone" msgid="2687419663127582503">"Aucun signal"</string>
+    <string name="accessibility_phone_one_bar" msgid="5719721147018970063">"Signal : faible"</string>
+    <string name="accessibility_phone_two_bars" msgid="2531458337458953263">"Signal : moyen"</string>
+    <string name="accessibility_phone_three_bars" msgid="1523967995996696619">"Signal : bon"</string>
+    <string name="accessibility_phone_signal_full" msgid="4302338883816077134">"Signal excellent"</string>
+    <string name="accessibility_no_data" msgid="4563181886936931008">"Aucun signal"</string>
+    <string name="accessibility_data_one_bar" msgid="6892888138070752480">"Signal faible"</string>
+    <string name="accessibility_data_two_bars" msgid="9202641507241802499">"Signal moyen"</string>
+    <string name="accessibility_data_three_bars" msgid="2813876214466722413">"Signal bon"</string>
+    <string name="accessibility_data_signal_full" msgid="1808301899314382337">"Signal excellent"</string>
+    <string name="accessibility_ethernet_disconnected" msgid="2832501530856497489">"Ethernet déconnecté"</string>
+    <string name="accessibility_ethernet_connected" msgid="2093872142317190618">"Ethernet connecté"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-gl/strings.xml b/packages/SettingsLib/res/values-gl/strings.xml
index c439253..486afe3 100644
--- a/packages/SettingsLib/res/values-gl/strings.xml
+++ b/packages/SettingsLib/res/values-gl/strings.xml
@@ -403,7 +403,6 @@
     <string name="transcode_user_control" msgid="6176368544817731314">"Anular valores predeterminados de transcodificación"</string>
     <string name="transcode_enable_all" msgid="2411165920039166710">"Activar transcodificación"</string>
     <string name="transcode_default" msgid="3784803084573509491">"Considerar que as aplicacións admiten formatos modernos"</string>
-    <string name="transcode_skip_apps" msgid="8249721984597390142">"Activar transcodificación para as aplicacións"</string>
     <string name="runningservices_settings_title" msgid="6460099290493086515">"Servizos en uso"</string>
     <string name="runningservices_settings_summary" msgid="1046080643262665743">"Comproba e controla os servizos actualmente en uso"</string>
     <string name="select_webview_provider_title" msgid="3917815648099445503">"Implementación de WebView"</string>
@@ -566,4 +565,29 @@
     <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Auriculares con cable"</string>
     <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Activar"</string>
     <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Desactivar"</string>
+    <string name="carrier_network_change_mode" msgid="4257621815706644026">"Cambio de rede do operador"</string>
+    <string name="data_connection_3g" msgid="931852552688157407">"3G"</string>
+    <string name="data_connection_edge" msgid="4625509456544797637">"EDGE"</string>
+    <string name="data_connection_cdma" msgid="9098161966701934334">"1X"</string>
+    <string name="data_connection_gprs" msgid="1251945769006770189">"GPRS"</string>
+    <string name="data_connection_3_5g" msgid="4298721462047921400">"H"</string>
+    <string name="data_connection_3_5g_plus" msgid="6683055858295918170">"H+"</string>
+    <string name="data_connection_4g" msgid="2581705503356752044">"4G"</string>
+    <string name="data_connection_4g_plus" msgid="5194902328408751020">"4G+"</string>
+    <string name="data_connection_lte" msgid="7675461204366364124">"LTE"</string>
+    <string name="data_connection_lte_plus" msgid="6643158654804916653">"LTE+"</string>
+    <string name="cell_data_off_content_description" msgid="2280700839891636498">"Os datos móbiles están desactivados"</string>
+    <string name="not_default_data_content_description" msgid="6517068332106592887">"Non se configurou para utilizar datos"</string>
+    <string name="accessibility_no_phone" msgid="2687419663127582503">"Sen teléfono"</string>
+    <string name="accessibility_phone_one_bar" msgid="5719721147018970063">"Unha barra de cobertura"</string>
+    <string name="accessibility_phone_two_bars" msgid="2531458337458953263">"Dúas barras de cobertura"</string>
+    <string name="accessibility_phone_three_bars" msgid="1523967995996696619">"Tres barras de cobertura"</string>
+    <string name="accessibility_phone_signal_full" msgid="4302338883816077134">"Cobertura ao máximo"</string>
+    <string name="accessibility_no_data" msgid="4563181886936931008">"Sen datos"</string>
+    <string name="accessibility_data_one_bar" msgid="6892888138070752480">"Unha barra de sinal de datos"</string>
+    <string name="accessibility_data_two_bars" msgid="9202641507241802499">"Sinal de datos: dúas barras"</string>
+    <string name="accessibility_data_three_bars" msgid="2813876214466722413">"Tres barras de sinal de datos"</string>
+    <string name="accessibility_data_signal_full" msgid="1808301899314382337">"Sinal de datos: completo"</string>
+    <string name="accessibility_ethernet_disconnected" msgid="2832501530856497489">"Desconectouse a Ethernet."</string>
+    <string name="accessibility_ethernet_connected" msgid="2093872142317190618">"Conectouse a Ethernet."</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-gu/strings.xml b/packages/SettingsLib/res/values-gu/strings.xml
index 7dfdcee..2bebe36 100644
--- a/packages/SettingsLib/res/values-gu/strings.xml
+++ b/packages/SettingsLib/res/values-gu/strings.xml
@@ -400,13 +400,9 @@
     <string name="inactive_app_active_summary" msgid="8047630990208722344">"સક્રિય. ટોગલ કરવા માટે ટૅપ કરો."</string>
     <string name="standby_bucket_summary" msgid="5128193447550429600">"ઍપ સ્ટૅન્ડબાયની સ્થિતિ:<xliff:g id="BUCKET"> %s</xliff:g>"</string>
     <string name="transcode_settings_title" msgid="2581975870429850549">"મીડિયાનું ફૉર્મેટ બદલવાની પ્રક્રિયાના સેટિંગ"</string>
-    <!-- no translation found for transcode_user_control (6176368544817731314) -->
-    <skip />
-    <!-- no translation found for transcode_enable_all (2411165920039166710) -->
-    <skip />
-    <!-- no translation found for transcode_default (3784803084573509491) -->
-    <skip />
-    <string name="transcode_skip_apps" msgid="8249721984597390142">"ઍપ માટે ફૉર્મેટ બદલવાની પ્રક્રિયા ચાલુ કરો"</string>
+    <string name="transcode_user_control" msgid="6176368544817731314">"ફૉર્મેટ બદલવાની પ્રક્રિયાના ડિફૉલ્ટ સેટિંગ ઓવરરાઇડ કરો"</string>
+    <string name="transcode_enable_all" msgid="2411165920039166710">"ફૉર્મેટ બદલવાની પ્રક્રિયા ચાલુ કરો"</string>
+    <string name="transcode_default" msgid="3784803084573509491">"ધારો કે ઍપ આધુનિક ફૉર્મેટ પર કામ કરે છે"</string>
     <string name="runningservices_settings_title" msgid="6460099290493086515">"ચાલુ સેવાઓ"</string>
     <string name="runningservices_settings_summary" msgid="1046080643262665743">"હાલમાં ચાલતી સેવાઓ જુઓ અને નિયંત્રિત કરો"</string>
     <string name="select_webview_provider_title" msgid="3917815648099445503">"WebView અમલીકરણ"</string>
@@ -569,4 +565,29 @@
     <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"વાયરવાળો હૅડફોન"</string>
     <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"ચાલુ"</string>
     <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"બંધ"</string>
+    <string name="carrier_network_change_mode" msgid="4257621815706644026">"કૅરીઅર નેટવર્કમાં ફેરફાર થઈ રહ્યો છે"</string>
+    <string name="data_connection_3g" msgid="931852552688157407">"3G"</string>
+    <string name="data_connection_edge" msgid="4625509456544797637">"EDGE"</string>
+    <string name="data_connection_cdma" msgid="9098161966701934334">"1X"</string>
+    <string name="data_connection_gprs" msgid="1251945769006770189">"GPRS"</string>
+    <string name="data_connection_3_5g" msgid="4298721462047921400">"H"</string>
+    <string name="data_connection_3_5g_plus" msgid="6683055858295918170">"H+"</string>
+    <string name="data_connection_4g" msgid="2581705503356752044">"4G"</string>
+    <string name="data_connection_4g_plus" msgid="5194902328408751020">"4G+"</string>
+    <string name="data_connection_lte" msgid="7675461204366364124">"LTE"</string>
+    <string name="data_connection_lte_plus" msgid="6643158654804916653">"LTE+"</string>
+    <string name="cell_data_off_content_description" msgid="2280700839891636498">"મોબાઇલ ડેટા બંધ છે"</string>
+    <string name="not_default_data_content_description" msgid="6517068332106592887">"ડેટાનો ઉપયોગ કરવાનું સેટ કર્યું નથી"</string>
+    <string name="accessibility_no_phone" msgid="2687419663127582503">"કોઈ ફોન નથી."</string>
+    <string name="accessibility_phone_one_bar" msgid="5719721147018970063">"ફોન એક બાર."</string>
+    <string name="accessibility_phone_two_bars" msgid="2531458337458953263">"ફોન બે બાર."</string>
+    <string name="accessibility_phone_three_bars" msgid="1523967995996696619">"ફોન ત્રણ બાર."</string>
+    <string name="accessibility_phone_signal_full" msgid="4302338883816077134">"પૂર્ણ ફોન સિગ્નલ."</string>
+    <string name="accessibility_no_data" msgid="4563181886936931008">"કોઈ ડેટા નથી."</string>
+    <string name="accessibility_data_one_bar" msgid="6892888138070752480">"ડેટા એક બાર."</string>
+    <string name="accessibility_data_two_bars" msgid="9202641507241802499">"ડેટા બે બાર."</string>
+    <string name="accessibility_data_three_bars" msgid="2813876214466722413">"ડેટા ત્રણ બાર."</string>
+    <string name="accessibility_data_signal_full" msgid="1808301899314382337">"ડેટા સિગ્નલ પૂર્ણ."</string>
+    <string name="accessibility_ethernet_disconnected" msgid="2832501530856497489">"ઇથરનેટ ડિસ્કનેક્ટ થયું."</string>
+    <string name="accessibility_ethernet_connected" msgid="2093872142317190618">"ઇથરનેટ કનેક્ટ થયું."</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-hi/strings.xml b/packages/SettingsLib/res/values-hi/strings.xml
index 26d1a756..824ab25 100644
--- a/packages/SettingsLib/res/values-hi/strings.xml
+++ b/packages/SettingsLib/res/values-hi/strings.xml
@@ -402,8 +402,7 @@
     <string name="transcode_settings_title" msgid="2581975870429850549">"मीडिया ट्रांसकोडिंग सेटिंग"</string>
     <string name="transcode_user_control" msgid="6176368544817731314">"ट्रांसकोडिंग की डिफ़ॉल्ट सेटिंग बदलें"</string>
     <string name="transcode_enable_all" msgid="2411165920039166710">"ट्रांसकोडिंग चालू करें"</string>
-    <string name="transcode_default" msgid="3784803084573509491">"मानकर चलें कि ऐप्लिकेशन, मॉडर्न फ़ॉर्मैट के साथ काम करेंगे"</string>
-    <string name="transcode_skip_apps" msgid="8249721984597390142">"ऐप्लिकेशन के लिए ट्रांसकोडिंग चालू करें"</string>
+    <string name="transcode_default" msgid="3784803084573509491">"मानकर चलें कि ऐप्लिकेशन, नए फ़ॉर्मैट के साथ काम करेंगे"</string>
     <string name="runningservices_settings_title" msgid="6460099290493086515">"चल रही सेवाएं"</string>
     <string name="runningservices_settings_summary" msgid="1046080643262665743">"इस समय चल रही सेवाओं को देखें और नियंत्रित करें"</string>
     <string name="select_webview_provider_title" msgid="3917815648099445503">"वेबव्यू लागू करें"</string>
@@ -566,4 +565,29 @@
     <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"वायर वाला हेडफ़ोन"</string>
     <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"चालू है"</string>
     <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"बंद है"</string>
+    <string name="carrier_network_change_mode" msgid="4257621815706644026">"मोबाइल और इंटरनेट सेवा देने वाली कंपनी का नेटवर्क बदल रहा है"</string>
+    <string name="data_connection_3g" msgid="931852552688157407">"3जी"</string>
+    <string name="data_connection_edge" msgid="4625509456544797637">"EDGE"</string>
+    <string name="data_connection_cdma" msgid="9098161966701934334">"1X"</string>
+    <string name="data_connection_gprs" msgid="1251945769006770189">"GPRS"</string>
+    <string name="data_connection_3_5g" msgid="4298721462047921400">"H"</string>
+    <string name="data_connection_3_5g_plus" msgid="6683055858295918170">"H+"</string>
+    <string name="data_connection_4g" msgid="2581705503356752044">"4G"</string>
+    <string name="data_connection_4g_plus" msgid="5194902328408751020">"4G+"</string>
+    <string name="data_connection_lte" msgid="7675461204366364124">"एलटीई"</string>
+    <string name="data_connection_lte_plus" msgid="6643158654804916653">"LTE+"</string>
+    <string name="cell_data_off_content_description" msgid="2280700839891636498">"मोबाइल डेटा बंद है"</string>
+    <string name="not_default_data_content_description" msgid="6517068332106592887">"डेटा इस्तेमाल करने के लिए सेट नहीं किया गया है"</string>
+    <string name="accessibility_no_phone" msgid="2687419663127582503">"कोई फ़ोन नहीं."</string>
+    <string name="accessibility_phone_one_bar" msgid="5719721147018970063">"फ़ोन एक बार."</string>
+    <string name="accessibility_phone_two_bars" msgid="2531458337458953263">"फ़ोन दो बार."</string>
+    <string name="accessibility_phone_three_bars" msgid="1523967995996696619">"फोन तीन बार."</string>
+    <string name="accessibility_phone_signal_full" msgid="4302338883816077134">"फ़ोन सि‍ग्‍नल पूरा."</string>
+    <string name="accessibility_no_data" msgid="4563181886936931008">"कोई डेटा नहीं."</string>
+    <string name="accessibility_data_one_bar" msgid="6892888138070752480">"डेटा एक बार."</string>
+    <string name="accessibility_data_two_bars" msgid="9202641507241802499">"डेटा दो बार."</string>
+    <string name="accessibility_data_three_bars" msgid="2813876214466722413">"डेटा तीन बार."</string>
+    <string name="accessibility_data_signal_full" msgid="1808301899314382337">"डेटा सि‍ग्‍नल पूरा."</string>
+    <string name="accessibility_ethernet_disconnected" msgid="2832501530856497489">"ईथरनेट डिस्‍कनेक्‍ट किया गया."</string>
+    <string name="accessibility_ethernet_connected" msgid="2093872142317190618">"ईथरनेट कनेक्‍ट किया गया."</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-hr/strings.xml b/packages/SettingsLib/res/values-hr/strings.xml
index eccfd7a..cd21a5f 100644
--- a/packages/SettingsLib/res/values-hr/strings.xml
+++ b/packages/SettingsLib/res/values-hr/strings.xml
@@ -403,7 +403,6 @@
     <string name="transcode_user_control" msgid="6176368544817731314">"Nadjačaj zadane postavke konvertiranja"</string>
     <string name="transcode_enable_all" msgid="2411165920039166710">"Omogući konvertiranje"</string>
     <string name="transcode_default" msgid="3784803084573509491">"Pretpostavi da aplikacije podržavaju moderne formate"</string>
-    <string name="transcode_skip_apps" msgid="8249721984597390142">"Omogućivanje konvertiranja za aplikacije"</string>
     <string name="runningservices_settings_title" msgid="6460099290493086515">"Pokrenute usluge"</string>
     <string name="runningservices_settings_summary" msgid="1046080643262665743">"Pregledajte i kontrolirajte pokrenute usluge"</string>
     <string name="select_webview_provider_title" msgid="3917815648099445503">"Implementacija WebViewa"</string>
@@ -567,4 +566,29 @@
     <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Žičane slušalice"</string>
     <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Uključeno"</string>
     <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Isključeno"</string>
+    <string name="carrier_network_change_mode" msgid="4257621815706644026">"Promjena mreže mobilnog operatera"</string>
+    <string name="data_connection_3g" msgid="931852552688157407">"3G"</string>
+    <string name="data_connection_edge" msgid="4625509456544797637">"EDGE"</string>
+    <string name="data_connection_cdma" msgid="9098161966701934334">"1X"</string>
+    <string name="data_connection_gprs" msgid="1251945769006770189">"GPRS"</string>
+    <string name="data_connection_3_5g" msgid="4298721462047921400">"H"</string>
+    <string name="data_connection_3_5g_plus" msgid="6683055858295918170">"H+"</string>
+    <string name="data_connection_4g" msgid="2581705503356752044">"4G"</string>
+    <string name="data_connection_4g_plus" msgid="5194902328408751020">"4G i više"</string>
+    <string name="data_connection_lte" msgid="7675461204366364124">"LTE"</string>
+    <string name="data_connection_lte_plus" msgid="6643158654804916653">"LTE+"</string>
+    <string name="cell_data_off_content_description" msgid="2280700839891636498">"Mobilni su podaci isključeni"</string>
+    <string name="not_default_data_content_description" msgid="6517068332106592887">"Nije postavljeno za upotrebu podataka"</string>
+    <string name="accessibility_no_phone" msgid="2687419663127582503">"Nema telefona."</string>
+    <string name="accessibility_phone_one_bar" msgid="5719721147018970063">"Telefonski signal jedan stupac."</string>
+    <string name="accessibility_phone_two_bars" msgid="2531458337458953263">"Telefonski signal dva stupca."</string>
+    <string name="accessibility_phone_three_bars" msgid="1523967995996696619">"Telefonski signal tri stupca."</string>
+    <string name="accessibility_phone_signal_full" msgid="4302338883816077134">"Telefonski signal pun."</string>
+    <string name="accessibility_no_data" msgid="4563181886936931008">"Nema podataka."</string>
+    <string name="accessibility_data_one_bar" msgid="6892888138070752480">"Podatkovni signal jedan stupac."</string>
+    <string name="accessibility_data_two_bars" msgid="9202641507241802499">"Podatkovni signal dva stupca."</string>
+    <string name="accessibility_data_three_bars" msgid="2813876214466722413">"Podatkovni signal tri stupca."</string>
+    <string name="accessibility_data_signal_full" msgid="1808301899314382337">"Podatkovni signal pun."</string>
+    <string name="accessibility_ethernet_disconnected" msgid="2832501530856497489">"Prekinuta je veza s ethernetom."</string>
+    <string name="accessibility_ethernet_connected" msgid="2093872142317190618">"Uspostavljena je veza s ethernetom."</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-hu/strings.xml b/packages/SettingsLib/res/values-hu/strings.xml
index e5d4bd1..c3b859c 100644
--- a/packages/SettingsLib/res/values-hu/strings.xml
+++ b/packages/SettingsLib/res/values-hu/strings.xml
@@ -403,7 +403,6 @@
     <string name="transcode_user_control" msgid="6176368544817731314">"Az átkódolás alapértelmezett beállításainak felülbírálása"</string>
     <string name="transcode_enable_all" msgid="2411165920039166710">"Átkódolás engedélyezése"</string>
     <string name="transcode_default" msgid="3784803084573509491">"Annak feltételezése, hogy az alkalmazások támogatják a modern formátumokat"</string>
-    <string name="transcode_skip_apps" msgid="8249721984597390142">"Átkódolás engedélyezése az alkalmazásoknál"</string>
     <string name="runningservices_settings_title" msgid="6460099290493086515">"Futó szolgáltatások"</string>
     <string name="runningservices_settings_summary" msgid="1046080643262665743">"A jelenleg futó szolgáltatások megtekintése és vezérlése"</string>
     <string name="select_webview_provider_title" msgid="3917815648099445503">"WebView-megvalósítás"</string>
@@ -566,4 +565,29 @@
     <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Vezetékes fejhallgató"</string>
     <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Be"</string>
     <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Ki"</string>
+    <string name="carrier_network_change_mode" msgid="4257621815706644026">"Szolgáltatói hálózat váltása"</string>
+    <string name="data_connection_3g" msgid="931852552688157407">"3G"</string>
+    <string name="data_connection_edge" msgid="4625509456544797637">"EDGE"</string>
+    <string name="data_connection_cdma" msgid="9098161966701934334">"1X"</string>
+    <string name="data_connection_gprs" msgid="1251945769006770189">"GPRS"</string>
+    <string name="data_connection_3_5g" msgid="4298721462047921400">"H"</string>
+    <string name="data_connection_3_5g_plus" msgid="6683055858295918170">"H+"</string>
+    <string name="data_connection_4g" msgid="2581705503356752044">"4G"</string>
+    <string name="data_connection_4g_plus" msgid="5194902328408751020">"4G+"</string>
+    <string name="data_connection_lte" msgid="7675461204366364124">"LTE"</string>
+    <string name="data_connection_lte_plus" msgid="6643158654804916653">"LTE+"</string>
+    <string name="cell_data_off_content_description" msgid="2280700839891636498">"Mobiladatok kikapcsolva"</string>
+    <string name="not_default_data_content_description" msgid="6517068332106592887">"Nincs beállítva az adathasználat"</string>
+    <string name="accessibility_no_phone" msgid="2687419663127582503">"Nincs telefon."</string>
+    <string name="accessibility_phone_one_bar" msgid="5719721147018970063">"Telefon egy sáv."</string>
+    <string name="accessibility_phone_two_bars" msgid="2531458337458953263">"Telefon két sáv."</string>
+    <string name="accessibility_phone_three_bars" msgid="1523967995996696619">"Telefon három sáv."</string>
+    <string name="accessibility_phone_signal_full" msgid="4302338883816077134">"Telefonjel megtelt."</string>
+    <string name="accessibility_no_data" msgid="4563181886936931008">"Nincsenek adatok."</string>
+    <string name="accessibility_data_one_bar" msgid="6892888138070752480">"Adat egy sáv."</string>
+    <string name="accessibility_data_two_bars" msgid="9202641507241802499">"Adat két sáv."</string>
+    <string name="accessibility_data_three_bars" msgid="2813876214466722413">"Adat három sáv."</string>
+    <string name="accessibility_data_signal_full" msgid="1808301899314382337">"Adatjel teljes."</string>
+    <string name="accessibility_ethernet_disconnected" msgid="2832501530856497489">"Ethernet leválasztva."</string>
+    <string name="accessibility_ethernet_connected" msgid="2093872142317190618">"Ethernet csatlakoztatva."</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-hy/strings.xml b/packages/SettingsLib/res/values-hy/strings.xml
index 53eb766..041ad0e 100644
--- a/packages/SettingsLib/res/values-hy/strings.xml
+++ b/packages/SettingsLib/res/values-hy/strings.xml
@@ -403,7 +403,6 @@
     <string name="transcode_user_control" msgid="6176368544817731314">"Չեղարկել վերակոդավորման կանխադրված կարգավորումները"</string>
     <string name="transcode_enable_all" msgid="2411165920039166710">"Միացնել վերակոդավորումը"</string>
     <string name="transcode_default" msgid="3784803084573509491">"Ենթադրել, որ հավելվածներն աջակցում են ժամանակակից ձևաչափեր"</string>
-    <string name="transcode_skip_apps" msgid="8249721984597390142">"Միացնել վերակոդավորումը հավելվածների համար"</string>
     <string name="runningservices_settings_title" msgid="6460099290493086515">"Աշխատող ծառայություններ"</string>
     <string name="runningservices_settings_summary" msgid="1046080643262665743">"Դիտել և վերահսկել ընթացիկ աշխատող ծառայությունները"</string>
     <string name="select_webview_provider_title" msgid="3917815648099445503">"WebView ծառայություն"</string>
@@ -566,4 +565,29 @@
     <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Լարով ականջակալ"</string>
     <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Միացնել"</string>
     <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Անջատել"</string>
+    <string name="carrier_network_change_mode" msgid="4257621815706644026">"Օպերատորի ցանցի փոփոխություն"</string>
+    <string name="data_connection_3g" msgid="931852552688157407">"3G"</string>
+    <string name="data_connection_edge" msgid="4625509456544797637">"EDGE"</string>
+    <string name="data_connection_cdma" msgid="9098161966701934334">"1X"</string>
+    <string name="data_connection_gprs" msgid="1251945769006770189">"GPRS"</string>
+    <string name="data_connection_3_5g" msgid="4298721462047921400">"H"</string>
+    <string name="data_connection_3_5g_plus" msgid="6683055858295918170">"H+"</string>
+    <string name="data_connection_4g" msgid="2581705503356752044">"4G"</string>
+    <string name="data_connection_4g_plus" msgid="5194902328408751020">"4G+"</string>
+    <string name="data_connection_lte" msgid="7675461204366364124">"LTE"</string>
+    <string name="data_connection_lte_plus" msgid="6643158654804916653">"LTE+"</string>
+    <string name="cell_data_off_content_description" msgid="2280700839891636498">"Բջջային ինտերնետն անջատված է"</string>
+    <string name="not_default_data_content_description" msgid="6517068332106592887">"Բջջային ինտերնետն ըստ կանխադրման չի օգտագործվում"</string>
+    <string name="accessibility_no_phone" msgid="2687419663127582503">"Հեռախոս չկա:"</string>
+    <string name="accessibility_phone_one_bar" msgid="5719721147018970063">"Հեռախոսի մեկ գիծ:"</string>
+    <string name="accessibility_phone_two_bars" msgid="2531458337458953263">"Հեռախոսի երկու գիծ:"</string>
+    <string name="accessibility_phone_three_bars" msgid="1523967995996696619">"Հեռախոսի երեք գիծ:"</string>
+    <string name="accessibility_phone_signal_full" msgid="4302338883816077134">"Հեռախոսի ազդանշանը լիքն է:"</string>
+    <string name="accessibility_no_data" msgid="4563181886936931008">"Տվյալներ չկան:"</string>
+    <string name="accessibility_data_one_bar" msgid="6892888138070752480">"Տվյալների մեկ գիծ:"</string>
+    <string name="accessibility_data_two_bars" msgid="9202641507241802499">"Տվյալների երկու գիծ:"</string>
+    <string name="accessibility_data_three_bars" msgid="2813876214466722413">"Տվյալների երեք գիծ:"</string>
+    <string name="accessibility_data_signal_full" msgid="1808301899314382337">"Տվյալների ազդանշանը լրիվ է:"</string>
+    <string name="accessibility_ethernet_disconnected" msgid="2832501530856497489">"Ethernet-ը անջատված է:"</string>
+    <string name="accessibility_ethernet_connected" msgid="2093872142317190618">"Ethernet-ը կապակցված է:"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-in/strings.xml b/packages/SettingsLib/res/values-in/strings.xml
index edce3c5..69d4582 100644
--- a/packages/SettingsLib/res/values-in/strings.xml
+++ b/packages/SettingsLib/res/values-in/strings.xml
@@ -403,7 +403,6 @@
     <string name="transcode_user_control" msgid="6176368544817731314">"Ganti default transcoding"</string>
     <string name="transcode_enable_all" msgid="2411165920039166710">"Aktifkan transcoding"</string>
     <string name="transcode_default" msgid="3784803084573509491">"Asumsikan aplikasi mendukung format modern"</string>
-    <string name="transcode_skip_apps" msgid="8249721984597390142">"Mengaktifkan transcoding untuk aplikasi"</string>
     <string name="runningservices_settings_title" msgid="6460099290493086515">"Layanan yang sedang berjalan"</string>
     <string name="runningservices_settings_summary" msgid="1046080643262665743">"Melihat dan mengontrol layanan yang sedang berjalan"</string>
     <string name="select_webview_provider_title" msgid="3917815648099445503">"Penerapan WebView"</string>
@@ -566,4 +565,29 @@
     <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Headphone berkabel"</string>
     <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Aktif"</string>
     <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Nonaktif"</string>
+    <string name="carrier_network_change_mode" msgid="4257621815706644026">"Jaringan operator berubah"</string>
+    <string name="data_connection_3g" msgid="931852552688157407">"3G"</string>
+    <string name="data_connection_edge" msgid="4625509456544797637">"EDGE"</string>
+    <string name="data_connection_cdma" msgid="9098161966701934334">"1X"</string>
+    <string name="data_connection_gprs" msgid="1251945769006770189">"GPRS"</string>
+    <string name="data_connection_3_5g" msgid="4298721462047921400">"H"</string>
+    <string name="data_connection_3_5g_plus" msgid="6683055858295918170">"H+"</string>
+    <string name="data_connection_4g" msgid="2581705503356752044">"4G"</string>
+    <string name="data_connection_4g_plus" msgid="5194902328408751020">"4G+"</string>
+    <string name="data_connection_lte" msgid="7675461204366364124">"LTE"</string>
+    <string name="data_connection_lte_plus" msgid="6643158654804916653">"LTE+"</string>
+    <string name="cell_data_off_content_description" msgid="2280700839891636498">"Kuota nonaktif"</string>
+    <string name="not_default_data_content_description" msgid="6517068332106592887">"Tidak disetel untuk menggunakan data"</string>
+    <string name="accessibility_no_phone" msgid="2687419663127582503">"Tidak dapat melakukan panggilan."</string>
+    <string name="accessibility_phone_one_bar" msgid="5719721147018970063">"Ponsel satu batang."</string>
+    <string name="accessibility_phone_two_bars" msgid="2531458337458953263">"Ponsel dua batang."</string>
+    <string name="accessibility_phone_three_bars" msgid="1523967995996696619">"Ponsel tiga batang."</string>
+    <string name="accessibility_phone_signal_full" msgid="4302338883816077134">"Sinyal ponsel penuh."</string>
+    <string name="accessibility_no_data" msgid="4563181886936931008">"Tidak ada data yang diterima."</string>
+    <string name="accessibility_data_one_bar" msgid="6892888138070752480">"Data satu batang."</string>
+    <string name="accessibility_data_two_bars" msgid="9202641507241802499">"Data dua batang."</string>
+    <string name="accessibility_data_three_bars" msgid="2813876214466722413">"Data tiga batang."</string>
+    <string name="accessibility_data_signal_full" msgid="1808301899314382337">"Sinyal data penuh."</string>
+    <string name="accessibility_ethernet_disconnected" msgid="2832501530856497489">"Ethernet terputus."</string>
+    <string name="accessibility_ethernet_connected" msgid="2093872142317190618">"Ethernet tersambung."</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-is/strings.xml b/packages/SettingsLib/res/values-is/strings.xml
index 9e072cc..f401364 100644
--- a/packages/SettingsLib/res/values-is/strings.xml
+++ b/packages/SettingsLib/res/values-is/strings.xml
@@ -403,7 +403,6 @@
     <string name="transcode_user_control" msgid="6176368544817731314">"Hnekkja sjálfgefinni umkóðun"</string>
     <string name="transcode_enable_all" msgid="2411165920039166710">"Kveikja á umkóðun"</string>
     <string name="transcode_default" msgid="3784803084573509491">"Gera ráð fyrir að forrit styðji nútímasnið"</string>
-    <string name="transcode_skip_apps" msgid="8249721984597390142">"Kveikja á umkóðun í forritum"</string>
     <string name="runningservices_settings_title" msgid="6460099290493086515">"Þjónustur í gangi"</string>
     <string name="runningservices_settings_summary" msgid="1046080643262665743">"Skoða og stjórna þjónustum í gangi"</string>
     <string name="select_webview_provider_title" msgid="3917815648099445503">"Innleiðing WebView"</string>
@@ -566,4 +565,29 @@
     <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Heyrnartól með snúru"</string>
     <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Kveikt"</string>
     <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Slökkt"</string>
+    <string name="carrier_network_change_mode" msgid="4257621815706644026">"Skiptir um farsímakerfi"</string>
+    <string name="data_connection_3g" msgid="931852552688157407">"3G"</string>
+    <string name="data_connection_edge" msgid="4625509456544797637">"EDGE"</string>
+    <string name="data_connection_cdma" msgid="9098161966701934334">"1X"</string>
+    <string name="data_connection_gprs" msgid="1251945769006770189">"GPRS"</string>
+    <string name="data_connection_3_5g" msgid="4298721462047921400">"H"</string>
+    <string name="data_connection_3_5g_plus" msgid="6683055858295918170">"H+"</string>
+    <string name="data_connection_4g" msgid="2581705503356752044">"4G"</string>
+    <string name="data_connection_4g_plus" msgid="5194902328408751020">"4G+"</string>
+    <string name="data_connection_lte" msgid="7675461204366364124">"LTE"</string>
+    <string name="data_connection_lte_plus" msgid="6643158654804916653">"LTE+"</string>
+    <string name="cell_data_off_content_description" msgid="2280700839891636498">"Slökkt á farsímagögnum"</string>
+    <string name="not_default_data_content_description" msgid="6517068332106592887">"Ekki stillt á að nota gögn"</string>
+    <string name="accessibility_no_phone" msgid="2687419663127582503">"Ekkert símasamband."</string>
+    <string name="accessibility_phone_one_bar" msgid="5719721147018970063">"Styrkur símasambands er eitt strik."</string>
+    <string name="accessibility_phone_two_bars" msgid="2531458337458953263">"Styrkur símasambands er tvö strik."</string>
+    <string name="accessibility_phone_three_bars" msgid="1523967995996696619">"Styrkur símasambands er þrjú strik."</string>
+    <string name="accessibility_phone_signal_full" msgid="4302338883816077134">"Fullur styrkur símasambands."</string>
+    <string name="accessibility_no_data" msgid="4563181886936931008">"Engin gögn."</string>
+    <string name="accessibility_data_one_bar" msgid="6892888138070752480">"Sendistyrkur gagnatengingar er eitt strik."</string>
+    <string name="accessibility_data_two_bars" msgid="9202641507241802499">"Sendistyrkur gagnatengingar tvö strik."</string>
+    <string name="accessibility_data_three_bars" msgid="2813876214466722413">"Sendistyrkur gagnatengingar er þrjú strik."</string>
+    <string name="accessibility_data_signal_full" msgid="1808301899314382337">"Fullur sendistyrkur gagnatengingar."</string>
+    <string name="accessibility_ethernet_disconnected" msgid="2832501530856497489">"Ethernet aftengt."</string>
+    <string name="accessibility_ethernet_connected" msgid="2093872142317190618">"Ethernet tengt."</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-it/strings.xml b/packages/SettingsLib/res/values-it/strings.xml
index fc87d89..ef5e2ff 100644
--- a/packages/SettingsLib/res/values-it/strings.xml
+++ b/packages/SettingsLib/res/values-it/strings.xml
@@ -403,7 +403,6 @@
     <string name="transcode_user_control" msgid="6176368544817731314">"Sostituisci impostazioni predefinite transcodifica"</string>
     <string name="transcode_enable_all" msgid="2411165920039166710">"Attiva transcodifica"</string>
     <string name="transcode_default" msgid="3784803084573509491">"Presupponi che le app supportino i formati moderni"</string>
-    <string name="transcode_skip_apps" msgid="8249721984597390142">"Attiva transcodifica per le app"</string>
     <string name="runningservices_settings_title" msgid="6460099290493086515">"Servizi in esecuzione"</string>
     <string name="runningservices_settings_summary" msgid="1046080643262665743">"Visualizza e controlla i servizi attualmente in esecuzione"</string>
     <string name="select_webview_provider_title" msgid="3917815648099445503">"Implementazione di WebView"</string>
@@ -566,4 +565,29 @@
     <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Cuffie con cavo"</string>
     <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"On"</string>
     <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Off"</string>
+    <string name="carrier_network_change_mode" msgid="4257621815706644026">"Cambio della rete dell\'operatore"</string>
+    <string name="data_connection_3g" msgid="931852552688157407">"3G"</string>
+    <string name="data_connection_edge" msgid="4625509456544797637">"EDGE"</string>
+    <string name="data_connection_cdma" msgid="9098161966701934334">"1X"</string>
+    <string name="data_connection_gprs" msgid="1251945769006770189">"GPRS"</string>
+    <string name="data_connection_3_5g" msgid="4298721462047921400">"H"</string>
+    <string name="data_connection_3_5g_plus" msgid="6683055858295918170">"H+"</string>
+    <string name="data_connection_4g" msgid="2581705503356752044">"4G"</string>
+    <string name="data_connection_4g_plus" msgid="5194902328408751020">"4G+"</string>
+    <string name="data_connection_lte" msgid="7675461204366364124">"LTE"</string>
+    <string name="data_connection_lte_plus" msgid="6643158654804916653">"LTE+"</string>
+    <string name="cell_data_off_content_description" msgid="2280700839891636498">"Dati mobili disattivati"</string>
+    <string name="not_default_data_content_description" msgid="6517068332106592887">"Non impostato per l\'utilizzo dei dati"</string>
+    <string name="accessibility_no_phone" msgid="2687419663127582503">"Nessun telefono."</string>
+    <string name="accessibility_phone_one_bar" msgid="5719721147018970063">"Telefono: una barra."</string>
+    <string name="accessibility_phone_two_bars" msgid="2531458337458953263">"Telefono: due barre."</string>
+    <string name="accessibility_phone_three_bars" msgid="1523967995996696619">"Telefono: tre barre."</string>
+    <string name="accessibility_phone_signal_full" msgid="4302338883816077134">"Massimo segnale telefonico."</string>
+    <string name="accessibility_no_data" msgid="4563181886936931008">"Nessun dato."</string>
+    <string name="accessibility_data_one_bar" msgid="6892888138070752480">"Dati: una barra."</string>
+    <string name="accessibility_data_two_bars" msgid="9202641507241802499">"Dati: due barre."</string>
+    <string name="accessibility_data_three_bars" msgid="2813876214466722413">"Dati: tre barre."</string>
+    <string name="accessibility_data_signal_full" msgid="1808301899314382337">"Massimo segnale dati."</string>
+    <string name="accessibility_ethernet_disconnected" msgid="2832501530856497489">"Connessione Ethernet annullata."</string>
+    <string name="accessibility_ethernet_connected" msgid="2093872142317190618">"Connessione Ethernet stabilita."</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-iw/strings.xml b/packages/SettingsLib/res/values-iw/strings.xml
index b899b59..4cc6775 100644
--- a/packages/SettingsLib/res/values-iw/strings.xml
+++ b/packages/SettingsLib/res/values-iw/strings.xml
@@ -403,7 +403,6 @@
     <string name="transcode_user_control" msgid="6176368544817731314">"ביטול ברירות המחדל של המרת קידוד"</string>
     <string name="transcode_enable_all" msgid="2411165920039166710">"הפעלת המרת קידוד"</string>
     <string name="transcode_default" msgid="3784803084573509491">"הנחת העבודה היא שאפליקציות תומכות בפורמטים מודרניים"</string>
-    <string name="transcode_skip_apps" msgid="8249721984597390142">"הפעלה של המרת קידוד לאפליקציות"</string>
     <string name="runningservices_settings_title" msgid="6460099290493086515">"שירותים פועלים"</string>
     <string name="runningservices_settings_summary" msgid="1046080643262665743">"הצגת השירותים הפועלים כעת ושליטה בהם"</string>
     <string name="select_webview_provider_title" msgid="3917815648099445503">"‏יישום WebView"</string>
@@ -568,4 +567,29 @@
     <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"אוזניות חוטיות"</string>
     <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"פועלת"</string>
     <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"כבויה"</string>
+    <string name="carrier_network_change_mode" msgid="4257621815706644026">"רשת ספק משתנה"</string>
+    <string name="data_connection_3g" msgid="931852552688157407">"3G"</string>
+    <string name="data_connection_edge" msgid="4625509456544797637">"EDGE"</string>
+    <string name="data_connection_cdma" msgid="9098161966701934334">"1X"</string>
+    <string name="data_connection_gprs" msgid="1251945769006770189">"GPRS"</string>
+    <string name="data_connection_3_5g" msgid="4298721462047921400">"H"</string>
+    <string name="data_connection_3_5g_plus" msgid="6683055858295918170">"+H"</string>
+    <string name="data_connection_4g" msgid="2581705503356752044">"4G"</string>
+    <string name="data_connection_4g_plus" msgid="5194902328408751020">"+4G"</string>
+    <string name="data_connection_lte" msgid="7675461204366364124">"LTE"</string>
+    <string name="data_connection_lte_plus" msgid="6643158654804916653">"+LTE"</string>
+    <string name="cell_data_off_content_description" msgid="2280700839891636498">"חבילת הגלישה כבויה"</string>
+    <string name="not_default_data_content_description" msgid="6517068332106592887">"לא מוגדרת לשימוש בנתונים"</string>
+    <string name="accessibility_no_phone" msgid="2687419663127582503">"אין טלפון."</string>
+    <string name="accessibility_phone_one_bar" msgid="5719721147018970063">"פס אחד של טלפון."</string>
+    <string name="accessibility_phone_two_bars" msgid="2531458337458953263">"שני פסים של טלפון."</string>
+    <string name="accessibility_phone_three_bars" msgid="1523967995996696619">"שלושה פסים של טלפון."</string>
+    <string name="accessibility_phone_signal_full" msgid="4302338883816077134">"אות הטלפון מלא."</string>
+    <string name="accessibility_no_data" msgid="4563181886936931008">"אין נתונים."</string>
+    <string name="accessibility_data_one_bar" msgid="6892888138070752480">"פס אחד של נתונים."</string>
+    <string name="accessibility_data_two_bars" msgid="9202641507241802499">"שני פסים של נתונים."</string>
+    <string name="accessibility_data_three_bars" msgid="2813876214466722413">"שלושה פסים של נתונים."</string>
+    <string name="accessibility_data_signal_full" msgid="1808301899314382337">"אות הנתונים מלא."</string>
+    <string name="accessibility_ethernet_disconnected" msgid="2832501530856497489">"אתרנט מנותק."</string>
+    <string name="accessibility_ethernet_connected" msgid="2093872142317190618">"אתרנט מחובר."</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-ja/strings.xml b/packages/SettingsLib/res/values-ja/strings.xml
index ded207d..9e9db3d 100644
--- a/packages/SettingsLib/res/values-ja/strings.xml
+++ b/packages/SettingsLib/res/values-ja/strings.xml
@@ -403,7 +403,6 @@
     <string name="transcode_user_control" msgid="6176368544817731314">"デフォルトのコード変換をオーバーライド"</string>
     <string name="transcode_enable_all" msgid="2411165920039166710">"コード変換を有効にする"</string>
     <string name="transcode_default" msgid="3784803084573509491">"アプリによる最新形式のサポートを想定"</string>
-    <string name="transcode_skip_apps" msgid="8249721984597390142">"アプリに対しコード変換を有効にする"</string>
     <string name="runningservices_settings_title" msgid="6460099290493086515">"実行中のサービス"</string>
     <string name="runningservices_settings_summary" msgid="1046080643262665743">"現在実行中のサービスを表示して制御する"</string>
     <string name="select_webview_provider_title" msgid="3917815648099445503">"WebView の実装"</string>
@@ -566,4 +565,29 @@
     <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"有線ヘッドフォン"</string>
     <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"ON"</string>
     <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"OFF"</string>
+    <string name="carrier_network_change_mode" msgid="4257621815706644026">"携帯通信会社のネットワークを変更します"</string>
+    <string name="data_connection_3g" msgid="931852552688157407">"3G"</string>
+    <string name="data_connection_edge" msgid="4625509456544797637">"EDGE"</string>
+    <string name="data_connection_cdma" msgid="9098161966701934334">"1X"</string>
+    <string name="data_connection_gprs" msgid="1251945769006770189">"GPRS"</string>
+    <string name="data_connection_3_5g" msgid="4298721462047921400">"H"</string>
+    <string name="data_connection_3_5g_plus" msgid="6683055858295918170">"H+"</string>
+    <string name="data_connection_4g" msgid="2581705503356752044">"4G"</string>
+    <string name="data_connection_4g_plus" msgid="5194902328408751020">"4G+"</string>
+    <string name="data_connection_lte" msgid="7675461204366364124">"LTE"</string>
+    <string name="data_connection_lte_plus" msgid="6643158654804916653">"LTE+"</string>
+    <string name="cell_data_off_content_description" msgid="2280700839891636498">"モバイルデータ OFF"</string>
+    <string name="not_default_data_content_description" msgid="6517068332106592887">"データを使用するように設定されていません"</string>
+    <string name="accessibility_no_phone" msgid="2687419663127582503">"電波状態:なし"</string>
+    <string name="accessibility_phone_one_bar" msgid="5719721147018970063">"電波状態:レベル1"</string>
+    <string name="accessibility_phone_two_bars" msgid="2531458337458953263">"電波状態:レベル2"</string>
+    <string name="accessibility_phone_three_bars" msgid="1523967995996696619">"電波状態:レベル3"</string>
+    <string name="accessibility_phone_signal_full" msgid="4302338883816077134">"電波状態:フル"</string>
+    <string name="accessibility_no_data" msgid="4563181886936931008">"データ信号:なし"</string>
+    <string name="accessibility_data_one_bar" msgid="6892888138070752480">"データ信号:レベル1"</string>
+    <string name="accessibility_data_two_bars" msgid="9202641507241802499">"データ信号:レベル2"</string>
+    <string name="accessibility_data_three_bars" msgid="2813876214466722413">"データ信号:レベル3"</string>
+    <string name="accessibility_data_signal_full" msgid="1808301899314382337">"データ信号:フル"</string>
+    <string name="accessibility_ethernet_disconnected" msgid="2832501530856497489">"イーサネット接続を解除しました。"</string>
+    <string name="accessibility_ethernet_connected" msgid="2093872142317190618">"イーサネットに接続しました。"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-ka/strings.xml b/packages/SettingsLib/res/values-ka/strings.xml
index 2d89dc6..ec39008 100644
--- a/packages/SettingsLib/res/values-ka/strings.xml
+++ b/packages/SettingsLib/res/values-ka/strings.xml
@@ -403,7 +403,6 @@
     <string name="transcode_user_control" msgid="6176368544817731314">"ტრანსკოდირების ნაგულისხმევების უგულებელყოფა"</string>
     <string name="transcode_enable_all" msgid="2411165920039166710">"ტრანსკოდირების ჩართვა"</string>
     <string name="transcode_default" msgid="3784803084573509491">"დაშვება, რომ აპებს აქვთ თანამედროვე ფორმატების მხარდაჭერა"</string>
-    <string name="transcode_skip_apps" msgid="8249721984597390142">"ტრანსკოდირების ჩართვა აპებისთვის"</string>
     <string name="runningservices_settings_title" msgid="6460099290493086515">"მიმდინარე სერვისები"</string>
     <string name="runningservices_settings_summary" msgid="1046080643262665743">"ამჟამად მოქმედი სერვისების ნახვა და მართვა"</string>
     <string name="select_webview_provider_title" msgid="3917815648099445503">"WebView რეალიზაცია"</string>
@@ -566,4 +565,29 @@
     <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"სადენიანი ყურსასმენი"</string>
     <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"ჩართვა"</string>
     <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"გამორთვა"</string>
+    <string name="carrier_network_change_mode" msgid="4257621815706644026">"ოპერატორის ქსელის შეცვლა"</string>
+    <string name="data_connection_3g" msgid="931852552688157407">"3G"</string>
+    <string name="data_connection_edge" msgid="4625509456544797637">"EDGE"</string>
+    <string name="data_connection_cdma" msgid="9098161966701934334">"1X"</string>
+    <string name="data_connection_gprs" msgid="1251945769006770189">"GPRS"</string>
+    <string name="data_connection_3_5g" msgid="4298721462047921400">"H"</string>
+    <string name="data_connection_3_5g_plus" msgid="6683055858295918170">"H+"</string>
+    <string name="data_connection_4g" msgid="2581705503356752044">"4G"</string>
+    <string name="data_connection_4g_plus" msgid="5194902328408751020">"4G+"</string>
+    <string name="data_connection_lte" msgid="7675461204366364124">"LTE"</string>
+    <string name="data_connection_lte_plus" msgid="6643158654804916653">"LTE+"</string>
+    <string name="cell_data_off_content_description" msgid="2280700839891636498">"მობილური ინტერნეტი გამორთულია"</string>
+    <string name="not_default_data_content_description" msgid="6517068332106592887">"არ არის დაყენებული მონაცემების გამოყენებისთვის"</string>
+    <string name="accessibility_no_phone" msgid="2687419663127582503">"ტელეფონი არ არის."</string>
+    <string name="accessibility_phone_one_bar" msgid="5719721147018970063">"ტელეფონის სიგნალი ერთ ზოლზეა."</string>
+    <string name="accessibility_phone_two_bars" msgid="2531458337458953263">"ტელეფონის სიგნალი ორ ზოლზეა."</string>
+    <string name="accessibility_phone_three_bars" msgid="1523967995996696619">"ტელეფონის სიგნალი სამ ზოლზეა."</string>
+    <string name="accessibility_phone_signal_full" msgid="4302338883816077134">"ტელეფონის სიგნალი სრულია."</string>
+    <string name="accessibility_no_data" msgid="4563181886936931008">"მონაცემები არ არის."</string>
+    <string name="accessibility_data_one_bar" msgid="6892888138070752480">"თარიღი ზოლზე."</string>
+    <string name="accessibility_data_two_bars" msgid="9202641507241802499">"მონაცემების გადაცემა: ორი ზოლი"</string>
+    <string name="accessibility_data_three_bars" msgid="2813876214466722413">"მონაცემების გადაცემა: სამი ზოლი"</string>
+    <string name="accessibility_data_signal_full" msgid="1808301899314382337">"მონაცემთა გადაცემის საიმედო სიგნალი."</string>
+    <string name="accessibility_ethernet_disconnected" msgid="2832501530856497489">"Ethernet კავშირი შეწყვეტილია."</string>
+    <string name="accessibility_ethernet_connected" msgid="2093872142317190618">"Ethernet დაკავშირებულია."</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-kk/strings.xml b/packages/SettingsLib/res/values-kk/strings.xml
index fa99529..881a13c 100644
--- a/packages/SettingsLib/res/values-kk/strings.xml
+++ b/packages/SettingsLib/res/values-kk/strings.xml
@@ -403,7 +403,6 @@
     <string name="transcode_user_control" msgid="6176368544817731314">"Қайта қодтаудың әдепкі параметрлерін қайта анықтау"</string>
     <string name="transcode_enable_all" msgid="2411165920039166710">"Қайта кодтауды қосу"</string>
     <string name="transcode_default" msgid="3784803084573509491">"Қолданбалар қазіргі заманғы форматтарды қолдайды делік"</string>
-    <string name="transcode_skip_apps" msgid="8249721984597390142">"Қолданбалар үшін қайта кодтауға рұқсат ету"</string>
     <string name="runningservices_settings_title" msgid="6460099290493086515">"Қосылып тұрған қызметтер"</string>
     <string name="runningservices_settings_summary" msgid="1046080643262665743">"Қазір істеп тұрған қызметтерді көру және басқару"</string>
     <string name="select_webview_provider_title" msgid="3917815648099445503">"WebView қызметі"</string>
@@ -566,4 +565,29 @@
     <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Сымды құлақаспап"</string>
     <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Қосу"</string>
     <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Өшіру"</string>
+    <string name="carrier_network_change_mode" msgid="4257621815706644026">"Оператор желісін өзгерту"</string>
+    <string name="data_connection_3g" msgid="931852552688157407">"3G"</string>
+    <string name="data_connection_edge" msgid="4625509456544797637">"EDGE"</string>
+    <string name="data_connection_cdma" msgid="9098161966701934334">"1X"</string>
+    <string name="data_connection_gprs" msgid="1251945769006770189">"GPRS"</string>
+    <string name="data_connection_3_5g" msgid="4298721462047921400">"H"</string>
+    <string name="data_connection_3_5g_plus" msgid="6683055858295918170">"H+"</string>
+    <string name="data_connection_4g" msgid="2581705503356752044">"4G"</string>
+    <string name="data_connection_4g_plus" msgid="5194902328408751020">"4G+"</string>
+    <string name="data_connection_lte" msgid="7675461204366364124">"LTE"</string>
+    <string name="data_connection_lte_plus" msgid="6643158654804916653">"LTE+"</string>
+    <string name="cell_data_off_content_description" msgid="2280700839891636498">"Мобильдік деректер өшірулі"</string>
+    <string name="not_default_data_content_description" msgid="6517068332106592887">"Деректерді пайдалануға реттелмеген."</string>
+    <string name="accessibility_no_phone" msgid="2687419663127582503">"Телефон жоқ."</string>
+    <string name="accessibility_phone_one_bar" msgid="5719721147018970063">"Телефон бір баған."</string>
+    <string name="accessibility_phone_two_bars" msgid="2531458337458953263">"Телефон екі баған."</string>
+    <string name="accessibility_phone_three_bars" msgid="1523967995996696619">"Телефон үш баған."</string>
+    <string name="accessibility_phone_signal_full" msgid="4302338883816077134">"Телефон сигналы толық."</string>
+    <string name="accessibility_no_data" msgid="4563181886936931008">"Дерекқор жоқ."</string>
+    <string name="accessibility_data_one_bar" msgid="6892888138070752480">"Дерекқор бір баған."</string>
+    <string name="accessibility_data_two_bars" msgid="9202641507241802499">"Дерекқор екі баған."</string>
+    <string name="accessibility_data_three_bars" msgid="2813876214466722413">"Дерекқор үш баған."</string>
+    <string name="accessibility_data_signal_full" msgid="1808301899314382337">"Дерекқор сигналы толы."</string>
+    <string name="accessibility_ethernet_disconnected" msgid="2832501530856497489">"Ethernet ажыратылған."</string>
+    <string name="accessibility_ethernet_connected" msgid="2093872142317190618">"Ethernet қосылған."</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-km/strings.xml b/packages/SettingsLib/res/values-km/strings.xml
index a2b5e01..14f7788 100644
--- a/packages/SettingsLib/res/values-km/strings.xml
+++ b/packages/SettingsLib/res/values-km/strings.xml
@@ -403,7 +403,6 @@
     <string name="transcode_user_control" msgid="6176368544817731314">"លុបពីលើលំនាំដើម​នៃការបំប្លែងកូដ"</string>
     <string name="transcode_enable_all" msgid="2411165920039166710">"បើក​ការបំប្លែងកូដ"</string>
     <string name="transcode_default" msgid="3784803084573509491">"សន្មតថាកម្មវិធី​អាចប្រើ​ទម្រង់ទំនើបបាន"</string>
-    <string name="transcode_skip_apps" msgid="8249721984597390142">"បើក​ការបំប្លែងកូដ​សម្រាប់​កម្មវិធី"</string>
     <string name="runningservices_settings_title" msgid="6460099290493086515">"សេវាកម្ម​កំពុង​ដំណើរការ"</string>
     <string name="runningservices_settings_summary" msgid="1046080643262665743">"មើល និង​គ្រប់គ្រង​សេវាកម្ម​កំពុង​ដំណើរការ​បច្ចុប្បន្ន"</string>
     <string name="select_webview_provider_title" msgid="3917815648099445503">"ការអនុវត្ត WebView"</string>
@@ -566,4 +565,29 @@
     <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"កាស​មានខ្សែ"</string>
     <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"បើក"</string>
     <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"បិទ"</string>
+    <string name="carrier_network_change_mode" msgid="4257621815706644026">"បណ្តាញ​ក្រុមហ៊ុនសេវាទូរសព្ទ​កំពុងផ្លាស់ប្តូរ"</string>
+    <string name="data_connection_3g" msgid="931852552688157407">"3G"</string>
+    <string name="data_connection_edge" msgid="4625509456544797637">"EDGE"</string>
+    <string name="data_connection_cdma" msgid="9098161966701934334">"1X"</string>
+    <string name="data_connection_gprs" msgid="1251945769006770189">"GPRS"</string>
+    <string name="data_connection_3_5g" msgid="4298721462047921400">"H"</string>
+    <string name="data_connection_3_5g_plus" msgid="6683055858295918170">"H+"</string>
+    <string name="data_connection_4g" msgid="2581705503356752044">"4G"</string>
+    <string name="data_connection_4g_plus" msgid="5194902328408751020">"4G+"</string>
+    <string name="data_connection_lte" msgid="7675461204366364124">"LTE"</string>
+    <string name="data_connection_lte_plus" msgid="6643158654804916653">"LTE+"</string>
+    <string name="cell_data_off_content_description" msgid="2280700839891636498">"ទិន្នន័យ​ទូរសព្ទចល័ត​បានបិទ"</string>
+    <string name="not_default_data_content_description" msgid="6517068332106592887">"មិនបានកំណត់​ឱ្យប្រើ​ទិន្នន័យ​ទេ"</string>
+    <string name="accessibility_no_phone" msgid="2687419663127582503">"គ្មាន​ទូរស័ព្ទ។"</string>
+    <string name="accessibility_phone_one_bar" msgid="5719721147018970063">"សេវា​ទូរស័ព្ទ​មួយ​កាំ។"</string>
+    <string name="accessibility_phone_two_bars" msgid="2531458337458953263">"សេវា​ទូរស័ព្ទ​ពីរ​កាំ។"</string>
+    <string name="accessibility_phone_three_bars" msgid="1523967995996696619">"សេវា​ទូរស័ព្ទ​បី​កាំ​។"</string>
+    <string name="accessibility_phone_signal_full" msgid="4302338883816077134">"សេវា​ទូរស័ព្ទ​ពេញ។"</string>
+    <string name="accessibility_no_data" msgid="4563181886936931008">"គ្មាន​ទិន្នន័យ​។"</string>
+    <string name="accessibility_data_one_bar" msgid="6892888138070752480">"ទិន្នន័យ​មួយ​​កាំ។"</string>
+    <string name="accessibility_data_two_bars" msgid="9202641507241802499">"ទិន្នន័យ​ពីរ​​កាំ។"</string>
+    <string name="accessibility_data_three_bars" msgid="2813876214466722413">"ទិន្នន័យ​បី​កាំ។"</string>
+    <string name="accessibility_data_signal_full" msgid="1808301899314382337">"សញ្ញា​ទិន្នន័យ​ពេញ។"</string>
+    <string name="accessibility_ethernet_disconnected" msgid="2832501530856497489">"បានផ្តាច់អ៊ីសឺរណិត។"</string>
+    <string name="accessibility_ethernet_connected" msgid="2093872142317190618">"បានភ្ជាប់អ៊ីសឺរណិត។"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-kn/strings.xml b/packages/SettingsLib/res/values-kn/strings.xml
index f37cf8b..a279d22 100644
--- a/packages/SettingsLib/res/values-kn/strings.xml
+++ b/packages/SettingsLib/res/values-kn/strings.xml
@@ -400,13 +400,9 @@
     <string name="inactive_app_active_summary" msgid="8047630990208722344">"ಸಕ್ರಿಯ. ಟಾಗಲ್ ಮಾಡಲು ಟ್ಯಾಪ್ ಮಾಡಿ."</string>
     <string name="standby_bucket_summary" msgid="5128193447550429600">"ಅಪ್ಲಿಕೇಶನ್ ಸ್ಟ್ಯಾಂಡ್‌ಬೈ ಸ್ಥಿತಿ:<xliff:g id="BUCKET"> %s</xliff:g>"</string>
     <string name="transcode_settings_title" msgid="2581975870429850549">"ಮೀಡಿಯಾ ಟ್ರಾನ್ಸ್‌ಕೋಡಿಂಗ್ ಸೆಟ್ಟಿಂಗ್‌ಗಳು"</string>
-    <!-- no translation found for transcode_user_control (6176368544817731314) -->
-    <skip />
-    <!-- no translation found for transcode_enable_all (2411165920039166710) -->
-    <skip />
-    <!-- no translation found for transcode_default (3784803084573509491) -->
-    <skip />
-    <string name="transcode_skip_apps" msgid="8249721984597390142">"ಆ್ಯಪ್‌ಗಳಿಗಾಗಿ ಟ್ರಾನ್ಸ್‌ಕೋಡಿಂಗ್ ಅನ್ನು ಸಕ್ರಿಯಗೊಳಿಸಿ"</string>
+    <string name="transcode_user_control" msgid="6176368544817731314">"ಟ್ರಾನ್ಸ್‌ಕೋಡಿಂಗ್ ಡೀಫಾಲ್ಟ್‌ಗಳನ್ನು ಅತಿಕ್ರಮಿಸಿ"</string>
+    <string name="transcode_enable_all" msgid="2411165920039166710">"ಟ್ರಾನ್ಸ್‌ಕೋಡಿಂಗ್ ಅನ್ನು ಸಕ್ರಿಯಗೊಳಿಸಿ"</string>
+    <string name="transcode_default" msgid="3784803084573509491">"ಆ್ಯಪ್‌ಗಳು ಆಧುನಿಕ ಫಾರ್ಮ್ಯಾಟ್‌ಗಳನ್ನು ಬೆಂಬಲಿಸುತ್ತದೆ ಎಂದು ಊಹಿಸಿ"</string>
     <string name="runningservices_settings_title" msgid="6460099290493086515">"ರನ್‌ ಆಗುತ್ತಿರುವ ಸೇವೆಗಳು"</string>
     <string name="runningservices_settings_summary" msgid="1046080643262665743">"ಈಗ ರನ್‌ ಆಗುತ್ತಿರುವ ಸೇವೆಗಳನ್ನು ವೀಕ್ಷಿಸಿ ಮತ್ತು ನಿಯಂತ್ರಿಸಿ"</string>
     <string name="select_webview_provider_title" msgid="3917815648099445503">"WebView ಹೊಂದಿಸಿ"</string>
@@ -569,4 +565,29 @@
     <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"ವೈಯರ್ ಹೊಂದಿರುವ ಹೆಡ್‌ಫೋನ್"</string>
     <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"ಆನ್ ಆಗಿದೆ"</string>
     <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"ಆಫ್ ಆಗಿದೆ"</string>
+    <string name="carrier_network_change_mode" msgid="4257621815706644026">"ವಾಹಕ ನೆಟ್‌ವರ್ಕ್ ಬದಲಾಯಿಸುವಿಕೆ"</string>
+    <string name="data_connection_3g" msgid="931852552688157407">"3G"</string>
+    <string name="data_connection_edge" msgid="4625509456544797637">"EDGE"</string>
+    <string name="data_connection_cdma" msgid="9098161966701934334">"1X"</string>
+    <string name="data_connection_gprs" msgid="1251945769006770189">"GPRS"</string>
+    <string name="data_connection_3_5g" msgid="4298721462047921400">"H"</string>
+    <string name="data_connection_3_5g_plus" msgid="6683055858295918170">"H+"</string>
+    <string name="data_connection_4g" msgid="2581705503356752044">"4G"</string>
+    <string name="data_connection_4g_plus" msgid="5194902328408751020">"4G+"</string>
+    <string name="data_connection_lte" msgid="7675461204366364124">"LTE"</string>
+    <string name="data_connection_lte_plus" msgid="6643158654804916653">"LTE+"</string>
+    <string name="cell_data_off_content_description" msgid="2280700839891636498">"ಮೊಬೈಲ್ ಡೇಟಾ ಆಫ್"</string>
+    <string name="not_default_data_content_description" msgid="6517068332106592887">"ಡೇಟಾ ಬಳಸಲು ಹೊಂದಿಸಲಾಗಿಲ್ಲ"</string>
+    <string name="accessibility_no_phone" msgid="2687419663127582503">"ಯಾವುದೇ ಫೋನ್ ಇಲ್ಲ."</string>
+    <string name="accessibility_phone_one_bar" msgid="5719721147018970063">"ಪೋನ್ ಒಂದು ಪಟ್ಟಿ."</string>
+    <string name="accessibility_phone_two_bars" msgid="2531458337458953263">"ಫೋನ್ ಎರಡು ಪಟ್ಟಿಗಳು."</string>
+    <string name="accessibility_phone_three_bars" msgid="1523967995996696619">"ಫೋನ್ ಮೂರು ಪಟ್ಟಿಗಳು."</string>
+    <string name="accessibility_phone_signal_full" msgid="4302338883816077134">"ಫೋನ್ ಸಂಕೇತ ಪೂರ್ತಿ ಇದೆ."</string>
+    <string name="accessibility_no_data" msgid="4563181886936931008">"ಯಾವುದೇ ಡೇಟಾ ಇಲ್ಲ."</string>
+    <string name="accessibility_data_one_bar" msgid="6892888138070752480">"ಡೇಟಾ ಒಂದು ಪಟ್ಟಿ."</string>
+    <string name="accessibility_data_two_bars" msgid="9202641507241802499">"ಡೇಟಾ ಎರಡು ಪಟ್ಟಿಗಳು."</string>
+    <string name="accessibility_data_three_bars" msgid="2813876214466722413">"ಡೇಟಾ ಮೂರು ಪಟ್ಟಿಗಳು."</string>
+    <string name="accessibility_data_signal_full" msgid="1808301899314382337">"ಡೇಟಾ ಸಂಕೇತ ತುಂಬಿದೆ."</string>
+    <string name="accessibility_ethernet_disconnected" msgid="2832501530856497489">"ಇಥರ್ನೆಟ್ ಸಂಪರ್ಕ ಕಡಿತಗೊಳಿಸಲಾಗಿದೆ."</string>
+    <string name="accessibility_ethernet_connected" msgid="2093872142317190618">"ಇಥರ್ನೆಟ್ ಸಂಪರ್ಕಗೊಳಿಸಲಾಗಿದೆ."</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-ko/strings.xml b/packages/SettingsLib/res/values-ko/strings.xml
index 73921c2..de69488 100644
--- a/packages/SettingsLib/res/values-ko/strings.xml
+++ b/packages/SettingsLib/res/values-ko/strings.xml
@@ -403,7 +403,6 @@
     <string name="transcode_user_control" msgid="6176368544817731314">"트랜스코딩 기본값 재정의"</string>
     <string name="transcode_enable_all" msgid="2411165920039166710">"트랜스코딩 사용"</string>
     <string name="transcode_default" msgid="3784803084573509491">"앱이 최신 형식을 지원하는 것으로 가정"</string>
-    <string name="transcode_skip_apps" msgid="8249721984597390142">"앱 트랜스코딩 사용 설정"</string>
     <string name="runningservices_settings_title" msgid="6460099290493086515">"실행 중인 서비스"</string>
     <string name="runningservices_settings_summary" msgid="1046080643262665743">"현재 실행 중인 서비스 보기 및 제어"</string>
     <string name="select_webview_provider_title" msgid="3917815648099445503">"WebView 구현"</string>
@@ -566,4 +565,29 @@
     <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"유선 헤드폰"</string>
     <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"사용"</string>
     <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"사용 안 함"</string>
+    <string name="carrier_network_change_mode" msgid="4257621815706644026">"이동통신사 네트워크 변경"</string>
+    <string name="data_connection_3g" msgid="931852552688157407">"3G"</string>
+    <string name="data_connection_edge" msgid="4625509456544797637">"EDGE"</string>
+    <string name="data_connection_cdma" msgid="9098161966701934334">"1X"</string>
+    <string name="data_connection_gprs" msgid="1251945769006770189">"GPRS"</string>
+    <string name="data_connection_3_5g" msgid="4298721462047921400">"H"</string>
+    <string name="data_connection_3_5g_plus" msgid="6683055858295918170">"H+"</string>
+    <string name="data_connection_4g" msgid="2581705503356752044">"4G"</string>
+    <string name="data_connection_4g_plus" msgid="5194902328408751020">"4G 이상"</string>
+    <string name="data_connection_lte" msgid="7675461204366364124">"LTE"</string>
+    <string name="data_connection_lte_plus" msgid="6643158654804916653">"LTE+"</string>
+    <string name="cell_data_off_content_description" msgid="2280700839891636498">"모바일 데이터 꺼짐"</string>
+    <string name="not_default_data_content_description" msgid="6517068332106592887">"데이터를 사용하도록 설정되지 않음"</string>
+    <string name="accessibility_no_phone" msgid="2687419663127582503">"휴대전화의 신호가 없습니다."</string>
+    <string name="accessibility_phone_one_bar" msgid="5719721147018970063">"휴대전화 신호 막대가 하나입니다."</string>
+    <string name="accessibility_phone_two_bars" msgid="2531458337458953263">"휴대전화 신호 막대가 두 개입니다."</string>
+    <string name="accessibility_phone_three_bars" msgid="1523967995996696619">"휴대전화 신호 막대가 세 개입니다."</string>
+    <string name="accessibility_phone_signal_full" msgid="4302338883816077134">"휴대전화의 신호가 강합니다."</string>
+    <string name="accessibility_no_data" msgid="4563181886936931008">"데이터가 없습니다."</string>
+    <string name="accessibility_data_one_bar" msgid="6892888138070752480">"데이터 신호 막대가 하나입니다."</string>
+    <string name="accessibility_data_two_bars" msgid="9202641507241802499">"데이터 신호 막대가 두 개입니다."</string>
+    <string name="accessibility_data_three_bars" msgid="2813876214466722413">"데이터 신호 막대가 세 개입니다."</string>
+    <string name="accessibility_data_signal_full" msgid="1808301899314382337">"데이터 신호가 강합니다."</string>
+    <string name="accessibility_ethernet_disconnected" msgid="2832501530856497489">"이더넷에서 연결 해제되었습니다."</string>
+    <string name="accessibility_ethernet_connected" msgid="2093872142317190618">"이더넷에 연결되었습니다."</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-ky/strings.xml b/packages/SettingsLib/res/values-ky/strings.xml
index 5e978ba..e70460f 100644
--- a/packages/SettingsLib/res/values-ky/strings.xml
+++ b/packages/SettingsLib/res/values-ky/strings.xml
@@ -403,7 +403,6 @@
     <string name="transcode_user_control" msgid="6176368544817731314">"Демейки жүргүзүлгөн транскоддоону өзгөртүп коюу"</string>
     <string name="transcode_enable_all" msgid="2411165920039166710">"Транскоддоо жүргүзүүнү иштетүү"</string>
     <string name="transcode_default" msgid="3784803084573509491">"Колдонмолордо заманбап форматтар колдоого алынат"</string>
-    <string name="transcode_skip_apps" msgid="8249721984597390142">"Колдонмолорду транскоддоону күйгүзүү"</string>
     <string name="runningservices_settings_title" msgid="6460099290493086515">"Иштеп жаткан кызматтар"</string>
     <string name="runningservices_settings_summary" msgid="1046080643262665743">"Учурда иштеп жаткан кызматтарды көрүп, көзөмөлдөп турасыз"</string>
     <string name="select_webview_provider_title" msgid="3917815648099445503">"WebView кызматы"</string>
@@ -566,4 +565,29 @@
     <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Зымдуу гарнитура"</string>
     <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Күйгүзүү"</string>
     <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Өчүрүү"</string>
+    <string name="carrier_network_change_mode" msgid="4257621815706644026">"Байланыш оператору өзгөртүлүүдө"</string>
+    <string name="data_connection_3g" msgid="931852552688157407">"3G"</string>
+    <string name="data_connection_edge" msgid="4625509456544797637">"EDGE"</string>
+    <string name="data_connection_cdma" msgid="9098161966701934334">"1X"</string>
+    <string name="data_connection_gprs" msgid="1251945769006770189">"GPRS"</string>
+    <string name="data_connection_3_5g" msgid="4298721462047921400">"H"</string>
+    <string name="data_connection_3_5g_plus" msgid="6683055858295918170">"H+"</string>
+    <string name="data_connection_4g" msgid="2581705503356752044">"4G"</string>
+    <string name="data_connection_4g_plus" msgid="5194902328408751020">"4G+"</string>
+    <string name="data_connection_lte" msgid="7675461204366364124">"LTE"</string>
+    <string name="data_connection_lte_plus" msgid="6643158654804916653">"LTE+"</string>
+    <string name="cell_data_off_content_description" msgid="2280700839891636498">"Мобилдик Интернет өчүрүлгөн"</string>
+    <string name="not_default_data_content_description" msgid="6517068332106592887">"Дайындарды колдонуу үчүн жөндөлгөн эмес"</string>
+    <string name="accessibility_no_phone" msgid="2687419663127582503">"Телефон сигналы жок."</string>
+    <string name="accessibility_phone_one_bar" msgid="5719721147018970063">"Телефон сигналы бир таякча."</string>
+    <string name="accessibility_phone_two_bars" msgid="2531458337458953263">"Телефон сигналы эки таякча."</string>
+    <string name="accessibility_phone_three_bars" msgid="1523967995996696619">"Телефон сигналы үч таякча."</string>
+    <string name="accessibility_phone_signal_full" msgid="4302338883816077134">"Телефон сигналы толук."</string>
+    <string name="accessibility_no_data" msgid="4563181886936931008">"Сигнал жок."</string>
+    <string name="accessibility_data_one_bar" msgid="6892888138070752480">"Мобилдик интернеттин сигналы бир таякча."</string>
+    <string name="accessibility_data_two_bars" msgid="9202641507241802499">"Мобилдик интернеттин сигналы эки таякча."</string>
+    <string name="accessibility_data_three_bars" msgid="2813876214466722413">"Мобилдик интернеттин сигналы үч таякча."</string>
+    <string name="accessibility_data_signal_full" msgid="1808301899314382337">"Мобилдик интернеттин сигналы толук."</string>
+    <string name="accessibility_ethernet_disconnected" msgid="2832501530856497489">"Ethernet ажырады."</string>
+    <string name="accessibility_ethernet_connected" msgid="2093872142317190618">"Ethernet туташты."</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-lo/strings.xml b/packages/SettingsLib/res/values-lo/strings.xml
index 498cb25..c63cec8 100644
--- a/packages/SettingsLib/res/values-lo/strings.xml
+++ b/packages/SettingsLib/res/values-lo/strings.xml
@@ -403,7 +403,6 @@
     <string name="transcode_user_control" msgid="6176368544817731314">"ຍົກເລີກຄ່າເລີ່ມຕົ້ນການ​ປ່ຽນ​ຮູບ​ແບບ​ລະ​ຫັດ"</string>
     <string name="transcode_enable_all" msgid="2411165920039166710">"ເປີດການນຳໃຊ້ການ​ປ່ຽນ​ຮູບ​ແບບ​ລະ​ຫັດ"</string>
     <string name="transcode_default" msgid="3784803084573509491">"ສົມມຸດວ່າແອັບຮອງຮັບຮູບແບບສະໄໝໃໝ່"</string>
-    <string name="transcode_skip_apps" msgid="8249721984597390142">"ເປີດການນຳໃຊ້ການປ່ຽນຮູບແບບລະຫັດສຳລັບແອັບ"</string>
     <string name="runningservices_settings_title" msgid="6460099290493086515">"ບໍລິການທີ່ເຮັດວຽກຢູ່"</string>
     <string name="runningservices_settings_summary" msgid="1046080643262665743">"ເບິ່ງ ແລະຈັດການບໍລິການທີ່ກຳລັງເຮັດວຽກຢູ່ໃນປັດຈຸບັນ"</string>
     <string name="select_webview_provider_title" msgid="3917815648099445503">"ການຈັດຕັ້ງປະຕິບັດ WebView"</string>
@@ -566,4 +565,29 @@
     <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"ຫູຟັງແບບມີສາຍ"</string>
     <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"ເປີດ"</string>
     <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"ປິດ"</string>
+    <string name="carrier_network_change_mode" msgid="4257621815706644026">"ການປ່ຽນເຄືອຂ່າຍຜູ້ໃຫ້ບໍລິການ"</string>
+    <string name="data_connection_3g" msgid="931852552688157407">"3G"</string>
+    <string name="data_connection_edge" msgid="4625509456544797637">"EDGE"</string>
+    <string name="data_connection_cdma" msgid="9098161966701934334">"1X"</string>
+    <string name="data_connection_gprs" msgid="1251945769006770189">"GPRS"</string>
+    <string name="data_connection_3_5g" msgid="4298721462047921400">"H"</string>
+    <string name="data_connection_3_5g_plus" msgid="6683055858295918170">"H+"</string>
+    <string name="data_connection_4g" msgid="2581705503356752044">"4G"</string>
+    <string name="data_connection_4g_plus" msgid="5194902328408751020">"4G+"</string>
+    <string name="data_connection_lte" msgid="7675461204366364124">"LTE"</string>
+    <string name="data_connection_lte_plus" msgid="6643158654804916653">"LTE+"</string>
+    <string name="cell_data_off_content_description" msgid="2280700839891636498">"ປິດອິນເຕີເນັດມືຖືແລ້ວ"</string>
+    <string name="not_default_data_content_description" msgid="6517068332106592887">"ບໍ່ໄດ້ຕັ້ງໃຫ້ໃຊ້ອິນເຕີເນັດ"</string>
+    <string name="accessibility_no_phone" msgid="2687419663127582503">"ບໍ່ມີໂທລະສັບ."</string>
+    <string name="accessibility_phone_one_bar" msgid="5719721147018970063">"ສັນຍານນຶ່ງຂີດ."</string>
+    <string name="accessibility_phone_two_bars" msgid="2531458337458953263">"ສັນຍານສອງຂີດ."</string>
+    <string name="accessibility_phone_three_bars" msgid="1523967995996696619">"ສັນຍານສາມຂີດ."</string>
+    <string name="accessibility_phone_signal_full" msgid="4302338883816077134">"ສັນຍານເຕັມ."</string>
+    <string name="accessibility_no_data" msgid="4563181886936931008">"ບໍ່ມີຂໍ້ມູນ."</string>
+    <string name="accessibility_data_one_bar" msgid="6892888138070752480">"ຂໍ້ມູນນຶ່ງຂີດ."</string>
+    <string name="accessibility_data_two_bars" msgid="9202641507241802499">"ຂໍ້ມູນສອງຂີດ."</string>
+    <string name="accessibility_data_three_bars" msgid="2813876214466722413">"ຂໍ້ມູນສາມຂີດ."</string>
+    <string name="accessibility_data_signal_full" msgid="1808301899314382337">"ສັນ​ຍານຂໍ້ມູນ​ເຕັມ."</string>
+    <string name="accessibility_ethernet_disconnected" msgid="2832501530856497489">"ອີ​ເທີ​ເນັດ​ຕັດ​ເຊື່ອມ​ຕໍ່​ແລ້ວ."</string>
+    <string name="accessibility_ethernet_connected" msgid="2093872142317190618">"ອີ​ເທີ​ເນັດ​ເຊື່ອມ​ຕໍ່​ແລ້ວ."</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-lt/strings.xml b/packages/SettingsLib/res/values-lt/strings.xml
index c077268..d040edf 100644
--- a/packages/SettingsLib/res/values-lt/strings.xml
+++ b/packages/SettingsLib/res/values-lt/strings.xml
@@ -403,7 +403,6 @@
     <string name="transcode_user_control" msgid="6176368544817731314">"Perkodavimo numatytųjų nustatymų nepaisymas"</string>
     <string name="transcode_enable_all" msgid="2411165920039166710">"Perkodavimo įgalinimas"</string>
     <string name="transcode_default" msgid="3784803084573509491">"Manoma, kad programos palaiko modernius formatus"</string>
-    <string name="transcode_skip_apps" msgid="8249721984597390142">"Įjungti programų perkodavimą"</string>
     <string name="runningservices_settings_title" msgid="6460099290493086515">"Vykdomos paslaugos"</string>
     <string name="runningservices_settings_summary" msgid="1046080643262665743">"Žiūrėti ir valdyti dabar vykdomas paslaugas"</string>
     <string name="select_webview_provider_title" msgid="3917815648099445503">"„WebView“ diegimas"</string>
@@ -568,4 +567,29 @@
     <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Laidinės ausinės"</string>
     <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Įjungta"</string>
     <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Išjungta"</string>
+    <string name="carrier_network_change_mode" msgid="4257621815706644026">"Keičiamas operatoriaus tinklas"</string>
+    <string name="data_connection_3g" msgid="931852552688157407">"3G"</string>
+    <string name="data_connection_edge" msgid="4625509456544797637">"EDGE"</string>
+    <string name="data_connection_cdma" msgid="9098161966701934334">"1X"</string>
+    <string name="data_connection_gprs" msgid="1251945769006770189">"GPRS"</string>
+    <string name="data_connection_3_5g" msgid="4298721462047921400">"H"</string>
+    <string name="data_connection_3_5g_plus" msgid="6683055858295918170">"H+"</string>
+    <string name="data_connection_4g" msgid="2581705503356752044">"4G"</string>
+    <string name="data_connection_4g_plus" msgid="5194902328408751020">"4G+"</string>
+    <string name="data_connection_lte" msgid="7675461204366364124">"LTE"</string>
+    <string name="data_connection_lte_plus" msgid="6643158654804916653">"LTE+"</string>
+    <string name="cell_data_off_content_description" msgid="2280700839891636498">"Mobiliojo ryšio duomenys išjungti"</string>
+    <string name="not_default_data_content_description" msgid="6517068332106592887">"Nenustatyta naudoti duomenis"</string>
+    <string name="accessibility_no_phone" msgid="2687419663127582503">"Nėra telefono."</string>
+    <string name="accessibility_phone_one_bar" msgid="5719721147018970063">"Viena telefono juosta."</string>
+    <string name="accessibility_phone_two_bars" msgid="2531458337458953263">"Dvi telefono juostos."</string>
+    <string name="accessibility_phone_three_bars" msgid="1523967995996696619">"Trys telefono juostos."</string>
+    <string name="accessibility_phone_signal_full" msgid="4302338883816077134">"Telefono signalas stiprus."</string>
+    <string name="accessibility_no_data" msgid="4563181886936931008">"Duomenų nėra."</string>
+    <string name="accessibility_data_one_bar" msgid="6892888138070752480">"Viena duomenų juosta."</string>
+    <string name="accessibility_data_two_bars" msgid="9202641507241802499">"Dvi duomenų juostos."</string>
+    <string name="accessibility_data_three_bars" msgid="2813876214466722413">"Trys duomenų juostos."</string>
+    <string name="accessibility_data_signal_full" msgid="1808301899314382337">"Stiprus duomenų signalas."</string>
+    <string name="accessibility_ethernet_disconnected" msgid="2832501530856497489">"Atsijungta nuo eterneto."</string>
+    <string name="accessibility_ethernet_connected" msgid="2093872142317190618">"Prijungta prie eterneto."</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-lv/strings.xml b/packages/SettingsLib/res/values-lv/strings.xml
index d5755511..74c0dd5 100644
--- a/packages/SettingsLib/res/values-lv/strings.xml
+++ b/packages/SettingsLib/res/values-lv/strings.xml
@@ -403,7 +403,6 @@
     <string name="transcode_user_control" msgid="6176368544817731314">"Ignorēt pārkodēšanas noklusējuma iestatījumus"</string>
     <string name="transcode_enable_all" msgid="2411165920039166710">"Iespējot pārkodēšanu"</string>
     <string name="transcode_default" msgid="3784803084573509491">"Pieņemt, ka lietotnēs tiek atbalstīti moderni formāti"</string>
-    <string name="transcode_skip_apps" msgid="8249721984597390142">"Iespējot pārkodēšanu noteiktām lietotnēm"</string>
     <string name="runningservices_settings_title" msgid="6460099290493086515">"Aktīvie pakalpojumi"</string>
     <string name="runningservices_settings_summary" msgid="1046080643262665743">"Pašreiz darbojošos pakalpojumu skatīšana un vadība"</string>
     <string name="select_webview_provider_title" msgid="3917815648099445503">"WebView ieviešana"</string>
@@ -567,4 +566,29 @@
     <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Vadu austiņas"</string>
     <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Ieslēgts"</string>
     <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Izslēgts"</string>
+    <string name="carrier_network_change_mode" msgid="4257621815706644026">"Mobilo sakaru operatora tīkla mainīšana"</string>
+    <string name="data_connection_3g" msgid="931852552688157407">"3G"</string>
+    <string name="data_connection_edge" msgid="4625509456544797637">"EDGE"</string>
+    <string name="data_connection_cdma" msgid="9098161966701934334">"1X"</string>
+    <string name="data_connection_gprs" msgid="1251945769006770189">"GPRS"</string>
+    <string name="data_connection_3_5g" msgid="4298721462047921400">"H"</string>
+    <string name="data_connection_3_5g_plus" msgid="6683055858295918170">"H+"</string>
+    <string name="data_connection_4g" msgid="2581705503356752044">"4G"</string>
+    <string name="data_connection_4g_plus" msgid="5194902328408751020">"4G+"</string>
+    <string name="data_connection_lte" msgid="7675461204366364124">"LTE"</string>
+    <string name="data_connection_lte_plus" msgid="6643158654804916653">"LTE+"</string>
+    <string name="cell_data_off_content_description" msgid="2280700839891636498">"Mobilie dati izslēgti"</string>
+    <string name="not_default_data_content_description" msgid="6517068332106592887">"Nav iestatīts datu lietošanai"</string>
+    <string name="accessibility_no_phone" msgid="2687419663127582503">"Nav tālruņa."</string>
+    <string name="accessibility_phone_one_bar" msgid="5719721147018970063">"Tālrunis: viena josla."</string>
+    <string name="accessibility_phone_two_bars" msgid="2531458337458953263">"Tālrunis: divas joslas."</string>
+    <string name="accessibility_phone_three_bars" msgid="1523967995996696619">"Tālrunis: trīs joslas."</string>
+    <string name="accessibility_phone_signal_full" msgid="4302338883816077134">"Pilna piekļuve tālruņa signālam"</string>
+    <string name="accessibility_no_data" msgid="4563181886936931008">"Nav datu."</string>
+    <string name="accessibility_data_one_bar" msgid="6892888138070752480">"Dati: viena josla"</string>
+    <string name="accessibility_data_two_bars" msgid="9202641507241802499">"Dati: divas joslas."</string>
+    <string name="accessibility_data_three_bars" msgid="2813876214466722413">"Dati: trīs joslas."</string>
+    <string name="accessibility_data_signal_full" msgid="1808301899314382337">"Pilna piekļuve datu signālam."</string>
+    <string name="accessibility_ethernet_disconnected" msgid="2832501530856497489">"Pārtraukts savienojums ar tīklu Ethernet."</string>
+    <string name="accessibility_ethernet_connected" msgid="2093872142317190618">"Izveidots savienojums ar tīklu Ethernet."</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-mk/strings.xml b/packages/SettingsLib/res/values-mk/strings.xml
index 21dcb02..739bceb 100644
--- a/packages/SettingsLib/res/values-mk/strings.xml
+++ b/packages/SettingsLib/res/values-mk/strings.xml
@@ -403,7 +403,6 @@
     <string name="transcode_user_control" msgid="6176368544817731314">"Отфрли стандардни вредности за транскодирање"</string>
     <string name="transcode_enable_all" msgid="2411165920039166710">"Овозможи транскодирање"</string>
     <string name="transcode_default" msgid="3784803084573509491">"Претпостави дека апликациите поддржуваат модерни формати"</string>
-    <string name="transcode_skip_apps" msgid="8249721984597390142">"Овозможете транскодирање за апликациите"</string>
     <string name="runningservices_settings_title" msgid="6460099290493086515">"Активни услуги"</string>
     <string name="runningservices_settings_summary" msgid="1046080643262665743">"Погледнете и контролирајте услуги што се моментално активни"</string>
     <string name="select_webview_provider_title" msgid="3917815648099445503">"Воведување WebView"</string>
@@ -566,4 +565,29 @@
     <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Жичени слушалки"</string>
     <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Вклучено"</string>
     <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Исклучено"</string>
+    <string name="carrier_network_change_mode" msgid="4257621815706644026">"Променување на мрежата на операторот"</string>
+    <string name="data_connection_3g" msgid="931852552688157407">"3G"</string>
+    <string name="data_connection_edge" msgid="4625509456544797637">"EDGE"</string>
+    <string name="data_connection_cdma" msgid="9098161966701934334">"1X"</string>
+    <string name="data_connection_gprs" msgid="1251945769006770189">"GPRS"</string>
+    <string name="data_connection_3_5g" msgid="4298721462047921400">"H"</string>
+    <string name="data_connection_3_5g_plus" msgid="6683055858295918170">"H+"</string>
+    <string name="data_connection_4g" msgid="2581705503356752044">"4G"</string>
+    <string name="data_connection_4g_plus" msgid="5194902328408751020">"4G+"</string>
+    <string name="data_connection_lte" msgid="7675461204366364124">"LTE"</string>
+    <string name="data_connection_lte_plus" msgid="6643158654804916653">"LTE+"</string>
+    <string name="cell_data_off_content_description" msgid="2280700839891636498">"Мобилниот интернет е исклучен"</string>
+    <string name="not_default_data_content_description" msgid="6517068332106592887">"Не е поставен да користи интернет"</string>
+    <string name="accessibility_no_phone" msgid="2687419663127582503">"Нема сигнал."</string>
+    <string name="accessibility_phone_one_bar" msgid="5719721147018970063">"Телефон една цртичка.."</string>
+    <string name="accessibility_phone_two_bars" msgid="2531458337458953263">"Телефон две цртички."</string>
+    <string name="accessibility_phone_three_bars" msgid="1523967995996696619">"Телефон три цртички."</string>
+    <string name="accessibility_phone_signal_full" msgid="4302338883816077134">"Сигналот за телефон е исполнет."</string>
+    <string name="accessibility_no_data" msgid="4563181886936931008">"Нема податоци."</string>
+    <string name="accessibility_data_one_bar" msgid="6892888138070752480">"Податоци една цртичка."</string>
+    <string name="accessibility_data_two_bars" msgid="9202641507241802499">"Сигналот за податоци е на две цртички."</string>
+    <string name="accessibility_data_three_bars" msgid="2813876214466722413">"Податоци три цртички."</string>
+    <string name="accessibility_data_signal_full" msgid="1808301899314382337">"Сигналот за податоци е исполнет."</string>
+    <string name="accessibility_ethernet_disconnected" msgid="2832501530856497489">"Етернетот е исклучен."</string>
+    <string name="accessibility_ethernet_connected" msgid="2093872142317190618">"Етернетот е поврзан."</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-ml/strings.xml b/packages/SettingsLib/res/values-ml/strings.xml
index 97c22d5..122b481 100644
--- a/packages/SettingsLib/res/values-ml/strings.xml
+++ b/packages/SettingsLib/res/values-ml/strings.xml
@@ -400,13 +400,9 @@
     <string name="inactive_app_active_summary" msgid="8047630990208722344">"സജീവം. മാറ്റുന്നതിന് ടാപ്പുചെയ്യുക."</string>
     <string name="standby_bucket_summary" msgid="5128193447550429600">"ആപ്പ് സ്‌റ്റാൻഡ്‌ബൈ നില:<xliff:g id="BUCKET"> %s</xliff:g>"</string>
     <string name="transcode_settings_title" msgid="2581975870429850549">"മീഡിയ ട്രാൻസ്കോഡ് ചെയ്യൽ ക്രമീകരണം"</string>
-    <!-- no translation found for transcode_user_control (6176368544817731314) -->
-    <skip />
-    <!-- no translation found for transcode_enable_all (2411165920039166710) -->
-    <skip />
-    <!-- no translation found for transcode_default (3784803084573509491) -->
-    <skip />
-    <string name="transcode_skip_apps" msgid="8249721984597390142">"ആപ്പുകൾക്കായി ട്രാൻസ്കോഡ് ചെയ്യുന്നത് പ്രവർത്തനക്ഷമമാക്കുക"</string>
+    <string name="transcode_user_control" msgid="6176368544817731314">"ട്രാൻസ്കോഡ് ചെയ്യൽ ഡിഫോൾട്ടുകൾ അസാധുവാക്കുക"</string>
+    <string name="transcode_enable_all" msgid="2411165920039166710">"ട്രാൻസ്കോഡ് ചെയ്യൽ പ്രവർത്തനക്ഷമമാക്കുക"</string>
+    <string name="transcode_default" msgid="3784803084573509491">"ആപ്പുകൾ ആധുനിക ഫോർമാറ്റുകളെ പിന്തുണയ്ക്കുമെന്ന് കരുതുക"</string>
     <string name="runningservices_settings_title" msgid="6460099290493086515">"പ്രവർത്തിക്കുന്ന സേവനങ്ങൾ"</string>
     <string name="runningservices_settings_summary" msgid="1046080643262665743">"നിലവിൽ പ്രവർത്തിക്കുന്ന സേവനങ്ങൾ കാണുക, നിയന്ത്രിക്കുക"</string>
     <string name="select_webview_provider_title" msgid="3917815648099445503">"WebView നടപ്പാക്കൽ"</string>
@@ -569,4 +565,29 @@
     <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"വയേർഡ് ഹെഡ്ഫോൺ"</string>
     <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"ഓണാണ്"</string>
     <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"ഓഫാണ്"</string>
+    <string name="carrier_network_change_mode" msgid="4257621815706644026">"കാരിയർ നെറ്റ്‌വർക്ക് മാറ്റൽ"</string>
+    <string name="data_connection_3g" msgid="931852552688157407">"3G"</string>
+    <string name="data_connection_edge" msgid="4625509456544797637">"EDG"</string>
+    <string name="data_connection_cdma" msgid="9098161966701934334">"1X"</string>
+    <string name="data_connection_gprs" msgid="1251945769006770189">"GPRS"</string>
+    <string name="data_connection_3_5g" msgid="4298721462047921400">"H"</string>
+    <string name="data_connection_3_5g_plus" msgid="6683055858295918170">"H+"</string>
+    <string name="data_connection_4g" msgid="2581705503356752044">"4G"</string>
+    <string name="data_connection_4g_plus" msgid="5194902328408751020">"4G+"</string>
+    <string name="data_connection_lte" msgid="7675461204366364124">"LTE"</string>
+    <string name="data_connection_lte_plus" msgid="6643158654804916653">"LTE+"</string>
+    <string name="cell_data_off_content_description" msgid="2280700839891636498">"മൊബൈൽ ഡാറ്റ ഓഫാണ്"</string>
+    <string name="not_default_data_content_description" msgid="6517068332106592887">"ഡാറ്റ ഉപയോഗിക്കുന്നതിന് സജ്ജീകരിച്ചിട്ടില്ല"</string>
+    <string name="accessibility_no_phone" msgid="2687419663127582503">"ഫോൺ സിഗ്‌നൽ ഒന്നുമില്ല."</string>
+    <string name="accessibility_phone_one_bar" msgid="5719721147018970063">"ഫോണിൽ ഒരു ബാർ."</string>
+    <string name="accessibility_phone_two_bars" msgid="2531458337458953263">"ഫോണിൽ രണ്ട് ബാർ."</string>
+    <string name="accessibility_phone_three_bars" msgid="1523967995996696619">"ഫോണിൽ മൂന്ന് ബാർ."</string>
+    <string name="accessibility_phone_signal_full" msgid="4302338883816077134">"ഫോൺ സിഗ്‌നൽ പൂർണ്ണമാണ്."</string>
+    <string name="accessibility_no_data" msgid="4563181886936931008">"ഡാറ്റാ സിഗ്‌നൽ ഒന്നുമില്ല."</string>
+    <string name="accessibility_data_one_bar" msgid="6892888138070752480">"ഡാറ്റ ഒരു ബാർ."</string>
+    <string name="accessibility_data_two_bars" msgid="9202641507241802499">"ഡാറ്റ രണ്ട് ബാറുകൾ."</string>
+    <string name="accessibility_data_three_bars" msgid="2813876214466722413">"ഡാറ്റ മൂന്ന് ബാർ."</string>
+    <string name="accessibility_data_signal_full" msgid="1808301899314382337">"ഡാറ്റ സിഗ്‌നൽ പൂർണ്ണമാണ്."</string>
+    <string name="accessibility_ethernet_disconnected" msgid="2832501530856497489">"ഇതർനെറ്റ് വിച്ഛേദിച്ചു."</string>
+    <string name="accessibility_ethernet_connected" msgid="2093872142317190618">"ഇതർനെറ്റ് കണക്റ്റുചെയ്‌തു."</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-mn/strings.xml b/packages/SettingsLib/res/values-mn/strings.xml
index 8d1cc33..c7a2edd 100644
--- a/packages/SettingsLib/res/values-mn/strings.xml
+++ b/packages/SettingsLib/res/values-mn/strings.xml
@@ -403,7 +403,6 @@
     <string name="transcode_user_control" msgid="6176368544817731314">"Хөрвүүлгийн өгөгдмөлийг дарах"</string>
     <string name="transcode_enable_all" msgid="2411165920039166710">"Хөрвүүлгийг идэвхжүүлэх"</string>
     <string name="transcode_default" msgid="3784803084573509491">"Аппыг орчин үеийн форматыг дэмждэг гэж үздэг"</string>
-    <string name="transcode_skip_apps" msgid="8249721984597390142">"Аппуудад хөрвүүлгийг идэвхжүүлэх"</string>
     <string name="runningservices_settings_title" msgid="6460099290493086515">"Ажиллаж байгаа үйлчилгээнүүд"</string>
     <string name="runningservices_settings_summary" msgid="1046080643262665743">"Одоо ажиллаж байгаа үйлчилгээнүүдийг харах болон хянах"</string>
     <string name="select_webview_provider_title" msgid="3917815648099445503">"WebView хэрэгжилт"</string>
@@ -566,4 +565,29 @@
     <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Утастай чихэвч"</string>
     <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Асаах"</string>
     <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Унтраах"</string>
+    <string name="carrier_network_change_mode" msgid="4257621815706644026">"Оператор компанийн сүлжээг өөрчилж байна"</string>
+    <string name="data_connection_3g" msgid="931852552688157407">"3G"</string>
+    <string name="data_connection_edge" msgid="4625509456544797637">"EDGE"</string>
+    <string name="data_connection_cdma" msgid="9098161966701934334">"1X"</string>
+    <string name="data_connection_gprs" msgid="1251945769006770189">"GPRS"</string>
+    <string name="data_connection_3_5g" msgid="4298721462047921400">"H"</string>
+    <string name="data_connection_3_5g_plus" msgid="6683055858295918170">"H+"</string>
+    <string name="data_connection_4g" msgid="2581705503356752044">"4G"</string>
+    <string name="data_connection_4g_plus" msgid="5194902328408751020">"4G+"</string>
+    <string name="data_connection_lte" msgid="7675461204366364124">"LTE"</string>
+    <string name="data_connection_lte_plus" msgid="6643158654804916653">"LTE+"</string>
+    <string name="cell_data_off_content_description" msgid="2280700839891636498">"Мобайл дата унтраалттай байна"</string>
+    <string name="not_default_data_content_description" msgid="6517068332106592887">"Дата ашиглахаар тохируулаагүй"</string>
+    <string name="accessibility_no_phone" msgid="2687419663127582503">"Утас байхгүй."</string>
+    <string name="accessibility_phone_one_bar" msgid="5719721147018970063">"Утас нэг баганатай."</string>
+    <string name="accessibility_phone_two_bars" msgid="2531458337458953263">"Утас хоёр баганатай."</string>
+    <string name="accessibility_phone_three_bars" msgid="1523967995996696619">"Утас гурван баганатай."</string>
+    <string name="accessibility_phone_signal_full" msgid="4302338883816077134">"Утасны дохио дүүрэн."</string>
+    <string name="accessibility_no_data" msgid="4563181886936931008">"Дата байхгүй."</string>
+    <string name="accessibility_data_one_bar" msgid="6892888138070752480">"Дата нэг баганатай."</string>
+    <string name="accessibility_data_two_bars" msgid="9202641507241802499">"Дата хоёр баганатай."</string>
+    <string name="accessibility_data_three_bars" msgid="2813876214466722413">"Дата гурван баганатай."</string>
+    <string name="accessibility_data_signal_full" msgid="1808301899314382337">"Дата дохио дүүрэн."</string>
+    <string name="accessibility_ethernet_disconnected" msgid="2832501530856497489">"Ethernet саллаа."</string>
+    <string name="accessibility_ethernet_connected" msgid="2093872142317190618">"Ethernet холбогдсон."</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-mr/strings.xml b/packages/SettingsLib/res/values-mr/strings.xml
index c20888e..d29cb59 100644
--- a/packages/SettingsLib/res/values-mr/strings.xml
+++ b/packages/SettingsLib/res/values-mr/strings.xml
@@ -400,13 +400,9 @@
     <string name="inactive_app_active_summary" msgid="8047630990208722344">"सक्रिय. टॉगल करण्यासाठी टॅप करा."</string>
     <string name="standby_bucket_summary" msgid="5128193447550429600">"अ‍ॅप स्टँडबाय स्थिती: <xliff:g id="BUCKET"> %s</xliff:g>"</string>
     <string name="transcode_settings_title" msgid="2581975870429850549">"मीडिया ट्रान्सकोडिंगची सेटिंग्ज"</string>
-    <!-- no translation found for transcode_user_control (6176368544817731314) -->
-    <skip />
-    <!-- no translation found for transcode_enable_all (2411165920039166710) -->
-    <skip />
-    <!-- no translation found for transcode_default (3784803084573509491) -->
-    <skip />
-    <string name="transcode_skip_apps" msgid="8249721984597390142">"ॲप्ससाठी ट्रान्सकोडिंग सुरू करा"</string>
+    <string name="transcode_user_control" msgid="6176368544817731314">"ट्रान्सकोडिंग डीफॉल्ट ओव्हरराइड करा"</string>
+    <string name="transcode_enable_all" msgid="2411165920039166710">"ट्रान्सकोडिंग सुरू करा"</string>
+    <string name="transcode_default" msgid="3784803084573509491">"असे गृहीत धरा की, ॲप्स आधुनिक फॉरमॅटना सपोर्ट करतात"</string>
     <string name="runningservices_settings_title" msgid="6460099290493086515">"सुरू सेवा"</string>
     <string name="runningservices_settings_summary" msgid="1046080643262665743">"सध्या सुरू असलेल्या सेवा पहा आणि नियंत्रित करा"</string>
     <string name="select_webview_provider_title" msgid="3917815648099445503">"वेबदृश्य अंमलबजावणी"</string>
@@ -569,4 +565,29 @@
     <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"वायर असलेला हेडफोन"</string>
     <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"सुरू करा"</string>
     <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"बंद करा"</string>
+    <string name="carrier_network_change_mode" msgid="4257621815706644026">"वाहक नेटवर्क बदलत आहे"</string>
+    <string name="data_connection_3g" msgid="931852552688157407">"३G"</string>
+    <string name="data_connection_edge" msgid="4625509456544797637">"EDGE"</string>
+    <string name="data_connection_cdma" msgid="9098161966701934334">"१X"</string>
+    <string name="data_connection_gprs" msgid="1251945769006770189">"GPRS"</string>
+    <string name="data_connection_3_5g" msgid="4298721462047921400">"H"</string>
+    <string name="data_connection_3_5g_plus" msgid="6683055858295918170">"H+"</string>
+    <string name="data_connection_4g" msgid="2581705503356752044">"४G"</string>
+    <string name="data_connection_4g_plus" msgid="5194902328408751020">"४G+"</string>
+    <string name="data_connection_lte" msgid="7675461204366364124">"LTE"</string>
+    <string name="data_connection_lte_plus" msgid="6643158654804916653">"LTE+"</string>
+    <string name="cell_data_off_content_description" msgid="2280700839891636498">"मोबाइल डेटा बंद आहे"</string>
+    <string name="not_default_data_content_description" msgid="6517068332106592887">"डेटा वापरण्यासाठी सेट केलेले नाही"</string>
+    <string name="accessibility_no_phone" msgid="2687419663127582503">"कोणताही फोन नाही."</string>
+    <string name="accessibility_phone_one_bar" msgid="5719721147018970063">"फोन एक बार."</string>
+    <string name="accessibility_phone_two_bars" msgid="2531458337458953263">"फोन दोन बार."</string>
+    <string name="accessibility_phone_three_bars" msgid="1523967995996696619">"फोन तीन बार."</string>
+    <string name="accessibility_phone_signal_full" msgid="4302338883816077134">"फोन सिग्नल पूर्ण."</string>
+    <string name="accessibility_no_data" msgid="4563181886936931008">"कोणताही डेटा नाही."</string>
+    <string name="accessibility_data_one_bar" msgid="6892888138070752480">"डेटा एक बार."</string>
+    <string name="accessibility_data_two_bars" msgid="9202641507241802499">"डेटा दोन बार."</string>
+    <string name="accessibility_data_three_bars" msgid="2813876214466722413">"डेटा तीन बार."</string>
+    <string name="accessibility_data_signal_full" msgid="1808301899314382337">"डेटा सिग्नल पूर्ण."</string>
+    <string name="accessibility_ethernet_disconnected" msgid="2832501530856497489">"इथरनेट डिस्कनेक्ट केले."</string>
+    <string name="accessibility_ethernet_connected" msgid="2093872142317190618">"इथरनेट कनेक्ट केले."</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-ms/strings.xml b/packages/SettingsLib/res/values-ms/strings.xml
index 76840a5..c593e4b 100644
--- a/packages/SettingsLib/res/values-ms/strings.xml
+++ b/packages/SettingsLib/res/values-ms/strings.xml
@@ -403,7 +403,6 @@
     <string name="transcode_user_control" msgid="6176368544817731314">"Batalkan transpengekodan lalai"</string>
     <string name="transcode_enable_all" msgid="2411165920039166710">"Dayakan transpengekodan"</string>
     <string name="transcode_default" msgid="3784803084573509491">"Mengambil alih sokongan apl format moden"</string>
-    <string name="transcode_skip_apps" msgid="8249721984597390142">"Dayakan transpengekodan untuk apl"</string>
     <string name="runningservices_settings_title" msgid="6460099290493086515">"Perkhidmatan dijalankan"</string>
     <string name="runningservices_settings_summary" msgid="1046080643262665743">"Lihat dan kawal perkhidmatan yang sedang dijalankan"</string>
     <string name="select_webview_provider_title" msgid="3917815648099445503">"Pelaksanaan WebView"</string>
@@ -566,4 +565,29 @@
     <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Fon kepala berwayar"</string>
     <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Hidup"</string>
     <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Mati"</string>
+    <string name="carrier_network_change_mode" msgid="4257621815706644026">"Rangkaian pembawa berubah"</string>
+    <string name="data_connection_3g" msgid="931852552688157407">"3G"</string>
+    <string name="data_connection_edge" msgid="4625509456544797637">"EDGE"</string>
+    <string name="data_connection_cdma" msgid="9098161966701934334">"1X"</string>
+    <string name="data_connection_gprs" msgid="1251945769006770189">"GPRS"</string>
+    <string name="data_connection_3_5g" msgid="4298721462047921400">"H"</string>
+    <string name="data_connection_3_5g_plus" msgid="6683055858295918170">"H+"</string>
+    <string name="data_connection_4g" msgid="2581705503356752044">"4G"</string>
+    <string name="data_connection_4g_plus" msgid="5194902328408751020">"4G+"</string>
+    <string name="data_connection_lte" msgid="7675461204366364124">"LTE"</string>
+    <string name="data_connection_lte_plus" msgid="6643158654804916653">"LTE+"</string>
+    <string name="cell_data_off_content_description" msgid="2280700839891636498">"Data mudah alih dimatikan"</string>
+    <string name="not_default_data_content_description" msgid="6517068332106592887">"Tidak ditetapkan untuk menggunakan data"</string>
+    <string name="accessibility_no_phone" msgid="2687419663127582503">"Tiada telefon."</string>
+    <string name="accessibility_phone_one_bar" msgid="5719721147018970063">"Telefon satu bar."</string>
+    <string name="accessibility_phone_two_bars" msgid="2531458337458953263">"Telefon dua bar."</string>
+    <string name="accessibility_phone_three_bars" msgid="1523967995996696619">"Telefon tiga bar."</string>
+    <string name="accessibility_phone_signal_full" msgid="4302338883816077134">"Isyarat telefon penuh."</string>
+    <string name="accessibility_no_data" msgid="4563181886936931008">"Tiada data."</string>
+    <string name="accessibility_data_one_bar" msgid="6892888138070752480">"Data satu bar."</string>
+    <string name="accessibility_data_two_bars" msgid="9202641507241802499">"Data dua bar."</string>
+    <string name="accessibility_data_three_bars" msgid="2813876214466722413">"Data tiga bar."</string>
+    <string name="accessibility_data_signal_full" msgid="1808301899314382337">"Isyarat data penuh."</string>
+    <string name="accessibility_ethernet_disconnected" msgid="2832501530856497489">"Ethernet diputuskan sambungan."</string>
+    <string name="accessibility_ethernet_connected" msgid="2093872142317190618">"Ethernet disambungkan."</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-my/strings.xml b/packages/SettingsLib/res/values-my/strings.xml
index 377e49da..aa9d3d6 100644
--- a/packages/SettingsLib/res/values-my/strings.xml
+++ b/packages/SettingsLib/res/values-my/strings.xml
@@ -403,7 +403,6 @@
     <string name="transcode_user_control" msgid="6176368544817731314">"အမျိုးအစားပြောင်းခြင်း၏ မူရင်းဆက်တင်များကို အစားထိုးရန်"</string>
     <string name="transcode_enable_all" msgid="2411165920039166710">"အမျိုးအစားပြောင်းခြင်းကို ဖွင့်ရန်"</string>
     <string name="transcode_default" msgid="3784803084573509491">"ဤအက်ပ်များက ဖော်မက်အသစ်များကို ပံ့ပိုးသည်"</string>
-    <string name="transcode_skip_apps" msgid="8249721984597390142">"အက်ပ်များအတွက် အမျိုးအစားပြောင်းခြင်းကို ဖွင့်ရန်"</string>
     <string name="runningservices_settings_title" msgid="6460099290493086515">"အလုပ်လုပ်နေသောဝန်ဆောင်မှုများ"</string>
     <string name="runningservices_settings_summary" msgid="1046080643262665743">"လက်ရှိ ဝန်ဆောင်မှုများကို ကြည့်ရှု ထိန်းသိမ်းသည်"</string>
     <string name="select_webview_provider_title" msgid="3917815648099445503">"WebView အကောင်အထည်ဖော်မှု"</string>
@@ -566,4 +565,29 @@
     <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"ကြိုးတပ်နားကြပ်"</string>
     <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"ဖွင့်ထားသည်"</string>
     <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"ပိတ်ထားသည်"</string>
+    <string name="carrier_network_change_mode" msgid="4257621815706644026">"ဝန်ဆောင်မှုပေးသူ ကွန်ရက် ပြောင်းလဲနေသည်။"</string>
+    <string name="data_connection_3g" msgid="931852552688157407">"3G"</string>
+    <string name="data_connection_edge" msgid="4625509456544797637">"EDGE"</string>
+    <string name="data_connection_cdma" msgid="9098161966701934334">"1X"</string>
+    <string name="data_connection_gprs" msgid="1251945769006770189">"GPRS"</string>
+    <string name="data_connection_3_5g" msgid="4298721462047921400">"H"</string>
+    <string name="data_connection_3_5g_plus" msgid="6683055858295918170">"H+"</string>
+    <string name="data_connection_4g" msgid="2581705503356752044">"4G"</string>
+    <string name="data_connection_4g_plus" msgid="5194902328408751020">"4G+"</string>
+    <string name="data_connection_lte" msgid="7675461204366364124">"LTE"</string>
+    <string name="data_connection_lte_plus" msgid="6643158654804916653">"LTE+"</string>
+    <string name="cell_data_off_content_description" msgid="2280700839891636498">"မိုဘိုင်းဒေတာ ပိတ်ထားသည်"</string>
+    <string name="not_default_data_content_description" msgid="6517068332106592887">"ဒေတာအသုံးပြုရန် သတ်မှတ်မထားပါ"</string>
+    <string name="accessibility_no_phone" msgid="2687419663127582503">"ဖုန်းလိုင်းမရှိပါ။"</string>
+    <string name="accessibility_phone_one_bar" msgid="5719721147018970063">"ဖုန်းလိုင်းတစ်ဘား။"</string>
+    <string name="accessibility_phone_two_bars" msgid="2531458337458953263">"ဖုန်းလိုင်းနှစ်ဘား။"</string>
+    <string name="accessibility_phone_three_bars" msgid="1523967995996696619">"ဖုန်းလိုင်းသုံးဘား။"</string>
+    <string name="accessibility_phone_signal_full" msgid="4302338883816077134">"ဖုန်းလိုင်းအပြည့်။"</string>
+    <string name="accessibility_no_data" msgid="4563181886936931008">"ဒေတာမရှိပါ။"</string>
+    <string name="accessibility_data_one_bar" msgid="6892888138070752480">"ဒေတာတစ်ဘား။"</string>
+    <string name="accessibility_data_two_bars" msgid="9202641507241802499">"ဒေတာထုတ်လွှင့်မှု ၂ဘားဖမ်းမိခြင်း။"</string>
+    <string name="accessibility_data_three_bars" msgid="2813876214466722413">"ဒေတာသုံးဘား။"</string>
+    <string name="accessibility_data_signal_full" msgid="1808301899314382337">"ဒေတာထုတ်လွှင့်မှုအပြည့်ဖမ်းမိခြင်း"</string>
+    <string name="accessibility_ethernet_disconnected" msgid="2832501530856497489">"Ethernet နှင့်ချိတ်ဆက်မှုပြတ်တောက်"</string>
+    <string name="accessibility_ethernet_connected" msgid="2093872142317190618">"Ethernet ချိတ်ဆက်ထား။"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-nb/strings.xml b/packages/SettingsLib/res/values-nb/strings.xml
index db93121..9494c39 100644
--- a/packages/SettingsLib/res/values-nb/strings.xml
+++ b/packages/SettingsLib/res/values-nb/strings.xml
@@ -403,7 +403,6 @@
     <string name="transcode_user_control" msgid="6176368544817731314">"Overstyr omkodingsstandarder"</string>
     <string name="transcode_enable_all" msgid="2411165920039166710">"Slå på omkoding"</string>
     <string name="transcode_default" msgid="3784803084573509491">"Anta at apper støtter moderne formater"</string>
-    <string name="transcode_skip_apps" msgid="8249721984597390142">"Aktiver omkoding for apper"</string>
     <string name="runningservices_settings_title" msgid="6460099290493086515">"Aktive tjenester"</string>
     <string name="runningservices_settings_summary" msgid="1046080643262665743">"Se og kontrollér tjenester som kjører"</string>
     <string name="select_webview_provider_title" msgid="3917815648099445503">"WebView-implementering"</string>
@@ -566,4 +565,29 @@
     <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Hodetelefoner med kabel"</string>
     <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"På"</string>
     <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Av"</string>
+    <string name="carrier_network_change_mode" msgid="4257621815706644026">"Bytting av operatørnettverk"</string>
+    <string name="data_connection_3g" msgid="931852552688157407">"3G"</string>
+    <string name="data_connection_edge" msgid="4625509456544797637">"EDGE"</string>
+    <string name="data_connection_cdma" msgid="9098161966701934334">"1X"</string>
+    <string name="data_connection_gprs" msgid="1251945769006770189">"GPRS"</string>
+    <string name="data_connection_3_5g" msgid="4298721462047921400">"H"</string>
+    <string name="data_connection_3_5g_plus" msgid="6683055858295918170">"H+"</string>
+    <string name="data_connection_4g" msgid="2581705503356752044">"4G"</string>
+    <string name="data_connection_4g_plus" msgid="5194902328408751020">"4G+"</string>
+    <string name="data_connection_lte" msgid="7675461204366364124">"LTE"</string>
+    <string name="data_connection_lte_plus" msgid="6643158654804916653">"LTE+"</string>
+    <string name="cell_data_off_content_description" msgid="2280700839891636498">"Mobildata er slått av"</string>
+    <string name="not_default_data_content_description" msgid="6517068332106592887">"Ikke konfigurert til å bruke data"</string>
+    <string name="accessibility_no_phone" msgid="2687419663127582503">"Ingen telefon."</string>
+    <string name="accessibility_phone_one_bar" msgid="5719721147018970063">"Telefon – én stolpe."</string>
+    <string name="accessibility_phone_two_bars" msgid="2531458337458953263">"Telefon – to stolper."</string>
+    <string name="accessibility_phone_three_bars" msgid="1523967995996696619">"Telefon – tre stolper."</string>
+    <string name="accessibility_phone_signal_full" msgid="4302338883816077134">"Telefonsignal er fullt."</string>
+    <string name="accessibility_no_data" msgid="4563181886936931008">"Ingen data."</string>
+    <string name="accessibility_data_one_bar" msgid="6892888138070752480">"Data – én stolpe"</string>
+    <string name="accessibility_data_two_bars" msgid="9202641507241802499">"Data – to stolper."</string>
+    <string name="accessibility_data_three_bars" msgid="2813876214466722413">"Data – tre stolper."</string>
+    <string name="accessibility_data_signal_full" msgid="1808301899314382337">"Datasignal er fullt."</string>
+    <string name="accessibility_ethernet_disconnected" msgid="2832501530856497489">"Ethernet er frakoblet."</string>
+    <string name="accessibility_ethernet_connected" msgid="2093872142317190618">"Ethernet er tilkoblet."</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-ne/strings.xml b/packages/SettingsLib/res/values-ne/strings.xml
index 25a2919..e31fb4e 100644
--- a/packages/SettingsLib/res/values-ne/strings.xml
+++ b/packages/SettingsLib/res/values-ne/strings.xml
@@ -400,13 +400,9 @@
     <string name="inactive_app_active_summary" msgid="8047630990208722344">"सक्रिय। टगल गर्न ट्याप गर्नुहोस्।"</string>
     <string name="standby_bucket_summary" msgid="5128193447550429600">"एपको स्ट्यान्डबाई अवस्था:<xliff:g id="BUCKET"> %s</xliff:g>"</string>
     <string name="transcode_settings_title" msgid="2581975870429850549">"मिडिया ट्रान्सकोडिङ सेटिङ"</string>
-    <!-- no translation found for transcode_user_control (6176368544817731314) -->
-    <skip />
-    <!-- no translation found for transcode_enable_all (2411165920039166710) -->
-    <skip />
-    <!-- no translation found for transcode_default (3784803084573509491) -->
-    <skip />
-    <string name="transcode_skip_apps" msgid="8249721984597390142">"एपहरूमा ट्रान्सकोडिङ अन गर्नुहोस्"</string>
+    <string name="transcode_user_control" msgid="6176368544817731314">"ट्रान्सकोडिङसम्बन्धी पूर्वनिर्धारित सेटिङ परिवर्तन गर्नुहोस्"</string>
+    <string name="transcode_enable_all" msgid="2411165920039166710">"ट्रान्सकोडिङ अन गर्नुहोस्"</string>
+    <string name="transcode_default" msgid="3784803084573509491">"एपहरूमा आधुनिक फर्म्याट प्रयोग गर्न मिल्छ भनी मान्नुहोस्"</string>
     <string name="runningservices_settings_title" msgid="6460099290493086515">"चलिरहेका सेवाहरू"</string>
     <string name="runningservices_settings_summary" msgid="1046080643262665743">"हाल चालु भइरहेका सेवाहरू हेर्नुहोस् र नियन्त्रण गर्नुहोस्"</string>
     <string name="select_webview_provider_title" msgid="3917815648099445503">"WebView कार्यान्वयन"</string>
@@ -569,4 +565,29 @@
     <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"तारसहितको हेडफोन"</string>
     <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"अन छ"</string>
     <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"अफ छ"</string>
+    <string name="carrier_network_change_mode" msgid="4257621815706644026">"सेवा प्रदायकको नेटवर्क परिवर्तन गर्ने आइकन"</string>
+    <string name="data_connection_3g" msgid="931852552688157407">"3G"</string>
+    <string name="data_connection_edge" msgid="4625509456544797637">"EDGE"</string>
+    <string name="data_connection_cdma" msgid="9098161966701934334">"1X"</string>
+    <string name="data_connection_gprs" msgid="1251945769006770189">"GPRS"</string>
+    <string name="data_connection_3_5g" msgid="4298721462047921400">"H"</string>
+    <string name="data_connection_3_5g_plus" msgid="6683055858295918170">"H+"</string>
+    <string name="data_connection_4g" msgid="2581705503356752044">"4G"</string>
+    <string name="data_connection_4g_plus" msgid="5194902328408751020">"4G+"</string>
+    <string name="data_connection_lte" msgid="7675461204366364124">"LTE"</string>
+    <string name="data_connection_lte_plus" msgid="6643158654804916653">"LTE+"</string>
+    <string name="cell_data_off_content_description" msgid="2280700839891636498">"मोबाइल डेटा निष्क्रिय छ"</string>
+    <string name="not_default_data_content_description" msgid="6517068332106592887">"डेटा प्रयोग गर्ने गरी सेट गरिएन"</string>
+    <string name="accessibility_no_phone" msgid="2687419663127582503">"फोन छैन्।"</string>
+    <string name="accessibility_phone_one_bar" msgid="5719721147018970063">"फोन एउटा पट्टि।"</string>
+    <string name="accessibility_phone_two_bars" msgid="2531458337458953263">"फोन दुई पट्टि।"</string>
+    <string name="accessibility_phone_three_bars" msgid="1523967995996696619">"फोन तिन पट्टिहरू।"</string>
+    <string name="accessibility_phone_signal_full" msgid="4302338883816077134">"फोन सङ्केत भरिएको।"</string>
+    <string name="accessibility_no_data" msgid="4563181886936931008">"डेटा छैन।"</string>
+    <string name="accessibility_data_one_bar" msgid="6892888138070752480">"डेटाको एउटा पट्टि।"</string>
+    <string name="accessibility_data_two_bars" msgid="9202641507241802499">"डेटा दुई बाधाहरू।"</string>
+    <string name="accessibility_data_three_bars" msgid="2813876214466722413">"डेटा तिन बाधाहरू।"</string>
+    <string name="accessibility_data_signal_full" msgid="1808301899314382337">"डेटा संकेत पूर्ण।"</string>
+    <string name="accessibility_ethernet_disconnected" msgid="2832501530856497489">"इथरनेट विच्छेद भयो।"</string>
+    <string name="accessibility_ethernet_connected" msgid="2093872142317190618">"इथरनेट जोडियो।"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-nl/strings.xml b/packages/SettingsLib/res/values-nl/strings.xml
index 0f2cc6f..0b75fdd 100644
--- a/packages/SettingsLib/res/values-nl/strings.xml
+++ b/packages/SettingsLib/res/values-nl/strings.xml
@@ -403,7 +403,6 @@
     <string name="transcode_user_control" msgid="6176368544817731314">"Standaardwaarden voor transcodering overschrijven"</string>
     <string name="transcode_enable_all" msgid="2411165920039166710">"Transcodering inschakelen"</string>
     <string name="transcode_default" msgid="3784803084573509491">"Aannemen dat apps moderne indelingen ondersteunen"</string>
-    <string name="transcode_skip_apps" msgid="8249721984597390142">"Transcodering inschakelen voor apps"</string>
     <string name="runningservices_settings_title" msgid="6460099290493086515">"Actieve services"</string>
     <string name="runningservices_settings_summary" msgid="1046080643262665743">"Services die momenteel actief zijn, weergeven en beheren"</string>
     <string name="select_webview_provider_title" msgid="3917815648099445503">"WebView-implementatie"</string>
@@ -566,4 +565,29 @@
     <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Bedrade hoofdtelefoon"</string>
     <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Aan"</string>
     <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Uit"</string>
+    <string name="carrier_network_change_mode" msgid="4257621815706644026">"Netwerk van provider wordt gewijzigd"</string>
+    <string name="data_connection_3g" msgid="931852552688157407">"3G"</string>
+    <string name="data_connection_edge" msgid="4625509456544797637">"EDGE"</string>
+    <string name="data_connection_cdma" msgid="9098161966701934334">"1X"</string>
+    <string name="data_connection_gprs" msgid="1251945769006770189">"GPRS"</string>
+    <string name="data_connection_3_5g" msgid="4298721462047921400">"H"</string>
+    <string name="data_connection_3_5g_plus" msgid="6683055858295918170">"H+"</string>
+    <string name="data_connection_4g" msgid="2581705503356752044">"4G"</string>
+    <string name="data_connection_4g_plus" msgid="5194902328408751020">"4G+"</string>
+    <string name="data_connection_lte" msgid="7675461204366364124">"LTE"</string>
+    <string name="data_connection_lte_plus" msgid="6643158654804916653">"LTE+"</string>
+    <string name="cell_data_off_content_description" msgid="2280700839891636498">"Mobiele data uit"</string>
+    <string name="not_default_data_content_description" msgid="6517068332106592887">"Gebruik van gegevens is niet ingesteld"</string>
+    <string name="accessibility_no_phone" msgid="2687419663127582503">"Geen telefoonsignaal."</string>
+    <string name="accessibility_phone_one_bar" msgid="5719721147018970063">"Telefoon: één streepje."</string>
+    <string name="accessibility_phone_two_bars" msgid="2531458337458953263">"Telefoon: twee streepjes."</string>
+    <string name="accessibility_phone_three_bars" msgid="1523967995996696619">"Telefoon: drie streepjes."</string>
+    <string name="accessibility_phone_signal_full" msgid="4302338883816077134">"Telefoonsignaal is op volle sterkte."</string>
+    <string name="accessibility_no_data" msgid="4563181886936931008">"Geen gegevens."</string>
+    <string name="accessibility_data_one_bar" msgid="6892888138070752480">"Gegevens: één streepje."</string>
+    <string name="accessibility_data_two_bars" msgid="9202641507241802499">"Gegevens: twee streepjes."</string>
+    <string name="accessibility_data_three_bars" msgid="2813876214466722413">"Gegevens: drie streepjes."</string>
+    <string name="accessibility_data_signal_full" msgid="1808301899314382337">"Gegevenssignaal is op volle sterkte."</string>
+    <string name="accessibility_ethernet_disconnected" msgid="2832501530856497489">"Ethernetverbinding verbroken."</string>
+    <string name="accessibility_ethernet_connected" msgid="2093872142317190618">"Ethernet verbonden."</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-or/strings.xml b/packages/SettingsLib/res/values-or/strings.xml
index 040dddd..cfde61f 100644
--- a/packages/SettingsLib/res/values-or/strings.xml
+++ b/packages/SettingsLib/res/values-or/strings.xml
@@ -400,13 +400,9 @@
     <string name="inactive_app_active_summary" msgid="8047630990208722344">"ସକ୍ରିୟ। ବଦଳାଇବା ପାଇଁ ଟାପ୍‌ କରନ୍ତୁ"</string>
     <string name="standby_bucket_summary" msgid="5128193447550429600">"ଆପ୍ ଷ୍ଟାଣ୍ଡବାଏ ଅବସ୍ଥା:<xliff:g id="BUCKET"> %s</xliff:g>"</string>
     <string name="transcode_settings_title" msgid="2581975870429850549">"ମିଡିଆ ଟ୍ରାନ୍ସକୋଡିଂ ସେଟିଂସ୍"</string>
-    <!-- no translation found for transcode_user_control (6176368544817731314) -->
-    <skip />
-    <!-- no translation found for transcode_enable_all (2411165920039166710) -->
-    <skip />
-    <!-- no translation found for transcode_default (3784803084573509491) -->
-    <skip />
-    <string name="transcode_skip_apps" msgid="8249721984597390142">"ଆପଗୁଡ଼ିକ ପାଇଁ ଟ୍ରାନ୍ସକୋଡିଂ ସକ୍ଷମ କରନ୍ତୁ"</string>
+    <string name="transcode_user_control" msgid="6176368544817731314">"ଟ୍ରାନ୍ସକୋଡିଂ ଡିଫଲ୍ଟଗୁଡ଼ିକୁ ଓଭରରାଇଡ୍ କରନ୍ତୁ"</string>
+    <string name="transcode_enable_all" msgid="2411165920039166710">"ଟ୍ରାନ୍ସକୋଡିଂକୁ ସକ୍ଷମ କରନ୍ତୁ"</string>
+    <string name="transcode_default" msgid="3784803084573509491">"ଧରିନିଅନ୍ତୁ ଆପଗୁଡ଼ିକ ଆଧୁନିକ ଫର୍ମାଟଗୁଡ଼ିକୁ ସମର୍ଥନ କରେ"</string>
     <string name="runningservices_settings_title" msgid="6460099290493086515">"ଚାଲୁଥିବା ସେବାଗୁଡ଼ିକ"</string>
     <string name="runningservices_settings_summary" msgid="1046080643262665743">"ଏବେ ଚାଲୁଥିବା ସେବାଗୁଡ଼ିକୁ ଦେଖନ୍ତୁ ଓ ନିୟନ୍ତ୍ରଣ କରନ୍ତୁ"</string>
     <string name="select_webview_provider_title" msgid="3917815648099445503">"ୱେବ୍‌ଭ୍ୟୁ ପ୍ରୟୋଗ"</string>
@@ -569,4 +565,29 @@
     <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"ତାରଯୁକ୍ତ ହେଡଫୋନ୍"</string>
     <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"ଚାଲୁ ଅଛି"</string>
     <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"ବନ୍ଦ ଅଛି"</string>
+    <string name="carrier_network_change_mode" msgid="4257621815706644026">"କେରିଅର୍‍ ନେଟ୍‌ୱର୍କ ବଦଳୁଛି"</string>
+    <string name="data_connection_3g" msgid="931852552688157407">"3G"</string>
+    <string name="data_connection_edge" msgid="4625509456544797637">"EDGE"</string>
+    <string name="data_connection_cdma" msgid="9098161966701934334">"1X"</string>
+    <string name="data_connection_gprs" msgid="1251945769006770189">"GPRS"</string>
+    <string name="data_connection_3_5g" msgid="4298721462047921400">"H"</string>
+    <string name="data_connection_3_5g_plus" msgid="6683055858295918170">"H+"</string>
+    <string name="data_connection_4g" msgid="2581705503356752044">"4G"</string>
+    <string name="data_connection_4g_plus" msgid="5194902328408751020">"4G+"</string>
+    <string name="data_connection_lte" msgid="7675461204366364124">"LTE"</string>
+    <string name="data_connection_lte_plus" msgid="6643158654804916653">"LTE+"</string>
+    <string name="cell_data_off_content_description" msgid="2280700839891636498">"ମୋବାଇଲ୍‌ ଡାଟା ବନ୍ଦ ଅଛି"</string>
+    <string name="not_default_data_content_description" msgid="6517068332106592887">"ବ୍ୟବହୃତ ଡାଟା ପାଇଁ ସେଟ୍ ହୋଇନାହିଁ"</string>
+    <string name="accessibility_no_phone" msgid="2687419663127582503">"କୌଣସି ଫୋନ୍ ନାହିଁ।"</string>
+    <string name="accessibility_phone_one_bar" msgid="5719721147018970063">"ଫୋନର ଗୋଟିଏ ବାର ଅଛି।"</string>
+    <string name="accessibility_phone_two_bars" msgid="2531458337458953263">"ଫୋନର ଦୁଇଟି ବାର୍‌ ଅଛି।"</string>
+    <string name="accessibility_phone_three_bars" msgid="1523967995996696619">"ଫୋନ୍‍ରେ ତିନୋଟି ବାର୍‍ ଅଛି।"</string>
+    <string name="accessibility_phone_signal_full" msgid="4302338883816077134">"ଫୋନ୍ ସିଗ୍ନାଲ୍ ପୂର୍ଣ୍ଣ ଅଛି।"</string>
+    <string name="accessibility_no_data" msgid="4563181886936931008">"କୌଣସି ଡାଟା ନାହିଁ।"</string>
+    <string name="accessibility_data_one_bar" msgid="6892888138070752480">"ଡାଟାର ଗୋଟିଏ ବାର ଅଛି।"</string>
+    <string name="accessibility_data_two_bars" msgid="9202641507241802499">"ଡାଟାର ଦୁଇଟି ବାର୍‌ ଅଛି।"</string>
+    <string name="accessibility_data_three_bars" msgid="2813876214466722413">"ଡାଟାର ତିନୋଟି ବାର୍‍ ଅଛି।"</string>
+    <string name="accessibility_data_signal_full" msgid="1808301899314382337">"ଡାଟା ସିଗ୍ନାଲ୍ ପୂର୍ଣ୍ଣ ଅଛି।"</string>
+    <string name="accessibility_ethernet_disconnected" msgid="2832501530856497489">"ଇଥରନେଟ୍‍ ବିଚ୍ଛିନ୍ନ ହୋଇଛି।"</string>
+    <string name="accessibility_ethernet_connected" msgid="2093872142317190618">"ଇଥରନେଟ୍‍ ସଂଯୁକ୍ତ ହୋଇଛି।"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-pa/strings.xml b/packages/SettingsLib/res/values-pa/strings.xml
index e6adff3..1221862 100644
--- a/packages/SettingsLib/res/values-pa/strings.xml
+++ b/packages/SettingsLib/res/values-pa/strings.xml
@@ -400,13 +400,9 @@
     <string name="inactive_app_active_summary" msgid="8047630990208722344">"ਕਿਰਿਆਸ਼ੀਲ। ਟੌਗਲ ਕਰਨ ਲਈ ਟੈਪ ਕਰੋ।"</string>
     <string name="standby_bucket_summary" msgid="5128193447550429600">"ਐਪ ਸਟੈਂਡਬਾਈ ਸਥਿਤੀ:<xliff:g id="BUCKET"> %s</xliff:g>"</string>
     <string name="transcode_settings_title" msgid="2581975870429850549">"ਮੀਡੀਆ ਟ੍ਰਾਂਸਕੋਡਿੰਗ ਸੈਟਿੰਗਾਂ"</string>
-    <!-- no translation found for transcode_user_control (6176368544817731314) -->
-    <skip />
-    <!-- no translation found for transcode_enable_all (2411165920039166710) -->
-    <skip />
-    <!-- no translation found for transcode_default (3784803084573509491) -->
-    <skip />
-    <string name="transcode_skip_apps" msgid="8249721984597390142">"ਐਪਾਂ ਲਈ ਟ੍ਰਾਂਸਕੋਡਿੰਗ ਚਾਲੂ ਕਰੋ"</string>
+    <string name="transcode_user_control" msgid="6176368544817731314">"ਟ੍ਰਾਂਸਕੋਡਿੰਗ ਦੀਆਂ ਪੂਰਵ-ਨਿਰਧਾਰਤ ਸੈਟਿੰਗਾਂ ਨੂੰ ਓਵਰਰਾਈਡ ਕਰੋ"</string>
+    <string name="transcode_enable_all" msgid="2411165920039166710">"ਟ੍ਰਾਂਸਕੋਡਿੰਗ ਚਾਲੂ ਕਰੋ"</string>
+    <string name="transcode_default" msgid="3784803084573509491">"ਮੰਨ ਲਓ ਕਿ ਐਪਾਂ ਆਧੁਨਿਕ ਫਾਰਮੈਟਾਂ ਦਾ ਸਮਰਥਨ ਕਰਦੀਆਂ ਹਨ"</string>
     <string name="runningservices_settings_title" msgid="6460099290493086515">"ਚੱਲ ਰਹੀਆਂ ਸੇਵਾਵਾਂ"</string>
     <string name="runningservices_settings_summary" msgid="1046080643262665743">"ਇਸ ਵੇਲੇ ਚੱਲ ਰਹੀਆਂ ਸੇਵਾਵਾਂ ਦੇਖੋ ਅਤੇ ਇਹਨਾਂ ਨੂੰ ਕੰਟਰੋਲ ਕਰੋ"</string>
     <string name="select_webview_provider_title" msgid="3917815648099445503">"WebView ਅਮਲ"</string>
@@ -569,4 +565,29 @@
     <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"ਤਾਰ ਵਾਲੇ ਹੈੱਡਫ਼ੋਨ"</string>
     <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"ਚਾਲੂ"</string>
     <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"ਬੰਦ"</string>
+    <string name="carrier_network_change_mode" msgid="4257621815706644026">"ਕੈਰੀਅਰ ਨੈੱਟਵਰਕ ਦੀ ਬਦਲੀ"</string>
+    <string name="data_connection_3g" msgid="931852552688157407">"3G"</string>
+    <string name="data_connection_edge" msgid="4625509456544797637">"EDGE"</string>
+    <string name="data_connection_cdma" msgid="9098161966701934334">"1X"</string>
+    <string name="data_connection_gprs" msgid="1251945769006770189">"GPRS"</string>
+    <string name="data_connection_3_5g" msgid="4298721462047921400">"H"</string>
+    <string name="data_connection_3_5g_plus" msgid="6683055858295918170">"H+"</string>
+    <string name="data_connection_4g" msgid="2581705503356752044">"4G"</string>
+    <string name="data_connection_4g_plus" msgid="5194902328408751020">"4G+"</string>
+    <string name="data_connection_lte" msgid="7675461204366364124">"LTE"</string>
+    <string name="data_connection_lte_plus" msgid="6643158654804916653">"LTE+"</string>
+    <string name="cell_data_off_content_description" msgid="2280700839891636498">"ਮੋਬਾਈਲ ਡਾਟਾ ਬੰਦ"</string>
+    <string name="not_default_data_content_description" msgid="6517068332106592887">"ਡਾਟਾ ਵਰਤਣ ਲਈ ਸੈੱਟ ਨਹੀਂ"</string>
+    <string name="accessibility_no_phone" msgid="2687419663127582503">"ਕੋਈ ਫ਼ੋਨ ਨਹੀਂ।"</string>
+    <string name="accessibility_phone_one_bar" msgid="5719721147018970063">"ਫ਼ੋਨ ਇੱਕ ਬਾਰ।"</string>
+    <string name="accessibility_phone_two_bars" msgid="2531458337458953263">"ਫ਼ੋਨ ਦੋ ਬਾਰਸ।"</string>
+    <string name="accessibility_phone_three_bars" msgid="1523967995996696619">"ਫ਼ੋਨ ਤਿੰਨ ਬਾਰਸ।"</string>
+    <string name="accessibility_phone_signal_full" msgid="4302338883816077134">"ਫ਼ੋਨ ਸਿਗਨਲ ਪੂਰਾ।"</string>
+    <string name="accessibility_no_data" msgid="4563181886936931008">"ਕੋਈ  ਡਾਟਾ  ਨਹੀਂ।"</string>
+    <string name="accessibility_data_one_bar" msgid="6892888138070752480">" ਡਾਟਾ  ਇੱਕ ਬਾਰ।"</string>
+    <string name="accessibility_data_two_bars" msgid="9202641507241802499">" ਡਾਟਾ  ਦੋ ਬਾਰਸ।"</string>
+    <string name="accessibility_data_three_bars" msgid="2813876214466722413">" ਡਾਟਾ  ਤਿੰਨ ਬਾਰ।"</string>
+    <string name="accessibility_data_signal_full" msgid="1808301899314382337">" ਡਾਟਾ  ਸਿਗਨਲ ਪੂਰਾ।"</string>
+    <string name="accessibility_ethernet_disconnected" msgid="2832501530856497489">"ਈਥਰਨੈੱਟ ਡਿਸਕਨੈਕਟ ਹੋ ਗਿਆ।"</string>
+    <string name="accessibility_ethernet_connected" msgid="2093872142317190618">"ਈਥਰਨੈੱਟ ਕਨੈਕਟ ਹੋ ਗਿਆ।"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-pl/strings.xml b/packages/SettingsLib/res/values-pl/strings.xml
index 5690e74..102835c 100644
--- a/packages/SettingsLib/res/values-pl/strings.xml
+++ b/packages/SettingsLib/res/values-pl/strings.xml
@@ -400,13 +400,9 @@
     <string name="inactive_app_active_summary" msgid="8047630990208722344">"Aktywna. Dotknij, by zmienić."</string>
     <string name="standby_bucket_summary" msgid="5128193447550429600">"Stan aplikacji w trybie czuwania: <xliff:g id="BUCKET"> %s</xliff:g>"</string>
     <string name="transcode_settings_title" msgid="2581975870429850549">"Ustawienia transkodowania multimediów"</string>
-    <!-- no translation found for transcode_user_control (6176368544817731314) -->
-    <skip />
-    <!-- no translation found for transcode_enable_all (2411165920039166710) -->
-    <skip />
-    <!-- no translation found for transcode_default (3784803084573509491) -->
-    <skip />
-    <string name="transcode_skip_apps" msgid="8249721984597390142">"Włącz transkodowanie dla aplikacji"</string>
+    <string name="transcode_user_control" msgid="6176368544817731314">"Zastąp ustawienia domyślne transkodowania"</string>
+    <string name="transcode_enable_all" msgid="2411165920039166710">"Włącz transkodowanie"</string>
+    <string name="transcode_default" msgid="3784803084573509491">"Zakładaj, że aplikacje obsługują nowoczesne formaty"</string>
     <string name="runningservices_settings_title" msgid="6460099290493086515">"Uruchomione usługi"</string>
     <string name="runningservices_settings_summary" msgid="1046080643262665743">"Wyświetl obecnie uruchomione usługi i nimi zarządzaj"</string>
     <string name="select_webview_provider_title" msgid="3917815648099445503">"Implementacja WebView"</string>
@@ -571,4 +567,29 @@
     <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Słuchawki przewodowe"</string>
     <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Włączono"</string>
     <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Wyłączono"</string>
+    <string name="carrier_network_change_mode" msgid="4257621815706644026">"Zmiana sieci operatora"</string>
+    <string name="data_connection_3g" msgid="931852552688157407">"3G"</string>
+    <string name="data_connection_edge" msgid="4625509456544797637">"EDGE"</string>
+    <string name="data_connection_cdma" msgid="9098161966701934334">"1X"</string>
+    <string name="data_connection_gprs" msgid="1251945769006770189">"GPRS"</string>
+    <string name="data_connection_3_5g" msgid="4298721462047921400">"H"</string>
+    <string name="data_connection_3_5g_plus" msgid="6683055858295918170">"H+"</string>
+    <string name="data_connection_4g" msgid="2581705503356752044">"4G"</string>
+    <string name="data_connection_4g_plus" msgid="5194902328408751020">"4G+"</string>
+    <string name="data_connection_lte" msgid="7675461204366364124">"LTE"</string>
+    <string name="data_connection_lte_plus" msgid="6643158654804916653">"LTE+"</string>
+    <string name="cell_data_off_content_description" msgid="2280700839891636498">"Wyłączona"</string>
+    <string name="not_default_data_content_description" msgid="6517068332106592887">"Nie skonfigurowano do transmisji danych"</string>
+    <string name="accessibility_no_phone" msgid="2687419663127582503">"Brak sygnału telefonu."</string>
+    <string name="accessibility_phone_one_bar" msgid="5719721147018970063">"Telefon: jeden pasek."</string>
+    <string name="accessibility_phone_two_bars" msgid="2531458337458953263">"Telefon: dwa paski."</string>
+    <string name="accessibility_phone_three_bars" msgid="1523967995996696619">"Telefon: trzy paski."</string>
+    <string name="accessibility_phone_signal_full" msgid="4302338883816077134">"Telefon: pełna moc sygnału."</string>
+    <string name="accessibility_no_data" msgid="4563181886936931008">"Brak danych."</string>
+    <string name="accessibility_data_one_bar" msgid="6892888138070752480">"Dane: jeden pasek."</string>
+    <string name="accessibility_data_two_bars" msgid="9202641507241802499">"Dane: dwa paski."</string>
+    <string name="accessibility_data_three_bars" msgid="2813876214466722413">"Dane: trzy paski."</string>
+    <string name="accessibility_data_signal_full" msgid="1808301899314382337">"Dane: pełna moc sygnału."</string>
+    <string name="accessibility_ethernet_disconnected" msgid="2832501530856497489">"Rozłączono z siecią Ethernet."</string>
+    <string name="accessibility_ethernet_connected" msgid="2093872142317190618">"Połączono z siecią Ethernet."</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-pt-rBR/strings.xml b/packages/SettingsLib/res/values-pt-rBR/strings.xml
index a0ddcf2..99019a6 100644
--- a/packages/SettingsLib/res/values-pt-rBR/strings.xml
+++ b/packages/SettingsLib/res/values-pt-rBR/strings.xml
@@ -403,7 +403,6 @@
     <string name="transcode_user_control" msgid="6176368544817731314">"Substituir os padrões de transcodificação"</string>
     <string name="transcode_enable_all" msgid="2411165920039166710">"Ativar transcodificação"</string>
     <string name="transcode_default" msgid="3784803084573509491">"Considerar que os apps são compatíveis com formatos modernos"</string>
-    <string name="transcode_skip_apps" msgid="8249721984597390142">"Ativar transcodificação para apps"</string>
     <string name="runningservices_settings_title" msgid="6460099290493086515">"Serviços em execução"</string>
     <string name="runningservices_settings_summary" msgid="1046080643262665743">"Visualizar e controlar os serviços em execução no momento"</string>
     <string name="select_webview_provider_title" msgid="3917815648099445503">"Implementação do WebView"</string>
@@ -566,4 +565,29 @@
     <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Fones de ouvido com fio"</string>
     <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Ativado"</string>
     <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Desativado"</string>
+    <string name="carrier_network_change_mode" msgid="4257621815706644026">"Alteração de rede da operadora"</string>
+    <string name="data_connection_3g" msgid="931852552688157407">"3G"</string>
+    <string name="data_connection_edge" msgid="4625509456544797637">"EDGE"</string>
+    <string name="data_connection_cdma" msgid="9098161966701934334">"1X"</string>
+    <string name="data_connection_gprs" msgid="1251945769006770189">"GPRS"</string>
+    <string name="data_connection_3_5g" msgid="4298721462047921400">"H"</string>
+    <string name="data_connection_3_5g_plus" msgid="6683055858295918170">"H+"</string>
+    <string name="data_connection_4g" msgid="2581705503356752044">"4G"</string>
+    <string name="data_connection_4g_plus" msgid="5194902328408751020">"4G+"</string>
+    <string name="data_connection_lte" msgid="7675461204366364124">"LTE"</string>
+    <string name="data_connection_lte_plus" msgid="6643158654804916653">"LTE+"</string>
+    <string name="cell_data_off_content_description" msgid="2280700839891636498">"Dados móveis desativados"</string>
+    <string name="not_default_data_content_description" msgid="6517068332106592887">"Sem configuração para uso de dados"</string>
+    <string name="accessibility_no_phone" msgid="2687419663127582503">"Sem telefone."</string>
+    <string name="accessibility_phone_one_bar" msgid="5719721147018970063">"Uma barra de sinal do telefone."</string>
+    <string name="accessibility_phone_two_bars" msgid="2531458337458953263">"Duas barras de sinal do telefone."</string>
+    <string name="accessibility_phone_three_bars" msgid="1523967995996696619">"Três barras de sinal do telefone."</string>
+    <string name="accessibility_phone_signal_full" msgid="4302338883816077134">"Sinal do telefone cheio."</string>
+    <string name="accessibility_no_data" msgid="4563181886936931008">"Nenhum dado."</string>
+    <string name="accessibility_data_one_bar" msgid="6892888138070752480">"Uma barra de sinal de dados."</string>
+    <string name="accessibility_data_two_bars" msgid="9202641507241802499">"Duas barras de sinal de dados."</string>
+    <string name="accessibility_data_three_bars" msgid="2813876214466722413">"Três barras do sinal de dados."</string>
+    <string name="accessibility_data_signal_full" msgid="1808301899314382337">"Sinal de dados cheio."</string>
+    <string name="accessibility_ethernet_disconnected" msgid="2832501530856497489">"Ethernet desconectada."</string>
+    <string name="accessibility_ethernet_connected" msgid="2093872142317190618">"Ethernet conectada."</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-pt-rPT/strings.xml b/packages/SettingsLib/res/values-pt-rPT/strings.xml
index adaed74..238e54b 100644
--- a/packages/SettingsLib/res/values-pt-rPT/strings.xml
+++ b/packages/SettingsLib/res/values-pt-rPT/strings.xml
@@ -403,7 +403,6 @@
     <string name="transcode_user_control" msgid="6176368544817731314">"Substituir as predefinições da transcodificação"</string>
     <string name="transcode_enable_all" msgid="2411165920039166710">"Ativar a transcodificação"</string>
     <string name="transcode_default" msgid="3784803084573509491">"Assumir que as apps suportam formatos modernos"</string>
-    <string name="transcode_skip_apps" msgid="8249721984597390142">"Ative a transcodificação para apps"</string>
     <string name="runningservices_settings_title" msgid="6460099290493086515">"Serviços em execução"</string>
     <string name="runningservices_settings_summary" msgid="1046080643262665743">"Ver e controlar os serviços actualmente em execução"</string>
     <string name="select_webview_provider_title" msgid="3917815648099445503">"Implementação WebView"</string>
@@ -566,4 +565,29 @@
     <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Auscultadores com fios"</string>
     <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Ligado"</string>
     <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Desligado"</string>
+    <string name="carrier_network_change_mode" msgid="4257621815706644026">"Rede do operador em mudança."</string>
+    <string name="data_connection_3g" msgid="931852552688157407">"3G"</string>
+    <string name="data_connection_edge" msgid="4625509456544797637">"EDGE"</string>
+    <string name="data_connection_cdma" msgid="9098161966701934334">"1X"</string>
+    <string name="data_connection_gprs" msgid="1251945769006770189">"GPRS"</string>
+    <string name="data_connection_3_5g" msgid="4298721462047921400">"H"</string>
+    <string name="data_connection_3_5g_plus" msgid="6683055858295918170">"H+"</string>
+    <string name="data_connection_4g" msgid="2581705503356752044">"4G"</string>
+    <string name="data_connection_4g_plus" msgid="5194902328408751020">"4G+"</string>
+    <string name="data_connection_lte" msgid="7675461204366364124">"LTE"</string>
+    <string name="data_connection_lte_plus" msgid="6643158654804916653">"LTE+"</string>
+    <string name="cell_data_off_content_description" msgid="2280700839891636498">"Dados móveis desativados"</string>
+    <string name="not_default_data_content_description" msgid="6517068332106592887">"Não definido para utilizar dados"</string>
+    <string name="accessibility_no_phone" msgid="2687419663127582503">"Sem telefone."</string>
+    <string name="accessibility_phone_one_bar" msgid="5719721147018970063">"Uma barra de telefone."</string>
+    <string name="accessibility_phone_two_bars" msgid="2531458337458953263">"Duas barras de telefone."</string>
+    <string name="accessibility_phone_three_bars" msgid="1523967995996696619">"Três barras de telefone."</string>
+    <string name="accessibility_phone_signal_full" msgid="4302338883816077134">"Sinal de telefone completo."</string>
+    <string name="accessibility_no_data" msgid="4563181886936931008">"Sem dados."</string>
+    <string name="accessibility_data_one_bar" msgid="6892888138070752480">"Uma barra de dados."</string>
+    <string name="accessibility_data_two_bars" msgid="9202641507241802499">"Duas barras de dados."</string>
+    <string name="accessibility_data_three_bars" msgid="2813876214466722413">"Três barras de dados."</string>
+    <string name="accessibility_data_signal_full" msgid="1808301899314382337">"Sinal de dados completo."</string>
+    <string name="accessibility_ethernet_disconnected" msgid="2832501530856497489">"Ethernet desligada."</string>
+    <string name="accessibility_ethernet_connected" msgid="2093872142317190618">"Ethernet ligada."</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-pt/strings.xml b/packages/SettingsLib/res/values-pt/strings.xml
index a0ddcf2..99019a6 100644
--- a/packages/SettingsLib/res/values-pt/strings.xml
+++ b/packages/SettingsLib/res/values-pt/strings.xml
@@ -403,7 +403,6 @@
     <string name="transcode_user_control" msgid="6176368544817731314">"Substituir os padrões de transcodificação"</string>
     <string name="transcode_enable_all" msgid="2411165920039166710">"Ativar transcodificação"</string>
     <string name="transcode_default" msgid="3784803084573509491">"Considerar que os apps são compatíveis com formatos modernos"</string>
-    <string name="transcode_skip_apps" msgid="8249721984597390142">"Ativar transcodificação para apps"</string>
     <string name="runningservices_settings_title" msgid="6460099290493086515">"Serviços em execução"</string>
     <string name="runningservices_settings_summary" msgid="1046080643262665743">"Visualizar e controlar os serviços em execução no momento"</string>
     <string name="select_webview_provider_title" msgid="3917815648099445503">"Implementação do WebView"</string>
@@ -566,4 +565,29 @@
     <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Fones de ouvido com fio"</string>
     <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Ativado"</string>
     <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Desativado"</string>
+    <string name="carrier_network_change_mode" msgid="4257621815706644026">"Alteração de rede da operadora"</string>
+    <string name="data_connection_3g" msgid="931852552688157407">"3G"</string>
+    <string name="data_connection_edge" msgid="4625509456544797637">"EDGE"</string>
+    <string name="data_connection_cdma" msgid="9098161966701934334">"1X"</string>
+    <string name="data_connection_gprs" msgid="1251945769006770189">"GPRS"</string>
+    <string name="data_connection_3_5g" msgid="4298721462047921400">"H"</string>
+    <string name="data_connection_3_5g_plus" msgid="6683055858295918170">"H+"</string>
+    <string name="data_connection_4g" msgid="2581705503356752044">"4G"</string>
+    <string name="data_connection_4g_plus" msgid="5194902328408751020">"4G+"</string>
+    <string name="data_connection_lte" msgid="7675461204366364124">"LTE"</string>
+    <string name="data_connection_lte_plus" msgid="6643158654804916653">"LTE+"</string>
+    <string name="cell_data_off_content_description" msgid="2280700839891636498">"Dados móveis desativados"</string>
+    <string name="not_default_data_content_description" msgid="6517068332106592887">"Sem configuração para uso de dados"</string>
+    <string name="accessibility_no_phone" msgid="2687419663127582503">"Sem telefone."</string>
+    <string name="accessibility_phone_one_bar" msgid="5719721147018970063">"Uma barra de sinal do telefone."</string>
+    <string name="accessibility_phone_two_bars" msgid="2531458337458953263">"Duas barras de sinal do telefone."</string>
+    <string name="accessibility_phone_three_bars" msgid="1523967995996696619">"Três barras de sinal do telefone."</string>
+    <string name="accessibility_phone_signal_full" msgid="4302338883816077134">"Sinal do telefone cheio."</string>
+    <string name="accessibility_no_data" msgid="4563181886936931008">"Nenhum dado."</string>
+    <string name="accessibility_data_one_bar" msgid="6892888138070752480">"Uma barra de sinal de dados."</string>
+    <string name="accessibility_data_two_bars" msgid="9202641507241802499">"Duas barras de sinal de dados."</string>
+    <string name="accessibility_data_three_bars" msgid="2813876214466722413">"Três barras do sinal de dados."</string>
+    <string name="accessibility_data_signal_full" msgid="1808301899314382337">"Sinal de dados cheio."</string>
+    <string name="accessibility_ethernet_disconnected" msgid="2832501530856497489">"Ethernet desconectada."</string>
+    <string name="accessibility_ethernet_connected" msgid="2093872142317190618">"Ethernet conectada."</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-ro/strings.xml b/packages/SettingsLib/res/values-ro/strings.xml
index 266dff2..df95dbc 100644
--- a/packages/SettingsLib/res/values-ro/strings.xml
+++ b/packages/SettingsLib/res/values-ro/strings.xml
@@ -403,7 +403,6 @@
     <string name="transcode_user_control" msgid="6176368544817731314">"Modificați setările prestabilite de transcodare"</string>
     <string name="transcode_enable_all" msgid="2411165920039166710">"Activați transcodarea"</string>
     <string name="transcode_default" msgid="3784803084573509491">"Presupuneți că aplicațiile acceptă formatele moderne"</string>
-    <string name="transcode_skip_apps" msgid="8249721984597390142">"Activați transcodarea pentru aplicații"</string>
     <string name="runningservices_settings_title" msgid="6460099290493086515">"Servicii în curs de funcționare"</string>
     <string name="runningservices_settings_summary" msgid="1046080643262665743">"Vedeți și controlați serviciile care funcționează în prezent"</string>
     <string name="select_webview_provider_title" msgid="3917815648099445503">"Implementare WebView"</string>
@@ -567,4 +566,29 @@
     <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Căști cu fir"</string>
     <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Activat"</string>
     <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Dezactivat"</string>
+    <string name="carrier_network_change_mode" msgid="4257621815706644026">"Se schimbă rețeaua operatorului"</string>
+    <string name="data_connection_3g" msgid="931852552688157407">"3G"</string>
+    <string name="data_connection_edge" msgid="4625509456544797637">"EDGE"</string>
+    <string name="data_connection_cdma" msgid="9098161966701934334">"1X"</string>
+    <string name="data_connection_gprs" msgid="1251945769006770189">"GPRS"</string>
+    <string name="data_connection_3_5g" msgid="4298721462047921400">"H"</string>
+    <string name="data_connection_3_5g_plus" msgid="6683055858295918170">"H+"</string>
+    <string name="data_connection_4g" msgid="2581705503356752044">"4G"</string>
+    <string name="data_connection_4g_plus" msgid="5194902328408751020">"4G+"</string>
+    <string name="data_connection_lte" msgid="7675461204366364124">"LTE"</string>
+    <string name="data_connection_lte_plus" msgid="6643158654804916653">"LTE+"</string>
+    <string name="cell_data_off_content_description" msgid="2280700839891636498">"Date mobile dezactivate"</string>
+    <string name="not_default_data_content_description" msgid="6517068332106592887">"Nu este setat pentru a folosi datele"</string>
+    <string name="accessibility_no_phone" msgid="2687419663127582503">"Nu există semnal pentru telefon."</string>
+    <string name="accessibility_phone_one_bar" msgid="5719721147018970063">"Semnal pentru telefon: o bară."</string>
+    <string name="accessibility_phone_two_bars" msgid="2531458337458953263">"Semnal pentru telefon: două bare."</string>
+    <string name="accessibility_phone_three_bars" msgid="1523967995996696619">"Semnal pentru telefon: trei bare."</string>
+    <string name="accessibility_phone_signal_full" msgid="4302338883816077134">"Semnal pentru telefon: complet."</string>
+    <string name="accessibility_no_data" msgid="4563181886936931008">"Nu există semnal pentru date."</string>
+    <string name="accessibility_data_one_bar" msgid="6892888138070752480">"Semnal pentru date: o bară."</string>
+    <string name="accessibility_data_two_bars" msgid="9202641507241802499">"Semnal pentru date: două bare."</string>
+    <string name="accessibility_data_three_bars" msgid="2813876214466722413">"Semnal pentru date: trei bare."</string>
+    <string name="accessibility_data_signal_full" msgid="1808301899314382337">"Semnal pentru date: complet."</string>
+    <string name="accessibility_ethernet_disconnected" msgid="2832501530856497489">"Ethernet deconectat."</string>
+    <string name="accessibility_ethernet_connected" msgid="2093872142317190618">"Ethernet conectat."</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-ru/strings.xml b/packages/SettingsLib/res/values-ru/strings.xml
index ca20bae..68826d7 100644
--- a/packages/SettingsLib/res/values-ru/strings.xml
+++ b/packages/SettingsLib/res/values-ru/strings.xml
@@ -403,7 +403,6 @@
     <string name="transcode_user_control" msgid="6176368544817731314">"Переопределять настройки транскодирования по умолчанию"</string>
     <string name="transcode_enable_all" msgid="2411165920039166710">"Включить перекодирование"</string>
     <string name="transcode_default" msgid="3784803084573509491">"Считать, что приложения поддерживают современные форматы кодирования"</string>
-    <string name="transcode_skip_apps" msgid="8249721984597390142">"Включить перекодирование для приложений"</string>
     <string name="runningservices_settings_title" msgid="6460099290493086515">"Работающие службы"</string>
     <string name="runningservices_settings_summary" msgid="1046080643262665743">"Просмотр и управление работающими службами"</string>
     <string name="select_webview_provider_title" msgid="3917815648099445503">"Сервис WebView"</string>
@@ -568,4 +567,29 @@
     <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Проводные наушники"</string>
     <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Вкл."</string>
     <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Выкл."</string>
+    <string name="carrier_network_change_mode" msgid="4257621815706644026">"Сменить сеть"</string>
+    <string name="data_connection_3g" msgid="931852552688157407">"3G"</string>
+    <string name="data_connection_edge" msgid="4625509456544797637">"EDGE"</string>
+    <string name="data_connection_cdma" msgid="9098161966701934334">"1X"</string>
+    <string name="data_connection_gprs" msgid="1251945769006770189">"GPRS"</string>
+    <string name="data_connection_3_5g" msgid="4298721462047921400">"H"</string>
+    <string name="data_connection_3_5g_plus" msgid="6683055858295918170">"H+"</string>
+    <string name="data_connection_4g" msgid="2581705503356752044">"4G"</string>
+    <string name="data_connection_4g_plus" msgid="5194902328408751020">"4G+"</string>
+    <string name="data_connection_lte" msgid="7675461204366364124">"LTE"</string>
+    <string name="data_connection_lte_plus" msgid="6643158654804916653">"LTE+"</string>
+    <string name="cell_data_off_content_description" msgid="2280700839891636498">"Мобильный Интернет отключен"</string>
+    <string name="not_default_data_content_description" msgid="6517068332106592887">"Мобильный Интернет по умолчанию не используется."</string>
+    <string name="accessibility_no_phone" msgid="2687419663127582503">"Сигнал телефонной сети отсутствует."</string>
+    <string name="accessibility_phone_one_bar" msgid="5719721147018970063">"Сигнал телефонной сети: одно деление."</string>
+    <string name="accessibility_phone_two_bars" msgid="2531458337458953263">"Сигнал телефонной сети: два деления."</string>
+    <string name="accessibility_phone_three_bars" msgid="1523967995996696619">"Сигнал телефонной сети: три деления."</string>
+    <string name="accessibility_phone_signal_full" msgid="4302338883816077134">"Надежный телефонный сигнал."</string>
+    <string name="accessibility_no_data" msgid="4563181886936931008">"Сигнал передачи данных отсутствует."</string>
+    <string name="accessibility_data_one_bar" msgid="6892888138070752480">"Сигнал передачи данных: одно деление."</string>
+    <string name="accessibility_data_two_bars" msgid="9202641507241802499">"Сигнал передачи данных: два деления."</string>
+    <string name="accessibility_data_three_bars" msgid="2813876214466722413">"Сигнал передачи данных: три деления."</string>
+    <string name="accessibility_data_signal_full" msgid="1808301899314382337">"Надежный сигнал передачи данных."</string>
+    <string name="accessibility_ethernet_disconnected" msgid="2832501530856497489">"Устройство отключено от Ethernet."</string>
+    <string name="accessibility_ethernet_connected" msgid="2093872142317190618">"Устройство подключено к Ethernet."</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-si/strings.xml b/packages/SettingsLib/res/values-si/strings.xml
index da69b81..736445d 100644
--- a/packages/SettingsLib/res/values-si/strings.xml
+++ b/packages/SettingsLib/res/values-si/strings.xml
@@ -403,7 +403,6 @@
     <string name="transcode_user_control" msgid="6176368544817731314">"ට්‍රාන්ස්කෝඩින් පෙරනිමි ප්‍රතික්ෂේප කරන්න"</string>
     <string name="transcode_enable_all" msgid="2411165920039166710">"ට්‍රාන්ස්කෝඩින් සබල කරන්න"</string>
     <string name="transcode_default" msgid="3784803084573509491">"යෙදුම් නවීන ආකෘති සඳහා සහාය දක්වයි යැයි උපකල්පනය කරමු"</string>
-    <string name="transcode_skip_apps" msgid="8249721984597390142">"යෙදුම් සඳහා ට්‍රාන්ස්කෝඩින් සබල කරන්න"</string>
     <string name="runningservices_settings_title" msgid="6460099290493086515">"ධාවනය වන සේවා"</string>
     <string name="runningservices_settings_summary" msgid="1046080643262665743">"දැනට ධාවනය වන සේවා බලන්න සහ පාලනය කරන්න"</string>
     <string name="select_webview_provider_title" msgid="3917815648099445503">"WebView ක්‍රියාත්මක කිරීම"</string>
@@ -566,4 +565,29 @@
     <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"රැහැන්ගත කළ හෙඩ්ෆෝන්"</string>
     <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"ක්‍රියාත්මකයි"</string>
     <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"ක්‍රියාවිරහිතයි"</string>
+    <string name="carrier_network_change_mode" msgid="4257621815706644026">"වාහක ජාලය වෙනස් වෙමින්"</string>
+    <string name="data_connection_3g" msgid="931852552688157407">"3G"</string>
+    <string name="data_connection_edge" msgid="4625509456544797637">"EDGE"</string>
+    <string name="data_connection_cdma" msgid="9098161966701934334">"1X"</string>
+    <string name="data_connection_gprs" msgid="1251945769006770189">"GPRS"</string>
+    <string name="data_connection_3_5g" msgid="4298721462047921400">"H"</string>
+    <string name="data_connection_3_5g_plus" msgid="6683055858295918170">"H+"</string>
+    <string name="data_connection_4g" msgid="2581705503356752044">"4G"</string>
+    <string name="data_connection_4g_plus" msgid="5194902328408751020">"4G+"</string>
+    <string name="data_connection_lte" msgid="7675461204366364124">"LTE"</string>
+    <string name="data_connection_lte_plus" msgid="6643158654804916653">"LTE+"</string>
+    <string name="cell_data_off_content_description" msgid="2280700839891636498">"ජංගම දත්ත ක්‍රියාවිරහිතයි"</string>
+    <string name="not_default_data_content_description" msgid="6517068332106592887">"දත්ත භාවිත කිරීමට සකසා නැත"</string>
+    <string name="accessibility_no_phone" msgid="2687419663127582503">"දුරකථනයක් නැත."</string>
+    <string name="accessibility_phone_one_bar" msgid="5719721147018970063">"දුරකථනය තීරු එකයි."</string>
+    <string name="accessibility_phone_two_bars" msgid="2531458337458953263">"දුරකථනය තීරු දෙකයි."</string>
+    <string name="accessibility_phone_three_bars" msgid="1523967995996696619">"දුරකථනය තීරු තුනයි."</string>
+    <string name="accessibility_phone_signal_full" msgid="4302338883816077134">"දුරකථනයේ සංඥාව පිරී ඇත."</string>
+    <string name="accessibility_no_data" msgid="4563181886936931008">"දත්ත නැත."</string>
+    <string name="accessibility_data_one_bar" msgid="6892888138070752480">"දත්ත තීරු එකයි."</string>
+    <string name="accessibility_data_two_bars" msgid="9202641507241802499">"දත්ත තීරු 2."</string>
+    <string name="accessibility_data_three_bars" msgid="2813876214466722413">"දත්ත තීරු 3."</string>
+    <string name="accessibility_data_signal_full" msgid="1808301899314382337">"දත්ත සංඥාව පිරී ඇත."</string>
+    <string name="accessibility_ethernet_disconnected" msgid="2832501530856497489">"ඊතර්නෙට් විසන්ධි කරන ලදී."</string>
+    <string name="accessibility_ethernet_connected" msgid="2093872142317190618">"ඊතර්නෙට් සම්බන්ධ කරන ලදී."</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-sk/strings.xml b/packages/SettingsLib/res/values-sk/strings.xml
index b428b42..265ec8f 100644
--- a/packages/SettingsLib/res/values-sk/strings.xml
+++ b/packages/SettingsLib/res/values-sk/strings.xml
@@ -403,7 +403,6 @@
     <string name="transcode_user_control" msgid="6176368544817731314">"Prepísať predvolené nastavenia prekódovania"</string>
     <string name="transcode_enable_all" msgid="2411165920039166710">"Povoliť prekódovanie"</string>
     <string name="transcode_default" msgid="3784803084573509491">"Prepdokladať, že aplikácie podporujú moderné formáty"</string>
-    <string name="transcode_skip_apps" msgid="8249721984597390142">"Zapnúť prekódovanie aplikácií"</string>
     <string name="runningservices_settings_title" msgid="6460099290493086515">"Spustené služby"</string>
     <string name="runningservices_settings_summary" msgid="1046080643262665743">"Zobrazovať a riadiť aktuálne spustené služby"</string>
     <string name="select_webview_provider_title" msgid="3917815648099445503">"Implementácia WebView"</string>
@@ -568,4 +567,29 @@
     <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Slúchadlá s káblom"</string>
     <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Zapnúť"</string>
     <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Vypnúť"</string>
+    <string name="carrier_network_change_mode" msgid="4257621815706644026">"Mení sa sieť operátora"</string>
+    <string name="data_connection_3g" msgid="931852552688157407">"3G"</string>
+    <string name="data_connection_edge" msgid="4625509456544797637">"EDGE"</string>
+    <string name="data_connection_cdma" msgid="9098161966701934334">"1X"</string>
+    <string name="data_connection_gprs" msgid="1251945769006770189">"GPRS"</string>
+    <string name="data_connection_3_5g" msgid="4298721462047921400">"H"</string>
+    <string name="data_connection_3_5g_plus" msgid="6683055858295918170">"H+"</string>
+    <string name="data_connection_4g" msgid="2581705503356752044">"4G"</string>
+    <string name="data_connection_4g_plus" msgid="5194902328408751020">"4G+"</string>
+    <string name="data_connection_lte" msgid="7675461204366364124">"LTE"</string>
+    <string name="data_connection_lte_plus" msgid="6643158654804916653">"LTE+"</string>
+    <string name="cell_data_off_content_description" msgid="2280700839891636498">"Mobilné dáta sú vypnuté"</string>
+    <string name="not_default_data_content_description" msgid="6517068332106592887">"Nie je nastavené na používanie dát"</string>
+    <string name="accessibility_no_phone" msgid="2687419663127582503">"Žiadna telefónna sieť."</string>
+    <string name="accessibility_phone_one_bar" msgid="5719721147018970063">"Jeden stĺpec signálu telefónnej siete."</string>
+    <string name="accessibility_phone_two_bars" msgid="2531458337458953263">"Dve čiarky signálu telefónnej siete."</string>
+    <string name="accessibility_phone_three_bars" msgid="1523967995996696619">"Tri čiarky signálu telefónnej siete."</string>
+    <string name="accessibility_phone_signal_full" msgid="4302338883816077134">"Plný signál telefónnej siete."</string>
+    <string name="accessibility_no_data" msgid="4563181886936931008">"Žiadna dátová sieť."</string>
+    <string name="accessibility_data_one_bar" msgid="6892888138070752480">"Jedna čiarka signálu dátovej siete."</string>
+    <string name="accessibility_data_two_bars" msgid="9202641507241802499">"Dve čiarky signálu dátovej siete."</string>
+    <string name="accessibility_data_three_bars" msgid="2813876214466722413">"Tri čiarky signálu dátovej siete."</string>
+    <string name="accessibility_data_signal_full" msgid="1808301899314382337">"Plný signál dátovej siete."</string>
+    <string name="accessibility_ethernet_disconnected" msgid="2832501530856497489">"Sieť ethernet je odpojená"</string>
+    <string name="accessibility_ethernet_connected" msgid="2093872142317190618">"Sieť ethernet je pripojená"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-sl/strings.xml b/packages/SettingsLib/res/values-sl/strings.xml
index 3ba31fa..2e6fc0e 100644
--- a/packages/SettingsLib/res/values-sl/strings.xml
+++ b/packages/SettingsLib/res/values-sl/strings.xml
@@ -403,7 +403,6 @@
     <string name="transcode_user_control" msgid="6176368544817731314">"Preglasi privzete nastavitve prekodiranja"</string>
     <string name="transcode_enable_all" msgid="2411165920039166710">"Omogoči prekodiranje"</string>
     <string name="transcode_default" msgid="3784803084573509491">"Aplikacije naj bi podpirale sodobne oblike zapisov"</string>
-    <string name="transcode_skip_apps" msgid="8249721984597390142">"Omogočanje prekodiranja za aplikacije"</string>
     <string name="runningservices_settings_title" msgid="6460099290493086515">"Zagnane storitve"</string>
     <string name="runningservices_settings_summary" msgid="1046080643262665743">"Preglejte in nadzorujte storitve, ki so trenutno zagnane"</string>
     <string name="select_webview_provider_title" msgid="3917815648099445503">"Izvedba spletnega pogleda"</string>
@@ -568,4 +567,29 @@
     <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Žične slušalke"</string>
     <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Vklop"</string>
     <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Izklop"</string>
+    <string name="carrier_network_change_mode" msgid="4257621815706644026">"Spreminjanje omrežja operaterja"</string>
+    <string name="data_connection_3g" msgid="931852552688157407">"3G"</string>
+    <string name="data_connection_edge" msgid="4625509456544797637">"EDGE"</string>
+    <string name="data_connection_cdma" msgid="9098161966701934334">"1X"</string>
+    <string name="data_connection_gprs" msgid="1251945769006770189">"GPRS"</string>
+    <string name="data_connection_3_5g" msgid="4298721462047921400">"H"</string>
+    <string name="data_connection_3_5g_plus" msgid="6683055858295918170">"H+"</string>
+    <string name="data_connection_4g" msgid="2581705503356752044">"4G"</string>
+    <string name="data_connection_4g_plus" msgid="5194902328408751020">"4G+"</string>
+    <string name="data_connection_lte" msgid="7675461204366364124">"LTE"</string>
+    <string name="data_connection_lte_plus" msgid="6643158654804916653">"LTE+"</string>
+    <string name="cell_data_off_content_description" msgid="2280700839891636498">"Prenos podatkov v mobilnem omrežju je izklopljen"</string>
+    <string name="not_default_data_content_description" msgid="6517068332106592887">"Ni nastavljeno za uporabo prenosa podatkov"</string>
+    <string name="accessibility_no_phone" msgid="2687419663127582503">"Ni telefona."</string>
+    <string name="accessibility_phone_one_bar" msgid="5719721147018970063">"Telefon z eno črtico."</string>
+    <string name="accessibility_phone_two_bars" msgid="2531458337458953263">"Telefon z dvema črticama."</string>
+    <string name="accessibility_phone_three_bars" msgid="1523967995996696619">"Telefon s tremi črticami."</string>
+    <string name="accessibility_phone_signal_full" msgid="4302338883816077134">"Signal telefona je poln."</string>
+    <string name="accessibility_no_data" msgid="4563181886936931008">"Ni podatkov."</string>
+    <string name="accessibility_data_one_bar" msgid="6892888138070752480">"Podatkovni signal z eno črtico."</string>
+    <string name="accessibility_data_two_bars" msgid="9202641507241802499">"Podatki z dvema črticama."</string>
+    <string name="accessibility_data_three_bars" msgid="2813876214466722413">"Podatki s tremi črticami."</string>
+    <string name="accessibility_data_signal_full" msgid="1808301899314382337">"Podatkovni signal poln."</string>
+    <string name="accessibility_ethernet_disconnected" msgid="2832501530856497489">"Ethernetna povezava je prekinjena."</string>
+    <string name="accessibility_ethernet_connected" msgid="2093872142317190618">"Ethernetna povezava je vzpostavljena."</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-sq/strings.xml b/packages/SettingsLib/res/values-sq/strings.xml
index 15cbb74..5774d9b 100644
--- a/packages/SettingsLib/res/values-sq/strings.xml
+++ b/packages/SettingsLib/res/values-sq/strings.xml
@@ -400,13 +400,9 @@
     <string name="inactive_app_active_summary" msgid="8047630990208722344">"Aktiv. Trokit për ta ndryshuar."</string>
     <string name="standby_bucket_summary" msgid="5128193447550429600">"Gjendja e gatishmërisë e aplikacionit:<xliff:g id="BUCKET"> %s</xliff:g>"</string>
     <string name="transcode_settings_title" msgid="2581975870429850549">"Cilësimet e transkodimit të multimediave"</string>
-    <!-- no translation found for transcode_user_control (6176368544817731314) -->
-    <skip />
-    <!-- no translation found for transcode_enable_all (2411165920039166710) -->
-    <skip />
-    <!-- no translation found for transcode_default (3784803084573509491) -->
-    <skip />
-    <string name="transcode_skip_apps" msgid="8249721984597390142">"Aktivizo transkodimin për aplikacionet"</string>
+    <string name="transcode_user_control" msgid="6176368544817731314">"Anulo parazgjedhjet e transkodimit"</string>
+    <string name="transcode_enable_all" msgid="2411165920039166710">"Aktivizo transkodimin"</string>
+    <string name="transcode_default" msgid="3784803084573509491">"Supozo se aplikacionet i mbështetin formatet moderne"</string>
     <string name="runningservices_settings_title" msgid="6460099290493086515">"Shërbimet në ekzekutim"</string>
     <string name="runningservices_settings_summary" msgid="1046080643262665743">"Shiko dhe kontrollo shërbimet që po ekzekutohen aktualisht"</string>
     <string name="select_webview_provider_title" msgid="3917815648099445503">"Zbatimi i WebView"</string>
@@ -569,4 +565,29 @@
     <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Kufje me tela"</string>
     <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Aktive"</string>
     <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Joaktive"</string>
+    <string name="carrier_network_change_mode" msgid="4257621815706644026">"Rrjeti i operatorit celular po ndryshohet"</string>
+    <string name="data_connection_3g" msgid="931852552688157407">"3G"</string>
+    <string name="data_connection_edge" msgid="4625509456544797637">"EDGE"</string>
+    <string name="data_connection_cdma" msgid="9098161966701934334">"1X"</string>
+    <string name="data_connection_gprs" msgid="1251945769006770189">"GPRS"</string>
+    <string name="data_connection_3_5g" msgid="4298721462047921400">"H"</string>
+    <string name="data_connection_3_5g_plus" msgid="6683055858295918170">"H+"</string>
+    <string name="data_connection_4g" msgid="2581705503356752044">"4G"</string>
+    <string name="data_connection_4g_plus" msgid="5194902328408751020">"4G+"</string>
+    <string name="data_connection_lte" msgid="7675461204366364124">"LTE"</string>
+    <string name="data_connection_lte_plus" msgid="6643158654804916653">"LTE+"</string>
+    <string name="cell_data_off_content_description" msgid="2280700839891636498">"Të dhënat celulare janë joaktive"</string>
+    <string name="not_default_data_content_description" msgid="6517068332106592887">"Nuk është caktuar të përdorë të dhënat"</string>
+    <string name="accessibility_no_phone" msgid="2687419663127582503">"Nuk ka telefon."</string>
+    <string name="accessibility_phone_one_bar" msgid="5719721147018970063">"Telefoni ka edhe një vijë."</string>
+    <string name="accessibility_phone_two_bars" msgid="2531458337458953263">"Telefoni ka dy vija."</string>
+    <string name="accessibility_phone_three_bars" msgid="1523967995996696619">"Telefoni ka tre vija."</string>
+    <string name="accessibility_phone_signal_full" msgid="4302338883816077134">"Sinjali i telefonit është i plotë."</string>
+    <string name="accessibility_no_data" msgid="4563181886936931008">"Nuk ka të dhëna."</string>
+    <string name="accessibility_data_one_bar" msgid="6892888138070752480">"Sinjali është vetëm një vijë."</string>
+    <string name="accessibility_data_two_bars" msgid="9202641507241802499">"Të dhënat kanë dy vija."</string>
+    <string name="accessibility_data_three_bars" msgid="2813876214466722413">"Sinjali është me tre vija."</string>
+    <string name="accessibility_data_signal_full" msgid="1808301899314382337">"Sinjali i të dhënave është i plotë."</string>
+    <string name="accessibility_ethernet_disconnected" msgid="2832501530856497489">"Lidhja e eternetit u shkëput."</string>
+    <string name="accessibility_ethernet_connected" msgid="2093872142317190618">"Lidhja e eternetit u lidh."</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-sr/strings.xml b/packages/SettingsLib/res/values-sr/strings.xml
index c337182..207ca74 100644
--- a/packages/SettingsLib/res/values-sr/strings.xml
+++ b/packages/SettingsLib/res/values-sr/strings.xml
@@ -403,7 +403,6 @@
     <string name="transcode_user_control" msgid="6176368544817731314">"Замени подразумевана подешавања транскодирања"</string>
     <string name="transcode_enable_all" msgid="2411165920039166710">"Омогући транскодирање"</string>
     <string name="transcode_default" msgid="3784803084573509491">"Подразумевај да апликације подржавају модерне формате"</string>
-    <string name="transcode_skip_apps" msgid="8249721984597390142">"Омогућите транскодирање за апликације"</string>
     <string name="runningservices_settings_title" msgid="6460099290493086515">"Покренуте услуге"</string>
     <string name="runningservices_settings_summary" msgid="1046080643262665743">"Приказ и контрола тренутно покренутих услуга"</string>
     <string name="select_webview_provider_title" msgid="3917815648099445503">"Примена WebView-а"</string>
@@ -567,4 +566,29 @@
     <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Жичане слушалице"</string>
     <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Укључено"</string>
     <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Искључено"</string>
+    <string name="carrier_network_change_mode" msgid="4257621815706644026">"Промена мреже мобилног оператера"</string>
+    <string name="data_connection_3g" msgid="931852552688157407">"3G"</string>
+    <string name="data_connection_edge" msgid="4625509456544797637">"EDGE"</string>
+    <string name="data_connection_cdma" msgid="9098161966701934334">"1X"</string>
+    <string name="data_connection_gprs" msgid="1251945769006770189">"GPRS"</string>
+    <string name="data_connection_3_5g" msgid="4298721462047921400">"H"</string>
+    <string name="data_connection_3_5g_plus" msgid="6683055858295918170">"H+"</string>
+    <string name="data_connection_4g" msgid="2581705503356752044">"4G"</string>
+    <string name="data_connection_4g_plus" msgid="5194902328408751020">"4G+"</string>
+    <string name="data_connection_lte" msgid="7675461204366364124">"LTE"</string>
+    <string name="data_connection_lte_plus" msgid="6643158654804916653">"LTE+"</string>
+    <string name="cell_data_off_content_description" msgid="2280700839891636498">"Мобилни подаци су искључени"</string>
+    <string name="not_default_data_content_description" msgid="6517068332106592887">"Није подешено за коришћење података"</string>
+    <string name="accessibility_no_phone" msgid="2687419663127582503">"Нема телефона."</string>
+    <string name="accessibility_phone_one_bar" msgid="5719721147018970063">"Сигнал телефона има једну црту."</string>
+    <string name="accessibility_phone_two_bars" msgid="2531458337458953263">"Сигнал телефона од две црте."</string>
+    <string name="accessibility_phone_three_bars" msgid="1523967995996696619">"Сигнал телефона од три црте."</string>
+    <string name="accessibility_phone_signal_full" msgid="4302338883816077134">"Сигнал телефона је пун."</string>
+    <string name="accessibility_no_data" msgid="4563181886936931008">"Нема података."</string>
+    <string name="accessibility_data_one_bar" msgid="6892888138070752480">"Сигнал за податке има једну црту."</string>
+    <string name="accessibility_data_two_bars" msgid="9202641507241802499">"Сигнал за податке од две црте."</string>
+    <string name="accessibility_data_three_bars" msgid="2813876214466722413">"Сигнал за податке од три црте."</string>
+    <string name="accessibility_data_signal_full" msgid="1808301899314382337">"Сигнал за податке је најјачи."</string>
+    <string name="accessibility_ethernet_disconnected" msgid="2832501530856497489">"Веза са етернетом је прекинута."</string>
+    <string name="accessibility_ethernet_connected" msgid="2093872142317190618">"Етернет је повезан."</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-sv/strings.xml b/packages/SettingsLib/res/values-sv/strings.xml
index 2bf9785..7afd344 100644
--- a/packages/SettingsLib/res/values-sv/strings.xml
+++ b/packages/SettingsLib/res/values-sv/strings.xml
@@ -403,7 +403,6 @@
     <string name="transcode_user_control" msgid="6176368544817731314">"Åsidosätta standardinställningar för omkodning"</string>
     <string name="transcode_enable_all" msgid="2411165920039166710">"Aktivera omkodning"</string>
     <string name="transcode_default" msgid="3784803084573509491">"Anta att appar har stöd för moderna format"</string>
-    <string name="transcode_skip_apps" msgid="8249721984597390142">"Aktivera omkodning för appar"</string>
     <string name="runningservices_settings_title" msgid="6460099290493086515">"Aktiva tjänster"</string>
     <string name="runningservices_settings_summary" msgid="1046080643262665743">"Visa och styr aktiva tjänster"</string>
     <string name="select_webview_provider_title" msgid="3917815648099445503">"WebView-implementering"</string>
@@ -566,4 +565,29 @@
     <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Hörlurar med sladd"</string>
     <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"På"</string>
     <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Av"</string>
+    <string name="carrier_network_change_mode" msgid="4257621815706644026">"Byter leverantörsnätverk"</string>
+    <string name="data_connection_3g" msgid="931852552688157407">"3G"</string>
+    <string name="data_connection_edge" msgid="4625509456544797637">"EDGE"</string>
+    <string name="data_connection_cdma" msgid="9098161966701934334">"1X"</string>
+    <string name="data_connection_gprs" msgid="1251945769006770189">"GPRS"</string>
+    <string name="data_connection_3_5g" msgid="4298721462047921400">"H"</string>
+    <string name="data_connection_3_5g_plus" msgid="6683055858295918170">"H+"</string>
+    <string name="data_connection_4g" msgid="2581705503356752044">"4G"</string>
+    <string name="data_connection_4g_plus" msgid="5194902328408751020">"4G+"</string>
+    <string name="data_connection_lte" msgid="7675461204366364124">"LTE"</string>
+    <string name="data_connection_lte_plus" msgid="6643158654804916653">"LTE+"</string>
+    <string name="cell_data_off_content_description" msgid="2280700839891636498">"Mobildata har inaktiverats"</string>
+    <string name="not_default_data_content_description" msgid="6517068332106592887">"Inte inställd på mobildata"</string>
+    <string name="accessibility_no_phone" msgid="2687419663127582503">"Ingen telefon."</string>
+    <string name="accessibility_phone_one_bar" msgid="5719721147018970063">"Telefon: en stapel."</string>
+    <string name="accessibility_phone_two_bars" msgid="2531458337458953263">"Telefon: två staplar."</string>
+    <string name="accessibility_phone_three_bars" msgid="1523967995996696619">"Telefon: tre staplar."</string>
+    <string name="accessibility_phone_signal_full" msgid="4302338883816077134">"Telefonsignalen är full."</string>
+    <string name="accessibility_no_data" msgid="4563181886936931008">"Inga data."</string>
+    <string name="accessibility_data_one_bar" msgid="6892888138070752480">"Data: en stapel."</string>
+    <string name="accessibility_data_two_bars" msgid="9202641507241802499">"Data: två staplar."</string>
+    <string name="accessibility_data_three_bars" msgid="2813876214466722413">"Data: tre staplar."</string>
+    <string name="accessibility_data_signal_full" msgid="1808301899314382337">"Datasignalen är full."</string>
+    <string name="accessibility_ethernet_disconnected" msgid="2832501530856497489">"Ethernet har kopplats från."</string>
+    <string name="accessibility_ethernet_connected" msgid="2093872142317190618">"Ethernet har anslutits."</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-sw/strings.xml b/packages/SettingsLib/res/values-sw/strings.xml
index 610bfee..084b5c93 100644
--- a/packages/SettingsLib/res/values-sw/strings.xml
+++ b/packages/SettingsLib/res/values-sw/strings.xml
@@ -403,7 +403,6 @@
     <string name="transcode_user_control" msgid="6176368544817731314">"Batilisha chaguomsingi za kubadilisha miundo ya faili"</string>
     <string name="transcode_enable_all" msgid="2411165920039166710">"Ruhusu ubadilishaji wa miundo ya faili"</string>
     <string name="transcode_default" msgid="3784803084573509491">"Chukulia kuwa programu zinatumia miundo ya kisasa"</string>
-    <string name="transcode_skip_apps" msgid="8249721984597390142">"Washa ubadilishaji muundo wa faili kwenye programu"</string>
     <string name="runningservices_settings_title" msgid="6460099290493086515">"Huduma zinazoendeshwa"</string>
     <string name="runningservices_settings_summary" msgid="1046080643262665743">"Onyesha na udhibiti huduma zinazoendeshwa kwa sasa"</string>
     <string name="select_webview_provider_title" msgid="3917815648099445503">"Utekelezaji wa WebView"</string>
@@ -566,4 +565,29 @@
     <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Vipokea sauti vya waya"</string>
     <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Umewashwa"</string>
     <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Umezimwa"</string>
+    <string name="carrier_network_change_mode" msgid="4257621815706644026">"Mabadiliko katika mtandao wa mtoa huduma"</string>
+    <string name="data_connection_3g" msgid="931852552688157407">"3G"</string>
+    <string name="data_connection_edge" msgid="4625509456544797637">"EDGE"</string>
+    <string name="data_connection_cdma" msgid="9098161966701934334">"1X"</string>
+    <string name="data_connection_gprs" msgid="1251945769006770189">"GPRS"</string>
+    <string name="data_connection_3_5g" msgid="4298721462047921400">"H"</string>
+    <string name="data_connection_3_5g_plus" msgid="6683055858295918170">"H+"</string>
+    <string name="data_connection_4g" msgid="2581705503356752044">"4G"</string>
+    <string name="data_connection_4g_plus" msgid="5194902328408751020">"4G+"</string>
+    <string name="data_connection_lte" msgid="7675461204366364124">"LTE"</string>
+    <string name="data_connection_lte_plus" msgid="6643158654804916653">"LTE+"</string>
+    <string name="cell_data_off_content_description" msgid="2280700839891636498">"Umezima data ya mtandao wa simu"</string>
+    <string name="not_default_data_content_description" msgid="6517068332106592887">"Haijawekewa mipangilio ya kutumia data"</string>
+    <string name="accessibility_no_phone" msgid="2687419663127582503">"Hakuna simu"</string>
+    <string name="accessibility_phone_one_bar" msgid="5719721147018970063">"Mwambaa mmoja wa simu."</string>
+    <string name="accessibility_phone_two_bars" msgid="2531458337458953263">"Miambaa miwili ya simu"</string>
+    <string name="accessibility_phone_three_bars" msgid="1523967995996696619">"Miambaa mitatu ya simu."</string>
+    <string name="accessibility_phone_signal_full" msgid="4302338883816077134">"Ishara ya simu imejaa."</string>
+    <string name="accessibility_no_data" msgid="4563181886936931008">"Hakuna data."</string>
+    <string name="accessibility_data_one_bar" msgid="6892888138070752480">"Upapi mmoja wa habari"</string>
+    <string name="accessibility_data_two_bars" msgid="9202641507241802499">"Miamba miwili ya data."</string>
+    <string name="accessibility_data_three_bars" msgid="2813876214466722413">"Fito tatu za habari."</string>
+    <string name="accessibility_data_signal_full" msgid="1808301899314382337">"Ishara ya data imejaa."</string>
+    <string name="accessibility_ethernet_disconnected" msgid="2832501530856497489">"Ethaneti imeondolewa."</string>
+    <string name="accessibility_ethernet_connected" msgid="2093872142317190618">"Ethaneti imeunganishwa."</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-ta/strings.xml b/packages/SettingsLib/res/values-ta/strings.xml
index 7d77967..5fdf8bd 100644
--- a/packages/SettingsLib/res/values-ta/strings.xml
+++ b/packages/SettingsLib/res/values-ta/strings.xml
@@ -403,7 +403,6 @@
     <string name="transcode_user_control" msgid="6176368544817731314">"இயல்புநிலை குறிமாற்றங்களை மீறிச் செயல்படு"</string>
     <string name="transcode_enable_all" msgid="2411165920039166710">"குறிமாற்றத்தை இயக்கு"</string>
     <string name="transcode_default" msgid="3784803084573509491">"ஆப்ஸ் மாடர்ன் வடிவங்களை ஆதரிக்கும்படி அமை"</string>
-    <string name="transcode_skip_apps" msgid="8249721984597390142">"ஆப்ஸுக்குக் குறிமாற்றத்தை இயக்கு"</string>
     <string name="runningservices_settings_title" msgid="6460099290493086515">"இயங்கும் சேவைகள்"</string>
     <string name="runningservices_settings_summary" msgid="1046080643262665743">"தற்போது இயக்கத்தில் இருக்கும் சேவைகளைப் பார்த்து கட்டுப்படுத்து"</string>
     <string name="select_webview_provider_title" msgid="3917815648099445503">"WebView செயல்படுத்தல்"</string>
@@ -566,4 +565,29 @@
     <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"வயருள்ள ஹெட்ஃபோன்"</string>
     <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"ஆன்"</string>
     <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"ஆஃப்"</string>
+    <string name="carrier_network_change_mode" msgid="4257621815706644026">"மொபைல் நிறுவன நெட்வொர்க்கை மாற்றும்"</string>
+    <string name="data_connection_3g" msgid="931852552688157407">"3G"</string>
+    <string name="data_connection_edge" msgid="4625509456544797637">"EDGE"</string>
+    <string name="data_connection_cdma" msgid="9098161966701934334">"1X"</string>
+    <string name="data_connection_gprs" msgid="1251945769006770189">"GPRS"</string>
+    <string name="data_connection_3_5g" msgid="4298721462047921400">"H"</string>
+    <string name="data_connection_3_5g_plus" msgid="6683055858295918170">"H+"</string>
+    <string name="data_connection_4g" msgid="2581705503356752044">"4G"</string>
+    <string name="data_connection_4g_plus" msgid="5194902328408751020">"4G+"</string>
+    <string name="data_connection_lte" msgid="7675461204366364124">"LTE"</string>
+    <string name="data_connection_lte_plus" msgid="6643158654804916653">"LTE+"</string>
+    <string name="cell_data_off_content_description" msgid="2280700839891636498">"மொபைல் டேட்டா ஆஃப் செய்யப்பட்டது"</string>
+    <string name="not_default_data_content_description" msgid="6517068332106592887">"தரவை உபயோகிக்க அமைக்கப்படவில்லை"</string>
+    <string name="accessibility_no_phone" msgid="2687419663127582503">"சிக்னல் இல்லை."</string>
+    <string name="accessibility_phone_one_bar" msgid="5719721147018970063">"சிக்னல் ஒரு கோட்டில் உள்ளது."</string>
+    <string name="accessibility_phone_two_bars" msgid="2531458337458953263">"சிக்னல் இரண்டு கோட்டில் உள்ளது."</string>
+    <string name="accessibility_phone_three_bars" msgid="1523967995996696619">"சிக்னல் மூன்று கோட்டில் உள்ளது."</string>
+    <string name="accessibility_phone_signal_full" msgid="4302338883816077134">"சிக்னல் முழுமையாக உள்ளது."</string>
+    <string name="accessibility_no_data" msgid="4563181886936931008">"டேட்டா சிக்னல் இல்லை."</string>
+    <string name="accessibility_data_one_bar" msgid="6892888138070752480">"தரவு சிக்னல் ஒரு கோட்டில் உள்ளது."</string>
+    <string name="accessibility_data_two_bars" msgid="9202641507241802499">"தரவின் சிக்னல் இரண்டு கோடு வரை உள்ளது."</string>
+    <string name="accessibility_data_three_bars" msgid="2813876214466722413">"தரவு சிக்னல் மூன்று கோட்டில் உள்ளது."</string>
+    <string name="accessibility_data_signal_full" msgid="1808301899314382337">"தரவு சிக்னல் முழுமையாக உள்ளது."</string>
+    <string name="accessibility_ethernet_disconnected" msgid="2832501530856497489">"ஈத்தர்நெட் துண்டிக்கப்பட்டது."</string>
+    <string name="accessibility_ethernet_connected" msgid="2093872142317190618">"ஈத்தர்நெட் இணைக்கப்பட்டது."</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-te/strings.xml b/packages/SettingsLib/res/values-te/strings.xml
index f24caec..38f08b2 100644
--- a/packages/SettingsLib/res/values-te/strings.xml
+++ b/packages/SettingsLib/res/values-te/strings.xml
@@ -400,13 +400,9 @@
     <string name="inactive_app_active_summary" msgid="8047630990208722344">"సక్రియంగా ఉంది. టోగుల్ చేయడానికి నొక్కండి."</string>
     <string name="standby_bucket_summary" msgid="5128193447550429600">"యాప్ స్టాండ్‌బై స్థితి:<xliff:g id="BUCKET"> %s</xliff:g>"</string>
     <string name="transcode_settings_title" msgid="2581975870429850549">"మీడియా ట్రాన్స్‌కోడింగ్ సెట్టింగ్‌లు"</string>
-    <!-- no translation found for transcode_user_control (6176368544817731314) -->
-    <skip />
-    <!-- no translation found for transcode_enable_all (2411165920039166710) -->
-    <skip />
-    <!-- no translation found for transcode_default (3784803084573509491) -->
-    <skip />
-    <string name="transcode_skip_apps" msgid="8249721984597390142">"యాప్‌ల కోసం ట్రాన్స్‌కోడింగ్‌ను ఎనేబుల్ చేయండి"</string>
+    <string name="transcode_user_control" msgid="6176368544817731314">"ట్రాన్స్‌కోడింగ్ ఆటోమేటిక్ సెట్టింగ్‌లను ఓవర్‌రైడ్ చేయండి"</string>
+    <string name="transcode_enable_all" msgid="2411165920039166710">"ట్రాన్స్‌కోడింగ్‌ను ఎనేబుల్ చేయండి"</string>
+    <string name="transcode_default" msgid="3784803084573509491">"యాప్‌లు ఆధునిక ఫార్మాట్‌లకు సపోర్ట్ చేస్తాయని అనుకోండి"</string>
     <string name="runningservices_settings_title" msgid="6460099290493086515">"అమలులో ఉన్న సేవలు"</string>
     <string name="runningservices_settings_summary" msgid="1046080643262665743">"ప్రస్తుతం అమలులో ఉన్న సేవలను వీక్షించండి మరియు నియంత్రించండి"</string>
     <string name="select_webview_provider_title" msgid="3917815648099445503">"వెబ్ వీక్షణ అమలు"</string>
@@ -569,4 +565,29 @@
     <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"వైర్ ఉన్న హెడ్‌ఫోన్"</string>
     <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"ఆన్‌లో ఉంది"</string>
     <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"ఆఫ్‌లో ఉంది"</string>
+    <string name="carrier_network_change_mode" msgid="4257621815706644026">"క్యారియర్ నెట్‌వర్క్ మారుతోంది"</string>
+    <string name="data_connection_3g" msgid="931852552688157407">"3G"</string>
+    <string name="data_connection_edge" msgid="4625509456544797637">"EDGE"</string>
+    <string name="data_connection_cdma" msgid="9098161966701934334">"1X"</string>
+    <string name="data_connection_gprs" msgid="1251945769006770189">"GPRS"</string>
+    <string name="data_connection_3_5g" msgid="4298721462047921400">"H"</string>
+    <string name="data_connection_3_5g_plus" msgid="6683055858295918170">"H+"</string>
+    <string name="data_connection_4g" msgid="2581705503356752044">"4G"</string>
+    <string name="data_connection_4g_plus" msgid="5194902328408751020">"4G+"</string>
+    <string name="data_connection_lte" msgid="7675461204366364124">"LTE"</string>
+    <string name="data_connection_lte_plus" msgid="6643158654804916653">"LTE+"</string>
+    <string name="cell_data_off_content_description" msgid="2280700839891636498">"మొబైల్ డేటా ఆఫ్‌లో ఉంది"</string>
+    <string name="not_default_data_content_description" msgid="6517068332106592887">"డేటాను ఉపయోగించే విధంగా సెట్ చేయలేదు"</string>
+    <string name="accessibility_no_phone" msgid="2687419663127582503">"ఫోన్ లేదు."</string>
+    <string name="accessibility_phone_one_bar" msgid="5719721147018970063">"ఫోన్ ఒక బారు."</string>
+    <string name="accessibility_phone_two_bars" msgid="2531458337458953263">"ఫోన్ రెండు బార్లు."</string>
+    <string name="accessibility_phone_three_bars" msgid="1523967995996696619">"ఫోన్ మూడు బార్లు."</string>
+    <string name="accessibility_phone_signal_full" msgid="4302338883816077134">"ఫోన్ సిగ్నల్ పూర్తిగా ఉంది."</string>
+    <string name="accessibility_no_data" msgid="4563181886936931008">"డేటా లేదు."</string>
+    <string name="accessibility_data_one_bar" msgid="6892888138070752480">"డేటా ఒక బారు."</string>
+    <string name="accessibility_data_two_bars" msgid="9202641507241802499">"డేటా రెండు బార్‌లు."</string>
+    <string name="accessibility_data_three_bars" msgid="2813876214466722413">"డేటా మూడు బార్లు."</string>
+    <string name="accessibility_data_signal_full" msgid="1808301899314382337">"డేటా సిగ్నల్ సంపూర్ణంగా ఉంది."</string>
+    <string name="accessibility_ethernet_disconnected" msgid="2832501530856497489">"ఈథర్‌నెట్ డిస్‌కనెక్ట్ చేయబడింది."</string>
+    <string name="accessibility_ethernet_connected" msgid="2093872142317190618">"ఈథర్‌నెట్ కనెక్ట్ చేయబడింది."</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-th/strings.xml b/packages/SettingsLib/res/values-th/strings.xml
index 2c01998..dabb9d3 100644
--- a/packages/SettingsLib/res/values-th/strings.xml
+++ b/packages/SettingsLib/res/values-th/strings.xml
@@ -403,7 +403,6 @@
     <string name="transcode_user_control" msgid="6176368544817731314">"ลบล้างค่าเริ่มต้นของการแปลง"</string>
     <string name="transcode_enable_all" msgid="2411165920039166710">"เปิดใช้การแปลง"</string>
     <string name="transcode_default" msgid="3784803084573509491">"ถือว่าแอปรองรับรูปแบบสมัยใหม่"</string>
-    <string name="transcode_skip_apps" msgid="8249721984597390142">"เปิดใช้การแปลงสำหรับแอป"</string>
     <string name="runningservices_settings_title" msgid="6460099290493086515">"บริการที่ทำงานอยู่"</string>
     <string name="runningservices_settings_summary" msgid="1046080643262665743">"ดูและควบคุมบริการที่ทำงานอยู่"</string>
     <string name="select_webview_provider_title" msgid="3917815648099445503">"การใช้งาน WebView"</string>
@@ -566,4 +565,29 @@
     <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"หูฟังแบบมีสาย"</string>
     <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"เปิด"</string>
     <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"ปิด"</string>
+    <string name="carrier_network_change_mode" msgid="4257621815706644026">"การเปลี่ยนเครือข่ายผู้ให้บริการ"</string>
+    <string name="data_connection_3g" msgid="931852552688157407">"3G"</string>
+    <string name="data_connection_edge" msgid="4625509456544797637">"EDGE"</string>
+    <string name="data_connection_cdma" msgid="9098161966701934334">"1X"</string>
+    <string name="data_connection_gprs" msgid="1251945769006770189">"GPRS"</string>
+    <string name="data_connection_3_5g" msgid="4298721462047921400">"H"</string>
+    <string name="data_connection_3_5g_plus" msgid="6683055858295918170">"H+"</string>
+    <string name="data_connection_4g" msgid="2581705503356752044">"4G"</string>
+    <string name="data_connection_4g_plus" msgid="5194902328408751020">"4G+"</string>
+    <string name="data_connection_lte" msgid="7675461204366364124">"LTE"</string>
+    <string name="data_connection_lte_plus" msgid="6643158654804916653">"LTE+"</string>
+    <string name="cell_data_off_content_description" msgid="2280700839891636498">"เน็ตมือถือปิดอยู่"</string>
+    <string name="not_default_data_content_description" msgid="6517068332106592887">"ไม่ได้ตั้งค่าให้ใช้อินเทอร์เน็ตมือถือ"</string>
+    <string name="accessibility_no_phone" msgid="2687419663127582503">"ไม่มีสัญญาณโทรศัพท์"</string>
+    <string name="accessibility_phone_one_bar" msgid="5719721147018970063">"สัญญาณโทรศัพท์หนึ่งขีด"</string>
+    <string name="accessibility_phone_two_bars" msgid="2531458337458953263">"สัญญาณโทรศัพท์สองขีด"</string>
+    <string name="accessibility_phone_three_bars" msgid="1523967995996696619">"สัญญาณโทรศัพท์สามขีด"</string>
+    <string name="accessibility_phone_signal_full" msgid="4302338883816077134">"สัญญาณโทรศัพท์เต็ม"</string>
+    <string name="accessibility_no_data" msgid="4563181886936931008">"ไม่มีข้อมูล"</string>
+    <string name="accessibility_data_one_bar" msgid="6892888138070752480">"สัญญาณข้อมูลหนึ่งขีด"</string>
+    <string name="accessibility_data_two_bars" msgid="9202641507241802499">"สัญญาณข้อมูลสองขีด"</string>
+    <string name="accessibility_data_three_bars" msgid="2813876214466722413">"สัญญาณข้อมูลสามขีด"</string>
+    <string name="accessibility_data_signal_full" msgid="1808301899314382337">"สัญญาณข้อมูลเต็ม"</string>
+    <string name="accessibility_ethernet_disconnected" msgid="2832501530856497489">"ยกเลิกการเชื่อมต่ออีเทอร์เน็ตแล้ว"</string>
+    <string name="accessibility_ethernet_connected" msgid="2093872142317190618">"เชื่อมต่ออีเทอร์เน็ตแล้ว"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-tl/strings.xml b/packages/SettingsLib/res/values-tl/strings.xml
index 54ba90e..b451d89 100644
--- a/packages/SettingsLib/res/values-tl/strings.xml
+++ b/packages/SettingsLib/res/values-tl/strings.xml
@@ -403,7 +403,6 @@
     <string name="transcode_user_control" msgid="6176368544817731314">"I-override ang mga default ng pagta-transcode"</string>
     <string name="transcode_enable_all" msgid="2411165920039166710">"I-enable ang pagta-transcode"</string>
     <string name="transcode_default" msgid="3784803084573509491">"Ipagpalagay na sinusuportahan ng mga app ang mga modernong format"</string>
-    <string name="transcode_skip_apps" msgid="8249721984597390142">"I-enable ang pag-transcode para sa mga app"</string>
     <string name="runningservices_settings_title" msgid="6460099290493086515">"Mga tumatakbong serbisyo"</string>
     <string name="runningservices_settings_summary" msgid="1046080643262665743">"Tingnan at kontrolin ang mga kasalukuyang tumatakbong serbisyo"</string>
     <string name="select_webview_provider_title" msgid="3917815648099445503">"Pagpapatupad sa WebView"</string>
@@ -566,4 +565,29 @@
     <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Wired na headphone"</string>
     <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Naka-on"</string>
     <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Naka-off"</string>
+    <string name="carrier_network_change_mode" msgid="4257621815706644026">"Nagpapalit ng carrier network"</string>
+    <string name="data_connection_3g" msgid="931852552688157407">"3G"</string>
+    <string name="data_connection_edge" msgid="4625509456544797637">"EDGE"</string>
+    <string name="data_connection_cdma" msgid="9098161966701934334">"1X"</string>
+    <string name="data_connection_gprs" msgid="1251945769006770189">"GPRS"</string>
+    <string name="data_connection_3_5g" msgid="4298721462047921400">"H"</string>
+    <string name="data_connection_3_5g_plus" msgid="6683055858295918170">"H+"</string>
+    <string name="data_connection_4g" msgid="2581705503356752044">"4G"</string>
+    <string name="data_connection_4g_plus" msgid="5194902328408751020">"4G+"</string>
+    <string name="data_connection_lte" msgid="7675461204366364124">"LTE"</string>
+    <string name="data_connection_lte_plus" msgid="6643158654804916653">"LTE+"</string>
+    <string name="cell_data_off_content_description" msgid="2280700839891636498">"Naka-off ang mobile data"</string>
+    <string name="not_default_data_content_description" msgid="6517068332106592887">"Hindi nakatakdang gumamit ng data"</string>
+    <string name="accessibility_no_phone" msgid="2687419663127582503">"Walang telepono."</string>
+    <string name="accessibility_phone_one_bar" msgid="5719721147018970063">"Telepono na isang bar."</string>
+    <string name="accessibility_phone_two_bars" msgid="2531458337458953263">"Telepono na dalawang bar."</string>
+    <string name="accessibility_phone_three_bars" msgid="1523967995996696619">"Telepono na tatlong bar."</string>
+    <string name="accessibility_phone_signal_full" msgid="4302338883816077134">"Puno ang signal ng telepono."</string>
+    <string name="accessibility_no_data" msgid="4563181886936931008">"Walang data."</string>
+    <string name="accessibility_data_one_bar" msgid="6892888138070752480">"Data na isang bar."</string>
+    <string name="accessibility_data_two_bars" msgid="9202641507241802499">"Data na dalawang bar."</string>
+    <string name="accessibility_data_three_bars" msgid="2813876214466722413">"Data na tatlong bar."</string>
+    <string name="accessibility_data_signal_full" msgid="1808301899314382337">"Puno ang signal ng data."</string>
+    <string name="accessibility_ethernet_disconnected" msgid="2832501530856497489">"Nadiskonekta ang Ethernet."</string>
+    <string name="accessibility_ethernet_connected" msgid="2093872142317190618">"Nakakonekta ang Ethernet."</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-tr/strings.xml b/packages/SettingsLib/res/values-tr/strings.xml
index 942834f..e1ff56b 100644
--- a/packages/SettingsLib/res/values-tr/strings.xml
+++ b/packages/SettingsLib/res/values-tr/strings.xml
@@ -403,7 +403,6 @@
     <string name="transcode_user_control" msgid="6176368544817731314">"Kod dönüştürme varsayılanlarını geçersiz kıl"</string>
     <string name="transcode_enable_all" msgid="2411165920039166710">"Kod dönüştürmeyi etkinleştir"</string>
     <string name="transcode_default" msgid="3784803084573509491">"Uygulamaların modern biçimleri desteklediğini varsay"</string>
-    <string name="transcode_skip_apps" msgid="8249721984597390142">"Uygulamalar için kod dönüştürmeyi etkinleştir"</string>
     <string name="runningservices_settings_title" msgid="6460099290493086515">"Çalışan hizmetler"</string>
     <string name="runningservices_settings_summary" msgid="1046080643262665743">"Şu anda çalışan hizmetleri görüntüle ve denetle"</string>
     <string name="select_webview_provider_title" msgid="3917815648099445503">"Web Görünümü kullanımı"</string>
@@ -566,4 +565,29 @@
     <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Kablolu kulaklık"</string>
     <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Açık"</string>
     <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Kapalı"</string>
+    <string name="carrier_network_change_mode" msgid="4257621815706644026">"Operatör ağı değiştiriliyor"</string>
+    <string name="data_connection_3g" msgid="931852552688157407">"3G"</string>
+    <string name="data_connection_edge" msgid="4625509456544797637">"EDGE"</string>
+    <string name="data_connection_cdma" msgid="9098161966701934334">"1X"</string>
+    <string name="data_connection_gprs" msgid="1251945769006770189">"GPRS"</string>
+    <string name="data_connection_3_5g" msgid="4298721462047921400">"H"</string>
+    <string name="data_connection_3_5g_plus" msgid="6683055858295918170">"H+"</string>
+    <string name="data_connection_4g" msgid="2581705503356752044">"4G"</string>
+    <string name="data_connection_4g_plus" msgid="5194902328408751020">"4G+"</string>
+    <string name="data_connection_lte" msgid="7675461204366364124">"LTE"</string>
+    <string name="data_connection_lte_plus" msgid="6643158654804916653">"LTE+"</string>
+    <string name="cell_data_off_content_description" msgid="2280700839891636498">"Mobil veri kapalı"</string>
+    <string name="not_default_data_content_description" msgid="6517068332106592887">"Veri kullanmak üzere ayarlanmadı"</string>
+    <string name="accessibility_no_phone" msgid="2687419663127582503">"Telefon sinyali yok."</string>
+    <string name="accessibility_phone_one_bar" msgid="5719721147018970063">"Telefon sinyali bir çubuk."</string>
+    <string name="accessibility_phone_two_bars" msgid="2531458337458953263">"Telefon sinyali iki çubuk."</string>
+    <string name="accessibility_phone_three_bars" msgid="1523967995996696619">"Telefon sinyali üç çubuk."</string>
+    <string name="accessibility_phone_signal_full" msgid="4302338883816077134">"Telefon sinyali tam."</string>
+    <string name="accessibility_no_data" msgid="4563181886936931008">"Veri yok."</string>
+    <string name="accessibility_data_one_bar" msgid="6892888138070752480">"Veri sinyali bir çubuk."</string>
+    <string name="accessibility_data_two_bars" msgid="9202641507241802499">"Veri sinyali iki çubuk."</string>
+    <string name="accessibility_data_three_bars" msgid="2813876214466722413">"Veri sinyali üç çubuk."</string>
+    <string name="accessibility_data_signal_full" msgid="1808301899314382337">"Veri sinyali tam."</string>
+    <string name="accessibility_ethernet_disconnected" msgid="2832501530856497489">"Ethernet bağlantısı kesildi."</string>
+    <string name="accessibility_ethernet_connected" msgid="2093872142317190618">"Ethernet bağlandı."</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-uk/strings.xml b/packages/SettingsLib/res/values-uk/strings.xml
index f6063f8..6806ce6 100644
--- a/packages/SettingsLib/res/values-uk/strings.xml
+++ b/packages/SettingsLib/res/values-uk/strings.xml
@@ -403,7 +403,6 @@
     <string name="transcode_user_control" msgid="6176368544817731314">"Замінити стандартні налаштування перекодування"</string>
     <string name="transcode_enable_all" msgid="2411165920039166710">"Увімкнути перекодування"</string>
     <string name="transcode_default" msgid="3784803084573509491">"Вважати, що додатки підтримують сучасні формати"</string>
-    <string name="transcode_skip_apps" msgid="8249721984597390142">"Увімкнути перекодування додатків"</string>
     <string name="runningservices_settings_title" msgid="6460099290493086515">"Запущені сервіси"</string>
     <string name="runningservices_settings_summary" msgid="1046080643262665743">"Переглянути й налаштувати запущені сервіси"</string>
     <string name="select_webview_provider_title" msgid="3917815648099445503">"Застосування WebView"</string>
@@ -568,4 +567,29 @@
     <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Дротові навушники"</string>
     <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Увімкнено"</string>
     <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Вимкнено"</string>
+    <string name="carrier_network_change_mode" msgid="4257621815706644026">"Змінення мережі оператора"</string>
+    <string name="data_connection_3g" msgid="931852552688157407">"3G"</string>
+    <string name="data_connection_edge" msgid="4625509456544797637">"EDGE"</string>
+    <string name="data_connection_cdma" msgid="9098161966701934334">"1X"</string>
+    <string name="data_connection_gprs" msgid="1251945769006770189">"GPRS"</string>
+    <string name="data_connection_3_5g" msgid="4298721462047921400">"H"</string>
+    <string name="data_connection_3_5g_plus" msgid="6683055858295918170">"H+"</string>
+    <string name="data_connection_4g" msgid="2581705503356752044">"4G"</string>
+    <string name="data_connection_4g_plus" msgid="5194902328408751020">"4G+"</string>
+    <string name="data_connection_lte" msgid="7675461204366364124">"LTE"</string>
+    <string name="data_connection_lte_plus" msgid="6643158654804916653">"LTE+"</string>
+    <string name="cell_data_off_content_description" msgid="2280700839891636498">"Мобільне передавання даних вимкнено"</string>
+    <string name="not_default_data_content_description" msgid="6517068332106592887">"Не вибрано для використання даних"</string>
+    <string name="accessibility_no_phone" msgid="2687419663127582503">"Немає сигналу телефону."</string>
+    <string name="accessibility_phone_one_bar" msgid="5719721147018970063">"Одна смужка сигналу телефону."</string>
+    <string name="accessibility_phone_two_bars" msgid="2531458337458953263">"Дві смужки сигналу телефону."</string>
+    <string name="accessibility_phone_three_bars" msgid="1523967995996696619">"Три смужки сигналу телефону."</string>
+    <string name="accessibility_phone_signal_full" msgid="4302338883816077134">"Максимальний сигнал телефону."</string>
+    <string name="accessibility_no_data" msgid="4563181886936931008">"Немає сигналу даних."</string>
+    <string name="accessibility_data_one_bar" msgid="6892888138070752480">"Одна смужка сигналу даних."</string>
+    <string name="accessibility_data_two_bars" msgid="9202641507241802499">"Дві смужки сигналу даних."</string>
+    <string name="accessibility_data_three_bars" msgid="2813876214466722413">"Три смужки сигналу даних."</string>
+    <string name="accessibility_data_signal_full" msgid="1808301899314382337">"Максимальний сигнал даних."</string>
+    <string name="accessibility_ethernet_disconnected" msgid="2832501530856497489">"Ethernet відключено."</string>
+    <string name="accessibility_ethernet_connected" msgid="2093872142317190618">"Ethernet підключено."</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-ur/strings.xml b/packages/SettingsLib/res/values-ur/strings.xml
index 5d75437..4363f0b 100644
--- a/packages/SettingsLib/res/values-ur/strings.xml
+++ b/packages/SettingsLib/res/values-ur/strings.xml
@@ -400,13 +400,9 @@
     <string name="inactive_app_active_summary" msgid="8047630990208722344">"فعال۔ ٹوگل کرنے کیلئے تھپتھپائیں۔"</string>
     <string name="standby_bucket_summary" msgid="5128193447550429600">"ایپ اسٹینڈ بائی کی حالت:<xliff:g id="BUCKET"> %s</xliff:g>"</string>
     <string name="transcode_settings_title" msgid="2581975870429850549">"میڈیا ٹرانسکوڈنگ کی ترتیبات"</string>
-    <!-- no translation found for transcode_user_control (6176368544817731314) -->
-    <skip />
-    <!-- no translation found for transcode_enable_all (2411165920039166710) -->
-    <skip />
-    <!-- no translation found for transcode_default (3784803084573509491) -->
-    <skip />
-    <string name="transcode_skip_apps" msgid="8249721984597390142">"ایپس کے لئے ٹرانسکوڈنگ فعال کریں"</string>
+    <string name="transcode_user_control" msgid="6176368544817731314">"ٹرانسکوڈنگ ڈیفالٹس کو اوور رائیڈ کریں"</string>
+    <string name="transcode_enable_all" msgid="2411165920039166710">"ٹرانسکوڈنگ فعال کریں"</string>
+    <string name="transcode_default" msgid="3784803084573509491">"فرض کریں کہ ایپس جدید فارمیٹس کو سپورٹ کرتی ہیں"</string>
     <string name="runningservices_settings_title" msgid="6460099290493086515">"چل رہی سروسز"</string>
     <string name="runningservices_settings_summary" msgid="1046080643262665743">"فی الحال چل رہی سروسز دیکھیں اور انہیں کنٹرول کریں"</string>
     <string name="select_webview_provider_title" msgid="3917815648099445503">"‏WebView کا نفاذ"</string>
@@ -569,4 +565,29 @@
     <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"وائرڈ ہیڈ فون"</string>
     <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"آن"</string>
     <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"آف"</string>
+    <string name="carrier_network_change_mode" msgid="4257621815706644026">"کیریئر نیٹ ورک کی تبدیلی"</string>
+    <string name="data_connection_3g" msgid="931852552688157407">"3G"</string>
+    <string name="data_connection_edge" msgid="4625509456544797637">"EDGE"</string>
+    <string name="data_connection_cdma" msgid="9098161966701934334">"1X‎"</string>
+    <string name="data_connection_gprs" msgid="1251945769006770189">"GPRS"</string>
+    <string name="data_connection_3_5g" msgid="4298721462047921400">"H"</string>
+    <string name="data_connection_3_5g_plus" msgid="6683055858295918170">"H+‎"</string>
+    <string name="data_connection_4g" msgid="2581705503356752044">"4G"</string>
+    <string name="data_connection_4g_plus" msgid="5194902328408751020">"4G+‎"</string>
+    <string name="data_connection_lte" msgid="7675461204366364124">"LTE"</string>
+    <string name="data_connection_lte_plus" msgid="6643158654804916653">"LTE+‎"</string>
+    <string name="cell_data_off_content_description" msgid="2280700839891636498">"موبائل ڈیٹا آف ہے"</string>
+    <string name="not_default_data_content_description" msgid="6517068332106592887">"ڈیٹا استعمال کرنے کے لیے سیٹ نہیں ہے"</string>
+    <string name="accessibility_no_phone" msgid="2687419663127582503">"کوئی فون نہیں ہے۔"</string>
+    <string name="accessibility_phone_one_bar" msgid="5719721147018970063">"فون کا ایک بار۔"</string>
+    <string name="accessibility_phone_two_bars" msgid="2531458337458953263">"فون کے دو بارز۔"</string>
+    <string name="accessibility_phone_three_bars" msgid="1523967995996696619">"فون کے تین بارز۔"</string>
+    <string name="accessibility_phone_signal_full" msgid="4302338883816077134">"فون سگنل پورا ہے۔"</string>
+    <string name="accessibility_no_data" msgid="4563181886936931008">"کوئی ڈیٹا نہیں ہے۔"</string>
+    <string name="accessibility_data_one_bar" msgid="6892888138070752480">"ڈیٹا کا ایک بار۔"</string>
+    <string name="accessibility_data_two_bars" msgid="9202641507241802499">"ڈیٹا کے دو بارز۔"</string>
+    <string name="accessibility_data_three_bars" msgid="2813876214466722413">"ڈیٹا کے تین بارز۔"</string>
+    <string name="accessibility_data_signal_full" msgid="1808301899314382337">"ڈیٹا سگنل بھرا ہوا ہے۔"</string>
+    <string name="accessibility_ethernet_disconnected" msgid="2832501530856497489">"ایتھرنیٹ منقطع ہے۔"</string>
+    <string name="accessibility_ethernet_connected" msgid="2093872142317190618">"ایتھرنیٹ منسلک ہے۔"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-uz/strings.xml b/packages/SettingsLib/res/values-uz/strings.xml
index f1fc8dd..1eecf88 100644
--- a/packages/SettingsLib/res/values-uz/strings.xml
+++ b/packages/SettingsLib/res/values-uz/strings.xml
@@ -402,8 +402,7 @@
     <string name="transcode_settings_title" msgid="2581975870429850549">"Media transkripsiyasi sozlamalari"</string>
     <string name="transcode_user_control" msgid="6176368544817731314">"Transkripsiya parametrlarini almashtirish"</string>
     <string name="transcode_enable_all" msgid="2411165920039166710">"Transkripsiyasini yoqish"</string>
-    <string name="transcode_default" msgid="3784803084573509491">"Ilovalar zamonaviy kodlash formatlarini qoʻllab-quvvatlaydi deb hisoblash"</string>
-    <string name="transcode_skip_apps" msgid="8249721984597390142">"Ilovalar uchun transkripsiyani yoqish"</string>
+    <string name="transcode_default" msgid="3784803084573509491">"Ilovalarda zamonaviy kodlash formatlari ishlaydi deb hisoblash"</string>
     <string name="runningservices_settings_title" msgid="6460099290493086515">"Ishlab turgan ilovalar"</string>
     <string name="runningservices_settings_summary" msgid="1046080643262665743">"Ishlab turgan ilovalarni ko‘rish va boshqarish"</string>
     <string name="select_webview_provider_title" msgid="3917815648099445503">"WebView ta’minotchisi"</string>
@@ -566,4 +565,29 @@
     <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Simli quloqlik"</string>
     <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Yoniq"</string>
     <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Oʻchiq"</string>
+    <string name="carrier_network_change_mode" msgid="4257621815706644026">"Mobil tarmoqni o‘zgartirish"</string>
+    <string name="data_connection_3g" msgid="931852552688157407">"3G"</string>
+    <string name="data_connection_edge" msgid="4625509456544797637">"EDGE"</string>
+    <string name="data_connection_cdma" msgid="9098161966701934334">"1X"</string>
+    <string name="data_connection_gprs" msgid="1251945769006770189">"GPRS"</string>
+    <string name="data_connection_3_5g" msgid="4298721462047921400">"H"</string>
+    <string name="data_connection_3_5g_plus" msgid="6683055858295918170">"H+"</string>
+    <string name="data_connection_4g" msgid="2581705503356752044">"4G"</string>
+    <string name="data_connection_4g_plus" msgid="5194902328408751020">"4G+"</string>
+    <string name="data_connection_lte" msgid="7675461204366364124">"LTE"</string>
+    <string name="data_connection_lte_plus" msgid="6643158654804916653">"LTE+"</string>
+    <string name="cell_data_off_content_description" msgid="2280700839891636498">"Mobil internet yoqilmagan"</string>
+    <string name="not_default_data_content_description" msgid="6517068332106592887">"Maʼlumotlardan foydalanish uchun sozlanmagan"</string>
+    <string name="accessibility_no_phone" msgid="2687419663127582503">"Signal yo‘q."</string>
+    <string name="accessibility_phone_one_bar" msgid="5719721147018970063">"Telefon bitta panelda."</string>
+    <string name="accessibility_phone_two_bars" msgid="2531458337458953263">"Telefon ikkita panelda."</string>
+    <string name="accessibility_phone_three_bars" msgid="1523967995996696619">"Telefon uchta panelda."</string>
+    <string name="accessibility_phone_signal_full" msgid="4302338883816077134">"Telefon signali to‘liq."</string>
+    <string name="accessibility_no_data" msgid="4563181886936931008">"Ma’lumotlar yo‘q."</string>
+    <string name="accessibility_data_one_bar" msgid="6892888138070752480">"Ma’lumotlar bitta panelda."</string>
+    <string name="accessibility_data_two_bars" msgid="9202641507241802499">"Ma’lumotlar ikkita panelda."</string>
+    <string name="accessibility_data_three_bars" msgid="2813876214466722413">"Ma’lumotlar uchta panelda."</string>
+    <string name="accessibility_data_signal_full" msgid="1808301899314382337">"Internet signali butun."</string>
+    <string name="accessibility_ethernet_disconnected" msgid="2832501530856497489">"Qurilma Ethernet tarmog‘idan uzildi."</string>
+    <string name="accessibility_ethernet_connected" msgid="2093872142317190618">"Qurilma Ethernet tarmog‘iga ulandi."</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-vi/strings.xml b/packages/SettingsLib/res/values-vi/strings.xml
index 910fa26..643fdb9 100644
--- a/packages/SettingsLib/res/values-vi/strings.xml
+++ b/packages/SettingsLib/res/values-vi/strings.xml
@@ -403,7 +403,6 @@
     <string name="transcode_user_control" msgid="6176368544817731314">"Ghi đè tùy chọn chuyển mã mặc định"</string>
     <string name="transcode_enable_all" msgid="2411165920039166710">"Bật tính năng chuyển mã"</string>
     <string name="transcode_default" msgid="3784803084573509491">"Giả định rằng các ứng dụng hỗ trợ định dạng hiện đại"</string>
-    <string name="transcode_skip_apps" msgid="8249721984597390142">"Bật tùy chọn chuyển mã cho ứng dụng"</string>
     <string name="runningservices_settings_title" msgid="6460099290493086515">"Các dịch vụ đang chạy"</string>
     <string name="runningservices_settings_summary" msgid="1046080643262665743">"Xem và kiểm soát các dịch vụ đang chạy"</string>
     <string name="select_webview_provider_title" msgid="3917815648099445503">"Triển khai WebView"</string>
@@ -566,4 +565,29 @@
     <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Tai nghe có dây"</string>
     <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Đang bật"</string>
     <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Đang tắt"</string>
+    <string name="carrier_network_change_mode" msgid="4257621815706644026">"Thay đổi mạng của nhà mạng"</string>
+    <string name="data_connection_3g" msgid="931852552688157407">"3G"</string>
+    <string name="data_connection_edge" msgid="4625509456544797637">"EDGE"</string>
+    <string name="data_connection_cdma" msgid="9098161966701934334">"1X"</string>
+    <string name="data_connection_gprs" msgid="1251945769006770189">"GPRS"</string>
+    <string name="data_connection_3_5g" msgid="4298721462047921400">"H"</string>
+    <string name="data_connection_3_5g_plus" msgid="6683055858295918170">"H+"</string>
+    <string name="data_connection_4g" msgid="2581705503356752044">"4G"</string>
+    <string name="data_connection_4g_plus" msgid="5194902328408751020">"4G+"</string>
+    <string name="data_connection_lte" msgid="7675461204366364124">"LTE"</string>
+    <string name="data_connection_lte_plus" msgid="6643158654804916653">"LTE+"</string>
+    <string name="cell_data_off_content_description" msgid="2280700839891636498">"Đã tắt dữ liệu di động"</string>
+    <string name="not_default_data_content_description" msgid="6517068332106592887">"Chưa được đặt để sử dụng dữ liệu"</string>
+    <string name="accessibility_no_phone" msgid="2687419663127582503">"Không có điện thoại nào."</string>
+    <string name="accessibility_phone_one_bar" msgid="5719721147018970063">"Tín hiệu điện thoại một vạch."</string>
+    <string name="accessibility_phone_two_bars" msgid="2531458337458953263">"Tín hiệu điện thoại hai vạch."</string>
+    <string name="accessibility_phone_three_bars" msgid="1523967995996696619">"Tín hiệu điện thoại ba vạch."</string>
+    <string name="accessibility_phone_signal_full" msgid="4302338883816077134">"Tín hiệu điện thoại đầy đủ."</string>
+    <string name="accessibility_no_data" msgid="4563181886936931008">"Không có dữ liệu."</string>
+    <string name="accessibility_data_one_bar" msgid="6892888138070752480">"Tín hiệu dữ liệu một vạch."</string>
+    <string name="accessibility_data_two_bars" msgid="9202641507241802499">"Tín hiệu dữ liệu hai vạch."</string>
+    <string name="accessibility_data_three_bars" msgid="2813876214466722413">"Tín hiệu dữ liệu ba vạch."</string>
+    <string name="accessibility_data_signal_full" msgid="1808301899314382337">"Tín hiệu dữ liệu đầy đủ."</string>
+    <string name="accessibility_ethernet_disconnected" msgid="2832501530856497489">"Đã ngắt kết nối Ethernet."</string>
+    <string name="accessibility_ethernet_connected" msgid="2093872142317190618">"Đã kết nối Ethernet."</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-zh-rCN/strings.xml b/packages/SettingsLib/res/values-zh-rCN/strings.xml
index c9ecab1..81d8106 100644
--- a/packages/SettingsLib/res/values-zh-rCN/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rCN/strings.xml
@@ -403,7 +403,6 @@
     <string name="transcode_user_control" msgid="6176368544817731314">"覆盖转码默认设置"</string>
     <string name="transcode_enable_all" msgid="2411165920039166710">"启用转码"</string>
     <string name="transcode_default" msgid="3784803084573509491">"假设应用支持现代格式"</string>
-    <string name="transcode_skip_apps" msgid="8249721984597390142">"为应用启用转码功能"</string>
     <string name="runningservices_settings_title" msgid="6460099290493086515">"正在运行的服务"</string>
     <string name="runningservices_settings_summary" msgid="1046080643262665743">"查看和控制当前正在运行的服务"</string>
     <string name="select_webview_provider_title" msgid="3917815648099445503">"WebView 实现"</string>
@@ -566,4 +565,29 @@
     <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"有线耳机"</string>
     <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"开启"</string>
     <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"关闭"</string>
+    <string name="carrier_network_change_mode" msgid="4257621815706644026">"运营商网络正在更改"</string>
+    <string name="data_connection_3g" msgid="931852552688157407">"3G"</string>
+    <string name="data_connection_edge" msgid="4625509456544797637">"EDGE"</string>
+    <string name="data_connection_cdma" msgid="9098161966701934334">"1X"</string>
+    <string name="data_connection_gprs" msgid="1251945769006770189">"GPRS"</string>
+    <string name="data_connection_3_5g" msgid="4298721462047921400">"H"</string>
+    <string name="data_connection_3_5g_plus" msgid="6683055858295918170">"H+"</string>
+    <string name="data_connection_4g" msgid="2581705503356752044">"4G"</string>
+    <string name="data_connection_4g_plus" msgid="5194902328408751020">"4G+"</string>
+    <string name="data_connection_lte" msgid="7675461204366364124">"LTE"</string>
+    <string name="data_connection_lte_plus" msgid="6643158654804916653">"LTE+"</string>
+    <string name="cell_data_off_content_description" msgid="2280700839891636498">"移动数据网络已关闭"</string>
+    <string name="not_default_data_content_description" msgid="6517068332106592887">"未设置为使用移动数据"</string>
+    <string name="accessibility_no_phone" msgid="2687419663127582503">"没有手机信号。"</string>
+    <string name="accessibility_phone_one_bar" msgid="5719721147018970063">"手机信号强度为一格。"</string>
+    <string name="accessibility_phone_two_bars" msgid="2531458337458953263">"手机信号强度为两格。"</string>
+    <string name="accessibility_phone_three_bars" msgid="1523967995996696619">"手机信号强度为三格。"</string>
+    <string name="accessibility_phone_signal_full" msgid="4302338883816077134">"手机信号满格。"</string>
+    <string name="accessibility_no_data" msgid="4563181886936931008">"没有数据网络信号。"</string>
+    <string name="accessibility_data_one_bar" msgid="6892888138070752480">"数据信号强度为一格。"</string>
+    <string name="accessibility_data_two_bars" msgid="9202641507241802499">"数据信号强度为两格。"</string>
+    <string name="accessibility_data_three_bars" msgid="2813876214466722413">"数据信号强度为三格。"</string>
+    <string name="accessibility_data_signal_full" msgid="1808301899314382337">"数据信号满格。"</string>
+    <string name="accessibility_ethernet_disconnected" msgid="2832501530856497489">"以太网已断开连接。"</string>
+    <string name="accessibility_ethernet_connected" msgid="2093872142317190618">"以太网已连接。"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-zh-rHK/strings.xml b/packages/SettingsLib/res/values-zh-rHK/strings.xml
index 3bbfa21..39a12aa 100644
--- a/packages/SettingsLib/res/values-zh-rHK/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rHK/strings.xml
@@ -403,7 +403,6 @@
     <string name="transcode_user_control" msgid="6176368544817731314">"覆寫轉碼預設設定"</string>
     <string name="transcode_enable_all" msgid="2411165920039166710">"啟用轉碼功能"</string>
     <string name="transcode_default" msgid="3784803084573509491">"假設應用程式支援新型格式"</string>
-    <string name="transcode_skip_apps" msgid="8249721984597390142">"為應用程式啟用轉碼功能"</string>
     <string name="runningservices_settings_title" msgid="6460099290493086515">"執行中的服務"</string>
     <string name="runningservices_settings_summary" msgid="1046080643262665743">"查看並控制目前正在執行中的服務"</string>
     <string name="select_webview_provider_title" msgid="3917815648099445503">"WebView 設置"</string>
@@ -566,4 +565,29 @@
     <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"有線耳機"</string>
     <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"開啟"</string>
     <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"關閉"</string>
+    <string name="carrier_network_change_mode" msgid="4257621815706644026">"流動網絡供應商網絡正在變更"</string>
+    <string name="data_connection_3g" msgid="931852552688157407">"3G"</string>
+    <string name="data_connection_edge" msgid="4625509456544797637">"EDGE"</string>
+    <string name="data_connection_cdma" msgid="9098161966701934334">"1X"</string>
+    <string name="data_connection_gprs" msgid="1251945769006770189">"GPRS"</string>
+    <string name="data_connection_3_5g" msgid="4298721462047921400">"H"</string>
+    <string name="data_connection_3_5g_plus" msgid="6683055858295918170">"H+"</string>
+    <string name="data_connection_4g" msgid="2581705503356752044">"4G"</string>
+    <string name="data_connection_4g_plus" msgid="5194902328408751020">"4G+"</string>
+    <string name="data_connection_lte" msgid="7675461204366364124">"LTE"</string>
+    <string name="data_connection_lte_plus" msgid="6643158654804916653">"LTE+"</string>
+    <string name="cell_data_off_content_description" msgid="2280700839891636498">"流動數據已關閉"</string>
+    <string name="not_default_data_content_description" msgid="6517068332106592887">"未設定至可使用資料"</string>
+    <string name="accessibility_no_phone" msgid="2687419663127582503">"沒有電話訊號。"</string>
+    <string name="accessibility_phone_one_bar" msgid="5719721147018970063">"電話訊號強度為一格。"</string>
+    <string name="accessibility_phone_two_bars" msgid="2531458337458953263">"電話訊號強度為兩格。"</string>
+    <string name="accessibility_phone_three_bars" msgid="1523967995996696619">"電話訊號強度為三格。"</string>
+    <string name="accessibility_phone_signal_full" msgid="4302338883816077134">"電話訊號滿格。"</string>
+    <string name="accessibility_no_data" msgid="4563181886936931008">"沒有數據網絡。"</string>
+    <string name="accessibility_data_one_bar" msgid="6892888138070752480">"數據網絡訊號強度為一格。"</string>
+    <string name="accessibility_data_two_bars" msgid="9202641507241802499">"數據網絡訊號強度為兩格。"</string>
+    <string name="accessibility_data_three_bars" msgid="2813876214466722413">"數據網絡訊號強度為三格。"</string>
+    <string name="accessibility_data_signal_full" msgid="1808301899314382337">"數據網絡訊號滿格。"</string>
+    <string name="accessibility_ethernet_disconnected" msgid="2832501530856497489">"以太網連接中斷。"</string>
+    <string name="accessibility_ethernet_connected" msgid="2093872142317190618">"已連接以太網。"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-zh-rTW/strings.xml b/packages/SettingsLib/res/values-zh-rTW/strings.xml
index b0dbb5f..cc35ed3 100644
--- a/packages/SettingsLib/res/values-zh-rTW/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rTW/strings.xml
@@ -403,7 +403,6 @@
     <string name="transcode_user_control" msgid="6176368544817731314">"覆寫轉碼預設設定"</string>
     <string name="transcode_enable_all" msgid="2411165920039166710">"啟用轉碼"</string>
     <string name="transcode_default" msgid="3784803084573509491">"假設應用程式支援新格式"</string>
-    <string name="transcode_skip_apps" msgid="8249721984597390142">"替應用程式啟用轉碼功能"</string>
     <string name="runningservices_settings_title" msgid="6460099290493086515">"正在運作的服務"</string>
     <string name="runningservices_settings_summary" msgid="1046080643262665743">"查看並管理目前正在執行的服務"</string>
     <string name="select_webview_provider_title" msgid="3917815648099445503">"WebView 實作"</string>
@@ -566,4 +565,29 @@
     <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"有線耳機"</string>
     <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"開啟"</string>
     <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"關閉"</string>
+    <string name="carrier_network_change_mode" msgid="4257621815706644026">"電信業者網路正在進行變更"</string>
+    <string name="data_connection_3g" msgid="931852552688157407">"3G"</string>
+    <string name="data_connection_edge" msgid="4625509456544797637">"EDGE"</string>
+    <string name="data_connection_cdma" msgid="9098161966701934334">"1X"</string>
+    <string name="data_connection_gprs" msgid="1251945769006770189">"GPRS"</string>
+    <string name="data_connection_3_5g" msgid="4298721462047921400">"H"</string>
+    <string name="data_connection_3_5g_plus" msgid="6683055858295918170">"H+"</string>
+    <string name="data_connection_4g" msgid="2581705503356752044">"4G"</string>
+    <string name="data_connection_4g_plus" msgid="5194902328408751020">"4G+"</string>
+    <string name="data_connection_lte" msgid="7675461204366364124">"LTE"</string>
+    <string name="data_connection_lte_plus" msgid="6643158654804916653">"LTE+"</string>
+    <string name="cell_data_off_content_description" msgid="2280700839891636498">"行動數據已關閉"</string>
+    <string name="not_default_data_content_description" msgid="6517068332106592887">"並未設為使用行動數據"</string>
+    <string name="accessibility_no_phone" msgid="2687419663127582503">"沒有電話訊號。"</string>
+    <string name="accessibility_phone_one_bar" msgid="5719721147018970063">"電話訊號強度一格。"</string>
+    <string name="accessibility_phone_two_bars" msgid="2531458337458953263">"電話訊號強度兩格。"</string>
+    <string name="accessibility_phone_three_bars" msgid="1523967995996696619">"電話訊號強度三格。"</string>
+    <string name="accessibility_phone_signal_full" msgid="4302338883816077134">"電話訊號滿格。"</string>
+    <string name="accessibility_no_data" msgid="4563181886936931008">"沒有數據網路。"</string>
+    <string name="accessibility_data_one_bar" msgid="6892888138070752480">"數據網路訊號強度一格。"</string>
+    <string name="accessibility_data_two_bars" msgid="9202641507241802499">"數據網路訊號強度兩格。"</string>
+    <string name="accessibility_data_three_bars" msgid="2813876214466722413">"數據網路訊號強度三格。"</string>
+    <string name="accessibility_data_signal_full" msgid="1808301899314382337">"數據網路訊號滿格。"</string>
+    <string name="accessibility_ethernet_disconnected" msgid="2832501530856497489">"未連上乙太網路。"</string>
+    <string name="accessibility_ethernet_connected" msgid="2093872142317190618">"已連上乙太網路。"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-zu/strings.xml b/packages/SettingsLib/res/values-zu/strings.xml
index 8f7c2ac1..bcc6369 100644
--- a/packages/SettingsLib/res/values-zu/strings.xml
+++ b/packages/SettingsLib/res/values-zu/strings.xml
@@ -403,7 +403,6 @@
     <string name="transcode_user_control" msgid="6176368544817731314">"Khipha okuzenzakalelayo kokudlulisela ikhodi"</string>
     <string name="transcode_enable_all" msgid="2411165920039166710">"Nika amandla ukudlulisela ikhodi"</string>
     <string name="transcode_default" msgid="3784803084573509491">"Kuthathe njengokungathi izinhlelo zokusebenza zisekela amafomethi esimanje"</string>
-    <string name="transcode_skip_apps" msgid="8249721984597390142">"Nika amandla ukudlulisela ikhodi kwezinhlelo zokusebenza"</string>
     <string name="runningservices_settings_title" msgid="6460099290493086515">"Amasevisi asebenzayo"</string>
     <string name="runningservices_settings_summary" msgid="1046080643262665743">"Buka futhi ulawule amasevisi  asebenzayo okwamanje"</string>
     <string name="select_webview_provider_title" msgid="3917815648099445503">"Ukufakwa ke-WebView"</string>
@@ -566,4 +565,29 @@
     <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Ama-headphone anentambo"</string>
     <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Vuliwe"</string>
     <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Valiwe"</string>
+    <string name="carrier_network_change_mode" msgid="4257621815706644026">"Inethiwekhi yenkampani yenethiwekhi iyashintsha"</string>
+    <string name="data_connection_3g" msgid="931852552688157407">"3G"</string>
+    <string name="data_connection_edge" msgid="4625509456544797637">"I-EDGE"</string>
+    <string name="data_connection_cdma" msgid="9098161966701934334">"1X"</string>
+    <string name="data_connection_gprs" msgid="1251945769006770189">"I-GPRS"</string>
+    <string name="data_connection_3_5g" msgid="4298721462047921400">"H"</string>
+    <string name="data_connection_3_5g_plus" msgid="6683055858295918170">"H+"</string>
+    <string name="data_connection_4g" msgid="2581705503356752044">"4G"</string>
+    <string name="data_connection_4g_plus" msgid="5194902328408751020">"4G+"</string>
+    <string name="data_connection_lte" msgid="7675461204366364124">"I-LTE"</string>
+    <string name="data_connection_lte_plus" msgid="6643158654804916653">"I-LTE+"</string>
+    <string name="cell_data_off_content_description" msgid="2280700839891636498">"Idatha yeselula ivaliwe"</string>
+    <string name="not_default_data_content_description" msgid="6517068332106592887">"Akusethiwe ukuze kusetshenziswe idatha"</string>
+    <string name="accessibility_no_phone" msgid="2687419663127582503">"Ayikho ifoni."</string>
+    <string name="accessibility_phone_one_bar" msgid="5719721147018970063">"Ibha eyodwa yefoni"</string>
+    <string name="accessibility_phone_two_bars" msgid="2531458337458953263">"Amabha amabilil efoni."</string>
+    <string name="accessibility_phone_three_bars" msgid="1523967995996696619">"Amabha amathathu efoni"</string>
+    <string name="accessibility_phone_signal_full" msgid="4302338883816077134">"Isiginali yefoni igcwele"</string>
+    <string name="accessibility_no_data" msgid="4563181886936931008">"Ayikho idatha."</string>
+    <string name="accessibility_data_one_bar" msgid="6892888138070752480">"Idatha enye yebha"</string>
+    <string name="accessibility_data_two_bars" msgid="9202641507241802499">"Amabha amabili edatha"</string>
+    <string name="accessibility_data_three_bars" msgid="2813876214466722413">"Amabha amathathu edatha"</string>
+    <string name="accessibility_data_signal_full" msgid="1808301899314382337">"Igcwele i-signal yedatha"</string>
+    <string name="accessibility_ethernet_disconnected" msgid="2832501530856497489">"I-Ethernet inqanyuliwe."</string>
+    <string name="accessibility_ethernet_connected" msgid="2093872142317190618">"I-Ethernet ixhunyiwe."</string>
 </resources>
diff --git a/packages/SettingsLib/src/com/android/settingslib/media/MediaOutputSliceConstants.java b/packages/SettingsLib/src/com/android/settingslib/media/MediaOutputSliceConstants.java
index fc16eb6..61af5a7 100644
--- a/packages/SettingsLib/src/com/android/settingslib/media/MediaOutputSliceConstants.java
+++ b/packages/SettingsLib/src/com/android/settingslib/media/MediaOutputSliceConstants.java
@@ -22,16 +22,6 @@
 public class MediaOutputSliceConstants {
 
     /**
-     * Key for the Media output setting.
-     */
-    public static final String KEY_MEDIA_OUTPUT = "media_output";
-
-    /**
-     * Key for the Media output group setting.
-     */
-    public static final String KEY_MEDIA_OUTPUT_GROUP = "media_output_group";
-
-    /**
      * Key for the Remote Media slice.
      */
     public static final String KEY_REMOTE_MEDIA = "remote_media";
@@ -47,19 +37,6 @@
     public static final String KEY_SESSION_INFO_ID = "key_session_info_id";
 
     /**
-     * Activity Action: Show a settings dialog containing {@link MediaDevice} to transfer media.
-     */
-    public static final String ACTION_MEDIA_OUTPUT =
-            "com.android.settings.panel.action.MEDIA_OUTPUT";
-
-    /**
-     * Activity Action: Show a settings dialog containing {@link MediaDevice} to handle media group
-     * operation.
-     */
-    public static final String ACTION_MEDIA_OUTPUT_GROUP =
-            "com.android.settings.panel.action.MEDIA_OUTPUT_GROUP";
-
-    /**
      * A string extra specifying a media package name.
      */
     public static final String EXTRA_PACKAGE_NAME =
@@ -72,12 +49,6 @@
             "com.android.systemui.action.LAUNCH_MEDIA_OUTPUT_DIALOG";
 
     /**
-     * An intent action to dismiss media output dialog.
-     */
-    public static final String ACTION_DISMISS_MEDIA_OUTPUT_DIALOG =
-            "com.android.systemui.action.DISMISS_MEDIA_OUTPUT_DIALOG";
-
-    /**
      * Settings package name.
      */
     public static final String SETTINGS_PACKAGE_NAME = "com.android.settings";
diff --git a/packages/SettingsProvider/res/values/defaults.xml b/packages/SettingsProvider/res/values/defaults.xml
index 846efa7..6c51f2f 100644
--- a/packages/SettingsProvider/res/values/defaults.xml
+++ b/packages/SettingsProvider/res/values/defaults.xml
@@ -241,6 +241,12 @@
     <!-- Default for setting for Settings.Global.HDMI_CONTROL_AUTO_DEVICE_OFF_ENABLED -->
     <bool name="def_hdmiControlAutoDeviceOff">false</bool>
 
+    <!-- Default for Settings.Secure.SWIPE_BOTTOM_TO_NOTIFICATION_ENABLED -->
+    <bool name="def_swipe_bottom_to_notification_enabled">true</bool>
+
+    <!-- Default for Settings.Secure.ONE_HANDED_MODE_ENABLED -->
+    <bool name="def_one_handed_mode_enabled">false</bool>
+
     <!-- Default for Settings.Secure.ACCESSIBILITY_MAGNIFICATION_CAPABILITY -->
     <integer name="def_accessibility_magnification_capabilities">3</integer>
 </resources>
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index c9e3b6f..edb5506 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -3342,7 +3342,7 @@
         }
 
         private final class UpgradeController {
-            private static final int SETTINGS_VERSION = 196;
+            private static final int SETTINGS_VERSION = 197;
 
             private final int mUserId;
 
@@ -4786,6 +4786,35 @@
                     currentVersion = 196;
                 }
 
+                if (currentVersion == 196) {
+                    // Version 196: Set the default value for Secure Settings:
+                    // SWIPE_BOTTOM_TO_NOTIFICATION_ENABLED & ONE_HANDED_MODE_ENABLED
+                    final SettingsState secureSettings = getSecureSettingsLocked(userId);
+                    final Setting swipeNotification = secureSettings.getSettingLocked(
+                            Secure.SWIPE_BOTTOM_TO_NOTIFICATION_ENABLED);
+                    if (swipeNotification.isNull()) {
+                        final boolean defSwipeNotification = getContext().getResources()
+                                .getBoolean(R.bool.def_swipe_bottom_to_notification_enabled);
+                        secureSettings.insertSettingLocked(
+                                Secure.SWIPE_BOTTOM_TO_NOTIFICATION_ENABLED,
+                                defSwipeNotification ? "1" : "0", null, true,
+                                SettingsState.SYSTEM_PACKAGE_NAME);
+                    }
+
+                    final Setting oneHandedModeEnabled = secureSettings.getSettingLocked(
+                            Secure.ONE_HANDED_MODE_ENABLED);
+                    if (oneHandedModeEnabled.isNull()) {
+                        final boolean defOneHandedModeEnabled = getContext().getResources()
+                                .getBoolean(R.bool.def_one_handed_mode_enabled);
+                        secureSettings.insertSettingLocked(
+                                Secure.ONE_HANDED_MODE_ENABLED,
+                                defOneHandedModeEnabled ? "1" : "0", null, true,
+                                SettingsState.SYSTEM_PACKAGE_NAME);
+                    }
+
+                    currentVersion = 197;
+                }
+
                 // vXXX: Add new settings above this point.
 
                 if (currentVersion != newVersion) {
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java
index 40b0fcff..53d868a 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java
@@ -42,6 +42,8 @@
 import android.util.Slog;
 import android.util.SparseIntArray;
 import android.util.TimeUtils;
+import android.util.TypedXmlPullParser;
+import android.util.TypedXmlSerializer;
 import android.util.Xml;
 import android.util.proto.ProtoOutputStream;
 
@@ -52,7 +54,6 @@
 
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
-import org.xmlpull.v1.XmlSerializer;
 
 import java.io.File;
 import java.io.FileInputStream;
@@ -60,7 +61,6 @@
 import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.PrintWriter;
-import java.nio.charset.StandardCharsets;
 import java.nio.file.Files;
 import java.nio.file.Path;
 import java.util.ArrayList;
@@ -806,13 +806,10 @@
             try {
                 out = destination.startWrite();
 
-                XmlSerializer serializer = Xml.newSerializer();
-                serializer.setOutput(out, StandardCharsets.UTF_8.name());
-                serializer.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output",
-                        true);
+                TypedXmlSerializer serializer = Xml.resolveSerializer(out);
                 serializer.startDocument(null, true);
                 serializer.startTag(null, TAG_SETTINGS);
-                serializer.attribute(null, ATTR_VERSION, String.valueOf(version));
+                serializer.attributeInt(null, ATTR_VERSION, version);
 
                 final int settingCount = settings.size();
                 for (int i = 0; i < settingCount; i++) {
@@ -908,7 +905,7 @@
         }
     }
 
-    static void writeSingleSetting(int version, XmlSerializer serializer, String id,
+    static void writeSingleSetting(int version, TypedXmlSerializer serializer, String id,
             String name, String value, String defaultValue, String packageName,
             String tag, boolean defaultSysSet, boolean isValuePreservedInRestore)
             throws IOException {
@@ -926,18 +923,18 @@
         if (defaultValue != null) {
             setValueAttribute(ATTR_DEFAULT_VALUE, ATTR_DEFAULT_VALUE_BASE64,
                     version, serializer, defaultValue);
-            serializer.attribute(null, ATTR_DEFAULT_SYS_SET, Boolean.toString(defaultSysSet));
+            serializer.attributeBoolean(null, ATTR_DEFAULT_SYS_SET, defaultSysSet);
             setValueAttribute(ATTR_TAG, ATTR_TAG_BASE64,
                     version, serializer, tag);
         }
         if (isValuePreservedInRestore) {
-            serializer.attribute(null, ATTR_PRESERVE_IN_RESTORE, Boolean.toString(true));
+            serializer.attributeBoolean(null, ATTR_PRESERVE_IN_RESTORE, true);
         }
         serializer.endTag(null, TAG_SETTING);
     }
 
     static void setValueAttribute(String attr, String attrBase64, int version,
-            XmlSerializer serializer, String value) throws IOException {
+            TypedXmlSerializer serializer, String value) throws IOException {
         if (version >= SETTINGS_VERSION_NEW_ENCODING) {
             if (value == null) {
                 // Null value -> No ATTR_VALUE nor ATTR_VALUE_BASE64.
@@ -956,7 +953,7 @@
         }
     }
 
-    private static void writeSingleNamespaceHash(XmlSerializer serializer, String namespace,
+    private static void writeSingleNamespaceHash(TypedXmlSerializer serializer, String namespace,
             String bannedHashCode) throws IOException {
         if (namespace == null || bannedHashCode == null) {
             return;
@@ -971,7 +968,7 @@
         return Integer.toString(keyValues.hashCode());
     }
 
-    private String getValueAttribute(XmlPullParser parser, String attr, String base64Attr) {
+    private String getValueAttribute(TypedXmlPullParser parser, String attr, String base64Attr) {
         if (mVersion >= SETTINGS_VERSION_NEW_ENCODING) {
             final String value = parser.getAttributeValue(null, attr);
             if (value != null) {
@@ -1039,8 +1036,7 @@
     @GuardedBy("mLock")
     private boolean parseStateFromXmlStreamLocked(FileInputStream in) {
         try {
-            XmlPullParser parser = Xml.newPullParser();
-            parser.setInput(in, StandardCharsets.UTF_8.name());
+            TypedXmlPullParser parser = Xml.resolvePullParser(in);
             parseStateLocked(parser);
             return true;
         } catch (XmlPullParserException | IOException e) {
@@ -1060,7 +1056,7 @@
         return stateFile.exists();
     }
 
-    private void parseStateLocked(XmlPullParser parser)
+    private void parseStateLocked(TypedXmlPullParser parser)
             throws IOException, XmlPullParserException {
         final int outerDepth = parser.getDepth();
         int type;
@@ -1080,10 +1076,10 @@
     }
 
     @GuardedBy("mLock")
-    private void parseSettingsLocked(XmlPullParser parser)
+    private void parseSettingsLocked(TypedXmlPullParser parser)
             throws IOException, XmlPullParserException {
 
-        mVersion = Integer.parseInt(parser.getAttributeValue(null, ATTR_VERSION));
+        mVersion = parser.getAttributeInt(null, ATTR_VERSION);
 
         final int outerDepth = parser.getDepth();
         int type;
@@ -1101,14 +1097,12 @@
                 String packageName = parser.getAttributeValue(null, ATTR_PACKAGE);
                 String defaultValue = getValueAttribute(parser, ATTR_DEFAULT_VALUE,
                         ATTR_DEFAULT_VALUE_BASE64);
-                String isPreservedInRestoreString = parser.getAttributeValue(null,
-                        ATTR_PRESERVE_IN_RESTORE);
-                boolean isPreservedInRestore = Boolean.parseBoolean(isPreservedInRestoreString);
+                boolean isPreservedInRestore = parser.getAttributeBoolean(null,
+                        ATTR_PRESERVE_IN_RESTORE, false);
                 String tag = null;
                 boolean fromSystem = false;
                 if (defaultValue != null) {
-                    fromSystem = Boolean.parseBoolean(parser.getAttributeValue(
-                            null, ATTR_DEFAULT_SYS_SET));
+                    fromSystem = parser.getAttributeBoolean(null, ATTR_DEFAULT_SYS_SET, false);
                     tag = getValueAttribute(parser, ATTR_TAG, ATTR_TAG_BASE64);
                 }
                 mSettings.put(name, new Setting(name, value, defaultValue, packageName, tag,
@@ -1122,7 +1116,7 @@
     }
 
     @GuardedBy("mLock")
-    private void parseNamespaceHash(XmlPullParser parser)
+    private void parseNamespaceHash(TypedXmlPullParser parser)
             throws IOException, XmlPullParserException {
 
         final int outerDepth = parser.getDepth();
diff --git a/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsStateTest.java b/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsStateTest.java
index 9f448af..69eb713 100644
--- a/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsStateTest.java
+++ b/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsStateTest.java
@@ -17,15 +17,13 @@
 
 import android.os.Looper;
 import android.test.AndroidTestCase;
+import android.util.TypedXmlSerializer;
 import android.util.Xml;
 
-import org.xmlpull.v1.XmlSerializer;
-
 import java.io.ByteArrayOutputStream;
 import java.io.File;
 import java.io.FileOutputStream;
 import java.io.PrintStream;
-import java.nio.charset.StandardCharsets;
 
 public class SettingsStateTest extends AndroidTestCase {
     public static final String CRAZY_STRING =
@@ -93,9 +91,7 @@
     public void testWriteReadNoCrash() throws Exception {
         ByteArrayOutputStream os = new ByteArrayOutputStream();
 
-        XmlSerializer serializer = Xml.newSerializer();
-        serializer.setOutput(os, StandardCharsets.UTF_8.name());
-        serializer.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true);
+        TypedXmlSerializer serializer = Xml.resolveSerializer(os);
         serializer.startDocument(null, true);
 
         for (int ch = 0; ch < 0x10000; ch++) {
@@ -118,12 +114,12 @@
                 serializer, "1", "k", "v", null, null, null, false, false);
     }
 
-    private void checkWriteSingleSetting(XmlSerializer serializer, String key, String value)
+    private void checkWriteSingleSetting(TypedXmlSerializer serializer, String key, String value)
             throws Exception {
         checkWriteSingleSetting(key + "/" + value, serializer, key, value);
     }
 
-    private void checkWriteSingleSetting(String msg, XmlSerializer serializer,
+    private void checkWriteSingleSetting(String msg, TypedXmlSerializer serializer,
             String key, String value) throws Exception {
         // Make sure the XML serializer won't crash.
         SettingsState.writeSingleSetting(
diff --git a/packages/SystemUI/res/drawable/ic_fingerprint.xml b/packages/SystemUI/res/drawable/ic_fingerprint.xml
new file mode 100644
index 0000000..e5f3360
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_fingerprint.xml
@@ -0,0 +1,59 @@
+<!--
+    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
+-->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="32dp"
+        android:height="32dp"
+        android:tint="?attr/wallpaperTextColor"
+        android:alpha=".75"
+        android:viewportHeight="32.0"
+        android:viewportWidth="32.0">
+    <path
+        android:fillColor="#ffffff"
+        android:pathData="M23.7,5.9c-0.1,0.0 -0.2,0.0 -0.3,-0.1C21.0,4.5 18.6,3.9 16.0,3.9c-2.5,0.0
+         -4.6,0.6 -6.9,1.9C8.8,6.0 8.3,5.9 8.1,5.5C7.9,5.2 8.0,4.7 8.4,4.5c2.5,-1.4 4.9,-2.1 7.7,
+         -2.1c2.8,0.0 5.4,0.7 8.0,2.1c0.4,0.2 0.5,0.6 0.3,1.0C24.2,5.7 24.0,5.9 23.7,5.9z" />
+    <path
+        android:fillColor="#ffffff"
+        android:pathData="M5.3,13.2c-0.1,0.0 -0.3,0.0 -0.4,-0.1c-0.3,-0.2 -0.4,-0.7 -0.2,-1.0c1.3,
+        -1.9 2.9,-3.4 4.9,-4.5c4.1,-2.2 9.3,-2.2 13.4,0.0c1.9,1.1 3.6,2.5 4.9,4.4c0.2,0.3 0.1,0.8
+        -0.2,1.0c-0.3,0.2 -0.8,0.1 -1.0,-0.2c-1.2,-1.7 -2.6,-3.0 -4.3,-4.0c-3.7,-2.0 -8.3,-2.0
+         -12.0,0.0c-1.7,0.9 -3.2,2.3 -4.3,4.0C5.7,13.1 5.5,13.2 5.3,13.2z" />
+    <path
+        android:fillColor="#ffffff"
+        android:pathData="M13.3,29.6c-0.2,0.0 -0.4,-0.1 -0.5,-0.2c-1.1,-1.2 -1.7,-2.0 -2.6,
+        -3.6c-0.9,-1.7 -1.4,-3.7 -1.4,-5.9c0.0,-4.1 3.3,-7.4 7.4,-7.4c4.1,0.0 7.4,3.3 7.4,7.4c0.0,
+        0.4 -0.3,0.7 -0.7,0.7s-0.7,-0.3 -0.7,-0.7c0.0,-3.3 -2.7,-5.9 -5.9,-5.9c-3.3,0.0 -5.9,
+        2.7 -5.9,5.9c0.0,2.0 0.4,3.8 1.2,5.2c0.8,1.6 1.4,2.2 2.4,3.3c0.3,0.3 0.3,0.8 0.0,1.0
+        C13.7,29.5 13.5,29.6 13.3,29.6z" />
+    <path
+        android:fillColor="#ffffff"
+        android:pathData="M22.6,27.1c-1.6,0.0 -2.9,-0.4 -4.1,-1.2c-1.9,-1.4 -3.1,-3.6 -3.1,
+        -6.0c0.0,-0.4 0.3,-0.7 0.7,-0.7s0.7,0.3 0.7,0.7c0.0,1.9 0.9,3.7 2.5,4.8c0.9,0.6 1.9,
+        1.0 3.2,1.0c0.3,0.0 0.8,0.0 1.3,-0.1c0.4,-0.1 0.8,0.2 0.8,0.6c0.1,0.4 -0.2,0.8 -0.6,
+        0.8C23.4,27.1 22.8,27.1 22.6,27.1z" />
+    <path
+        android:fillColor="#ffffff"
+        android:pathData="M20.0,29.9c-0.1,0.0 -0.1,0.0 -0.2,0.0c-2.1,-0.6 -3.4,-1.4 -4.8,-2.9c-1.8,
+        -1.9 -2.8,-4.4 -2.8,-7.1c0.0,-2.2 1.8,-4.1 4.1,-4.1c2.2,0.0 4.1,1.8 4.1,4.1c0.0,1.4 1.2,
+        2.6 2.6,2.6c1.4,0.0 2.6,-1.2 2.6,-2.6c0.0,-5.1 -4.2,-9.3 -9.3,-9.3c-3.6,0.0 -6.9,2.1 -8.4,
+        5.4C7.3,17.1 7.0,18.4 7.0,19.8c0.0,1.1 0.1,2.7 0.9,4.9c0.1,0.4 -0.1,0.8 -0.4,0.9c-0.4,
+        0.1 -0.8,-0.1 -0.9,-0.4c-0.6,-1.8 -0.9,-3.6 -0.9,-5.4c0.0,-1.6 0.3,-3.1 0.9,-4.4c1.7,
+        -3.8 5.6,-6.3 9.8,-6.3c5.9,0.0 10.7,4.8 10.7,10.7c0.0,2.2 -1.8,4.1 -4.1,4.1s-4.0,
+        -1.8 -4.0,-4.1c0.0,-1.4 -1.2,-2.6 -2.6,-2.6c-1.4,0.0 -2.6,1.2 -2.6,2.6c0.0,2.3 0.9,
+        4.5 2.4,6.1c1.2,1.3 2.4,2.0 4.2,2.5c0.4,0.1 0.6,0.5 0.5,0.9C20.6,29.7 20.3,29.9 20.0,
+        29.9z" />
+</vector>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/people_space_small_avatar_tile.xml b/packages/SystemUI/res/layout/people_space_small_avatar_tile.xml
index 085e955..5aa0533 100644
--- a/packages/SystemUI/res/layout/people_space_small_avatar_tile.xml
+++ b/packages/SystemUI/res/layout/people_space_small_avatar_tile.xml
@@ -18,89 +18,177 @@
     android:layout_width="match_parent"
     android:layout_height="match_parent"
     android:orientation="vertical">
-    <LinearLayout
+    <RelativeLayout
         android:background="@drawable/people_space_tile_view_card"
-        android:id="@+id/item"
-        android:orientation="vertical"
-        android:paddingTop="6dp"
         android:layout_width="match_parent"
         android:layout_height="match_parent">
         <LinearLayout
             android:orientation="horizontal"
-            android:paddingHorizontal="12dp"
-            android:paddingBottom="4dp"
-            android:gravity="top"
             android:layout_width="match_parent"
-            android:layout_height="wrap_content">
-
-            <ImageView
-                android:id="@+id/person_icon"
-                android:layout_width="34dp"
-                android:layout_height="34dp" />
-
+            android:layout_height="match_parent"
+            android:gravity="start">
+            <TextView
+                android:id="@+id/punctuation1"
+                android:textColor="?android:attr/textColorSecondary"
+                android:textAppearance="@*android:style/TextAppearance.DeviceDefault.ListItem"
+                android:textSize="36sp"
+                android:textStyle="bold"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_marginTop="5dp"
+                android:maxLines="1"
+                android:alpha="0.2"
+                android:rotation="350" />
+            <TextView
+                android:id="@+id/punctuation2"
+                android:textColor="?android:attr/textColorSecondary"
+                android:textAppearance="@*android:style/TextAppearance.DeviceDefault.ListItem"
+                android:textSize="36sp"
+                android:textStyle="bold"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_marginStart="25dp"
+                android:maxLines="1"
+                android:alpha="0.2"
+                android:rotation="5" />
+            <TextView
+                android:id="@+id/punctuation3"
+                android:textColor="?android:attr/textColorSecondary"
+                android:textAppearance="@*android:style/TextAppearance.DeviceDefault.ListItem"
+                android:textSize="36sp"
+                android:textStyle="bold"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_marginTop="5dp"
+                android:layout_marginStart="25dp"
+                android:maxLines="1"
+                android:alpha="0.2"
+                android:rotation="355"/>
+            <TextView
+                android:id="@+id/punctuation4"
+                android:textColor="?android:attr/textColorSecondary"
+                android:textAppearance="@*android:style/TextAppearance.DeviceDefault.ListItem"
+                android:textSize="36sp"
+                android:textStyle="bold"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_marginTop="-5dp"
+                android:layout_marginStart="25dp"
+                android:maxLines="1"
+                android:alpha="0.2"
+                android:rotation="10" />
+            <TextView
+                android:id="@+id/punctuation5"
+                android:textColor="?android:attr/textColorSecondary"
+                android:textAppearance="@*android:style/TextAppearance.DeviceDefault.ListItem"
+                android:textSize="36sp"
+                android:textStyle="bold"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_marginTop="5dp"
+                android:layout_marginStart="25dp"
+                android:maxLines="1"
+                android:alpha="0.2"
+                android:rotation="15" />
+            <TextView
+                android:id="@+id/punctuation6"
+                android:textColor="?android:attr/textColorSecondary"
+                android:textAppearance="@*android:style/TextAppearance.DeviceDefault.ListItem"
+                android:textSize="36sp"
+                android:textStyle="bold"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_marginTop="-5dp"
+                android:layout_marginStart="25dp"
+                android:maxLines="1"
+                android:alpha="0.2"
+                android:rotation="345" />
+        </LinearLayout>
+        <LinearLayout
+            android:id="@+id/item"
+            android:orientation="vertical"
+            android:paddingTop="6dp"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent">
             <LinearLayout
-                android:background="@drawable/people_space_rounded_border"
-                android:layout_marginStart="-5dp"
-                android:layout_marginTop="18dp"
-                android:layout_width="8dp"
-                android:layout_height="8dp">
-
-                <ImageView
-                    android:id="@+id/package_icon"
-                    android:layout_width="6dp"
-                    android:layout_marginEnd="1dp"
-                    android:layout_marginStart="1dp"
-                    android:layout_marginBottom="1dp"
-                    android:layout_marginTop="1dp"
-                    android:layout_height="6dp" />
-            </LinearLayout>
-
-            <LinearLayout
-                android:orientation="vertical"
-                android:paddingStart="6dp"
+                android:orientation="horizontal"
+                android:paddingHorizontal="12dp"
+                android:paddingBottom="4dp"
+                android:gravity="top"
                 android:layout_width="match_parent"
                 android:layout_height="wrap_content">
 
-                <TextView
-                    android:id="@+id/name"
-                    android:textAppearance="@*android:style/TextAppearance.DeviceDefault.ListItem"
-                    android:textColor="?android:attr/textColorPrimary"
-                    android:textSize="14sp"
-                    android:maxLines="1"
-                    android:ellipsize="end"
-                    android:layout_width="wrap_content"
-                    android:layout_height="wrap_content" />
+                <ImageView
+                    android:id="@+id/person_icon"
+                    android:layout_width="34dp"
+                    android:layout_height="34dp" />
 
+                <LinearLayout
+                    android:background="@drawable/people_space_rounded_border"
+                    android:layout_marginStart="-5dp"
+                    android:layout_marginTop="18dp"
+                    android:layout_width="8dp"
+                    android:layout_height="8dp">
+
+                    <ImageView
+                        android:id="@+id/package_icon"
+                        android:layout_width="6dp"
+                        android:layout_marginEnd="1dp"
+                        android:layout_marginStart="1dp"
+                        android:layout_marginBottom="1dp"
+                        android:layout_marginTop="1dp"
+                        android:layout_height="6dp" />
+                </LinearLayout>
+
+                <LinearLayout
+                    android:orientation="vertical"
+                    android:paddingStart="6dp"
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content">
+
+                    <TextView
+                        android:id="@+id/name"
+                        android:textAppearance="@*android:style/TextAppearance.DeviceDefault.ListItem"
+                        android:textColor="?android:attr/textColorPrimary"
+                        android:textSize="14sp"
+                        android:maxLines="1"
+                        android:ellipsize="end"
+                        android:layout_width="wrap_content"
+                        android:layout_height="wrap_content" />
+
+                    <TextView
+                        android:id="@+id/time"
+                        android:textColor="?android:attr/textColorSecondary"
+                        android:textAppearance="@*android:style/TextAppearance.DeviceDefault.ListItem"
+                        android:textSize="10sp"
+                        android:layout_width="wrap_content"
+                        android:layout_height="wrap_content"
+                        android:maxLines="1"
+                        android:ellipsize="end" />
+                </LinearLayout>
+            </LinearLayout>
+            <LinearLayout
+                android:background="@drawable/people_space_content_background"
+                android:layout_gravity="center"
+                android:layout_width="match_parent"
+                android:layout_height="match_parent">
                 <TextView
-                    android:id="@+id/time"
-                    android:textColor="?android:attr/textColorSecondary"
+                    android:id="@+id/content"
+                    android:paddingVertical="3dp"
+                    android:paddingHorizontal="12dp"
+                    android:gravity="center"
                     android:textAppearance="@*android:style/TextAppearance.DeviceDefault.ListItem"
-                    android:textSize="10sp"
-                    android:layout_width="wrap_content"
-                    android:layout_height="wrap_content"
-                    android:maxLines="1"
+                    android:textSize="16sp"
+                    android:layout_width="match_parent"
+                    android:layout_height="match_parent"
+                    android:maxLines="2"
                     android:ellipsize="end" />
+                <ImageView
+                    android:id="@+id/image"
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    android:visibility="gone"/>
             </LinearLayout>
         </LinearLayout>
-        <LinearLayout
-            android:background="@drawable/people_space_content_background"
-            android:layout_width="match_parent"
-            android:layout_height="match_parent">
-            <TextView
-                android:id="@+id/content"
-                android:paddingVertical="3dp"
-                android:paddingHorizontal="12dp"
-                android:textAppearance="@*android:style/TextAppearance.DeviceDefault.ListItem"
-                android:textSize="14sp"
-                android:layout_width="match_parent"
-                android:layout_height="match_parent"
-                android:maxLines="2"
-                android:ellipsize="end" />
-            <ImageView
-                android:id="@+id/image"
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"
-                android:visibility="gone"/>
-        </LinearLayout>
-    </LinearLayout>
+    </RelativeLayout>
 </LinearLayout>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/status_bar_notification_row.xml b/packages/SystemUI/res/layout/status_bar_notification_row.xml
index 84b9e3d..2c08f5d 100644
--- a/packages/SystemUI/res/layout/status_bar_notification_row.xml
+++ b/packages/SystemUI/res/layout/status_bar_notification_row.xml
@@ -18,6 +18,7 @@
 <!-- extends FrameLayout -->
 <com.android.systemui.statusbar.notification.row.ExpandableNotificationRow
     xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/expandableNotificationRow"
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
     android:focusable="true"
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 52b93ee..6f69483 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -677,6 +677,8 @@
     <dimen name="keyguard_clock_top_margin">36dp</dimen>
     <!-- The margin between top of clock and bottom of lock icon. -->
     <dimen name="keyguard_clock_lock_margin">16dp</dimen>
+    <!-- The amount to shift the clocks during a small/large transition -->
+    <dimen name="keyguard_clock_switch_y_shift">10dp</dimen>
 
     <item name="scrim_behind_alpha" format="float" type="dimen">0.62</item>
 
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 5435a15..0687d06 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -2773,6 +2773,14 @@
     <string name="basic_status" translatable="false">Open conversation</string>
     <!-- Status for conversation without interaction data [CHAR LIMIT=120] -->
     <string name="select_conversation_text" translatable="false">Select one conversation to show in your widget:</string>
+    <!-- Timestamp for notification with exact time [CHAR LIMIT=120] -->
+    <string name="timestamp" translatable="false"><xliff:g id="duration" example="5 hours">%1$s</xliff:g> ago</string>
+    <!-- Timestamp for notification when less than a certain time window [CHAR LIMIT=120] -->
+    <string name="less_than_timestamp" translatable="false">Less than <xliff:g id="duration" example="5 hours">%1$s</xliff:g> ago</string>
+    <!-- Timestamp for notification when over a certain time window [CHAR LIMIT=120] -->
+    <string name="over_timestamp" translatable="false">Over <xliff:g id="duration" example="1 week">%1$s</xliff:g> ago</string>
+    <!-- Status text for a birthday today [CHAR LIMIT=120] -->
+    <string name="birthday_status" translatable="false">Today is their birthday!</string>
 
     <!-- Title to display in a notification when ACTION_BATTERY_CHANGED.EXTRA_PRESENT field is false
     [CHAR LIMIT=NONE] -->
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java
index ab7ba8a..323449a 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java
@@ -1,6 +1,8 @@
 package com.android.keyguard;
 
 import android.animation.Animator;
+import android.animation.AnimatorSet;
+import android.animation.ObjectAnimator;
 import android.animation.ValueAnimator;
 import android.content.Context;
 import android.graphics.Paint;
@@ -48,6 +50,9 @@
      */
     private static final float TO_BOLD_TRANSITION_FRACTION = 0.7f;
 
+    private static final long CLOCK_OUT_MILLIS = 150;
+    private static final long CLOCK_IN_MILLIS = 200;
+
     /**
      * Layout transition that scales the default clock face.
      */
@@ -112,6 +117,7 @@
     private int[] mColorPalette;
 
     private int mLockScreenMode = KeyguardUpdateMonitor.LOCK_SCREEN_MODE_NORMAL;
+    private int mClockSwitchYAmount;
 
     public KeyguardClockSwitch(Context context, AttributeSet attrs) {
         super(context, attrs);
@@ -131,6 +137,17 @@
     }
 
     /**
+     * Apply dp changes on font/scale change
+     */
+    public void onDensityOrFontScaleChanged() {
+        setTextSize(TypedValue.COMPLEX_UNIT_PX, mContext.getResources()
+                .getDimensionPixelSize(R.dimen.widget_big_font_size));
+
+        mClockSwitchYAmount = mContext.getResources().getDimensionPixelSize(
+                R.dimen.keyguard_clock_switch_y_shift);
+    }
+
+    /**
      * Returns if this view is presenting a custom clock, or the default implementation.
      */
     public boolean hasCustomClock() {
@@ -181,6 +198,8 @@
         mNewLockscreenLargeClockFrame = findViewById(R.id.new_lockscreen_clock_view_large);
         mSmallClockFrame = findViewById(R.id.clock_view);
         mKeyguardStatusArea = findViewById(R.id.keyguard_status_area);
+
+        onDensityOrFontScaleChanged();
     }
 
     void setClockPlugin(ClockPlugin plugin, int statusBarState) {
@@ -296,31 +315,43 @@
         mClockViewBold.setFormat24Hour(format);
     }
 
-    private void updateClockLayout(boolean useLargeClock) {
+    private void animateClockChange(boolean useLargeClock) {
         if (mLockScreenMode != KeyguardUpdateMonitor.LOCK_SCREEN_MODE_LAYOUT_1) return;
 
-        Fade fadeIn = new Fade();
-        fadeIn.setDuration(KeyguardSliceView.DEFAULT_ANIM_DURATION);
-        fadeIn.setInterpolator(Interpolators.LINEAR_OUT_SLOW_IN);
-
-        Fade fadeOut = new Fade();
-        fadeOut.setDuration(KeyguardSliceView.DEFAULT_ANIM_DURATION / 2);
-        fadeOut.setInterpolator(Interpolators.FAST_OUT_LINEAR_IN);
-
+        View in, out;
+        int direction = 1;
         if (useLargeClock) {
-            TransitionManager.beginDelayedTransition(mNewLockscreenClockFrame, fadeOut);
-            TransitionManager.beginDelayedTransition(mNewLockscreenLargeClockFrame, fadeIn);
-
-            mNewLockscreenClockFrame.setVisibility(View.INVISIBLE);
-            addView(mNewLockscreenLargeClockFrame);
-            mNewLockscreenLargeClockFrame.setVisibility(View.VISIBLE);
+            out = mNewLockscreenClockFrame;
+            in = mNewLockscreenLargeClockFrame;
+            addView(in);
+            direction = -1;
         } else {
-            TransitionManager.beginDelayedTransition(mNewLockscreenClockFrame, fadeIn);
-            TransitionManager.beginDelayedTransition(mNewLockscreenLargeClockFrame, fadeOut);
+            in = mNewLockscreenClockFrame;
+            out = mNewLockscreenLargeClockFrame;
 
-            removeView(mNewLockscreenLargeClockFrame);
-            mNewLockscreenClockFrame.setVisibility(View.VISIBLE);
+            // Must remove in order for notifications to appear in the proper place
+            removeView(out);
         }
+
+        AnimatorSet outAnim = new AnimatorSet();
+        outAnim.setDuration(CLOCK_OUT_MILLIS);
+        outAnim.setInterpolator(Interpolators.FAST_OUT_LINEAR_IN);
+        outAnim.playTogether(
+                ObjectAnimator.ofFloat(out, View.ALPHA, 0f),
+                ObjectAnimator.ofFloat(out, View.TRANSLATION_Y, 0,
+                        direction * -mClockSwitchYAmount));
+
+        in.setAlpha(0);
+        in.setVisibility(View.VISIBLE);
+        AnimatorSet inAnim = new AnimatorSet();
+        inAnim.setDuration(CLOCK_IN_MILLIS);
+        inAnim.setInterpolator(Interpolators.LINEAR_OUT_SLOW_IN);
+        inAnim.playTogether(ObjectAnimator.ofFloat(in, View.ALPHA, 1f),
+                ObjectAnimator.ofFloat(in, View.TRANSLATION_Y, direction * mClockSwitchYAmount, 0));
+        inAnim.setStartDelay(CLOCK_OUT_MILLIS / 2);
+
+        inAnim.start();
+        outAnim.start();
     }
 
     /**
@@ -343,7 +374,8 @@
         if (hasVisibleNotifications == mHasVisibleNotifications) {
             return;
         }
-        updateClockLayout(!hasVisibleNotifications);
+
+        animateClockChange(!hasVisibleNotifications);
 
         mHasVisibleNotifications = hasVisibleNotifications;
         if (mDarkAmount == 0f && mBigClockContainer != null) {
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java
index 4d6e8a9..e0de180 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java
@@ -21,7 +21,6 @@
 import android.content.res.Resources;
 import android.provider.Settings;
 import android.text.format.DateFormat;
-import android.util.TypedValue;
 import android.view.View;
 import android.view.ViewGroup;
 import android.widget.FrameLayout;
@@ -146,11 +145,10 @@
     }
 
     /**
-     * Updates clock's text
+     * Apply dp changes on font/scale change
      */
     public void onDensityOrFontScaleChanged() {
-        mView.setTextSize(TypedValue.COMPLEX_UNIT_PX,
-                mResources.getDimensionPixelSize(R.dimen.widget_big_font_size));
+        mView.onDensityOrFontScaleChanged();
     }
 
     /**
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
index 2071cfa..b43496c 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -1901,6 +1901,15 @@
     }
 
     /**
+     * Whether to show the lock icon on lock screen and bouncer. This depends on the enrolled
+     * biometrics to the device.
+     */
+    public boolean shouldShowLockIcon() {
+        return isFaceAuthEnabledForUser(KeyguardUpdateMonitor.getCurrentUser())
+                && !isUdfpsEnrolled();
+    }
+
+    /**
      * @return true if there's at least one udfps enrolled
      */
     public boolean isUdfpsEnrolled() {
diff --git a/packages/SystemUI/src/com/android/systemui/ForegroundServiceLifetimeExtender.java b/packages/SystemUI/src/com/android/systemui/ForegroundServiceLifetimeExtender.java
new file mode 100644
index 0000000..c0f8cae
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/ForegroundServiceLifetimeExtender.java
@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui;
+
+import android.annotation.NonNull;
+import android.app.Notification;
+import android.os.Handler;
+import android.os.Looper;
+import android.util.ArraySet;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.systemui.statusbar.NotificationInteractionTracker;
+import com.android.systemui.statusbar.NotificationLifetimeExtender;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.util.time.SystemClock;
+
+import javax.inject.Inject;
+
+/**
+ * Extends the lifetime of foreground notification services such that they show for at least
+ * five seconds
+ */
+public class ForegroundServiceLifetimeExtender implements NotificationLifetimeExtender {
+
+    private static final String TAG = "FGSLifetimeExtender";
+    @VisibleForTesting
+    static final int MIN_FGS_TIME_MS = 5000;
+
+    private NotificationSafeToRemoveCallback mNotificationSafeToRemoveCallback;
+    private ArraySet<NotificationEntry> mManagedEntries = new ArraySet<>();
+    private Handler mHandler = new Handler(Looper.getMainLooper());
+    private final SystemClock mSystemClock;
+    private final NotificationInteractionTracker mInteractionTracker;
+
+    @Inject
+    public ForegroundServiceLifetimeExtender(
+            NotificationInteractionTracker interactionTracker,
+            SystemClock systemClock) {
+        mSystemClock = systemClock;
+        mInteractionTracker = interactionTracker;
+    }
+
+    @Override
+    public void setCallback(@NonNull NotificationSafeToRemoveCallback callback) {
+        mNotificationSafeToRemoveCallback = callback;
+    }
+
+    @Override
+    public boolean shouldExtendLifetime(@NonNull NotificationEntry entry) {
+        if ((entry.getSbn().getNotification().flags
+                & Notification.FLAG_FOREGROUND_SERVICE) == 0) {
+            return false;
+        }
+
+        // Entry has triggered a HUN or some other interruption, therefore it has been seen and the
+        // interrupter might be retaining it anyway.
+        if (entry.hasInterrupted()) {
+            return false;
+        }
+
+        boolean hasInteracted = mInteractionTracker.hasUserInteractedWith(entry.getKey());
+        long aliveTime = mSystemClock.uptimeMillis() - entry.getCreationTime();
+        return aliveTime < MIN_FGS_TIME_MS && !hasInteracted;
+    }
+
+    @Override
+    public boolean shouldExtendLifetimeForPendingNotification(
+            @NonNull NotificationEntry entry) {
+        return shouldExtendLifetime(entry);
+    }
+
+    @Override
+    public void setShouldManageLifetime(
+            @NonNull NotificationEntry entry, boolean shouldManage) {
+        if (!shouldManage) {
+            mManagedEntries.remove(entry);
+            return;
+        }
+
+        mManagedEntries.add(entry);
+
+        Runnable r = () -> {
+            if (mManagedEntries.contains(entry)) {
+                mManagedEntries.remove(entry);
+                if (mNotificationSafeToRemoveCallback != null) {
+                    mNotificationSafeToRemoveCallback.onSafeToRemove(entry.getKey());
+                }
+            }
+        };
+        long delayAmt = MIN_FGS_TIME_MS
+                - (mSystemClock.uptimeMillis() - entry.getCreationTime());
+        mHandler.postDelayed(r, delayAmt);
+    }
+}
+
diff --git a/packages/SystemUI/src/com/android/systemui/ForegroundServiceNotificationListener.java b/packages/SystemUI/src/com/android/systemui/ForegroundServiceNotificationListener.java
index 04e26d3..d6cb114 100644
--- a/packages/SystemUI/src/com/android/systemui/ForegroundServiceNotificationListener.java
+++ b/packages/SystemUI/src/com/android/systemui/ForegroundServiceNotificationListener.java
@@ -50,6 +50,7 @@
             ForegroundServiceController foregroundServiceController,
             NotificationEntryManager notificationEntryManager,
             NotifPipeline notifPipeline,
+            ForegroundServiceLifetimeExtender fgsLifetimeExtender,
             SystemClock systemClock) {
         mContext = context;
         mForegroundServiceController = foregroundServiceController;
@@ -77,6 +78,7 @@
                 removeNotification(entry.getSbn());
             }
         });
+        mEntryManager.addNotificationLifetimeExtender(fgsLifetimeExtender);
 
         notifPipeline.addCollectionListener(new NotifCollectionListener() {
             @Override
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
index a15a5aa..65a6f29 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
@@ -135,7 +135,7 @@
     @SuppressLint("ClickableViewAccessibility")
     private final UdfpsView.OnTouchListener mOnTouchListener = (v, event) -> {
         UdfpsView view = (UdfpsView) v;
-        final boolean isFingerDown = view.isScrimShowing();
+        final boolean isFingerDown = view.isShowScrimAndDot();
         switch (event.getAction()) {
             case MotionEvent.ACTION_DOWN:
             case MotionEvent.ACTION_MOVE:
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsView.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsView.java
index 5a61379..663a0da 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsView.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsView.java
@@ -27,6 +27,7 @@
 import android.graphics.Paint;
 import android.graphics.Rect;
 import android.graphics.RectF;
+import android.graphics.drawable.Drawable;
 import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
 import android.text.TextUtils;
 import android.util.AttributeSet;
@@ -70,6 +71,7 @@
     // mInsetsListener to restrict the touchable region and allow the touches outside of the sensor
     // to propagate to the rest of the UI.
     @NonNull private final ViewTreeObserver.OnComputeInternalInsetsListener mInsetsListener;
+    @NonNull private final Drawable mFingerprintDrawable;
 
     // Used to obtain the sensor location.
     @NonNull private FingerprintSensorPropertiesInternal mSensorProps;
@@ -79,7 +81,7 @@
     private float mBurnInOffsetX;
     private float mBurnInOffsetY;
 
-    private boolean mIsScrimShowing;
+    private boolean mShowScrimAndDot;
     private boolean mIsHbmSupported;
     @Nullable private String mDebugMessage;
 
@@ -112,15 +114,16 @@
         mSensorPaint = new Paint(0 /* flags */);
         mSensorPaint.setAntiAlias(true);
         mSensorPaint.setColor(Color.WHITE);
-        mSensorPaint.setStyle(Paint.Style.STROKE);
-        mSensorPaint.setStrokeWidth(SENSOR_OUTLINE_WIDTH);
         mSensorPaint.setShadowLayer(SENSOR_SHADOW_RADIUS, 0, 0, Color.BLACK);
+        mSensorPaint.setStyle(Paint.Style.FILL);
 
         mDebugTextPaint = new Paint();
         mDebugTextPaint.setAntiAlias(true);
         mDebugTextPaint.setColor(Color.BLUE);
         mDebugTextPaint.setTextSize(DEBUG_TEXT_SIZE_PX);
 
+        mFingerprintDrawable = getResources().getDrawable(R.drawable.ic_fingerprint, null);
+
         mTouchableRegion = new Rect();
         // When the device is rotated, it's important that mTouchableRegion is updated before
         // this listener is called. This listener is usually called shortly after onLayout.
@@ -130,7 +133,7 @@
             internalInsetsInfo.touchableRegion.set(mTouchableRegion);
         };
 
-        mIsScrimShowing = false;
+        mShowScrimAndDot = false;
     }
 
     void setSensorProperties(@NonNull FingerprintSensorPropertiesInternal properties) {
@@ -181,6 +184,13 @@
             default:
                 // Do nothing to stay in portrait mode.
         }
+
+        int margin =  (int) (mSensorRect.bottom - mSensorRect.top) / 5;
+        mFingerprintDrawable.setBounds(
+                (int) mSensorRect.left + margin,
+                (int) mSensorRect.top + margin,
+                (int) mSensorRect.right - margin,
+                (int) mSensorRect.bottom - margin);
     }
 
     @Override
@@ -198,6 +208,8 @@
         // is finished, mTouchableRegion will be used by mInsetsListener to compute the touch
         // insets.
         mSensorRect.roundOut(mTouchableRegion);
+
+
     }
 
     @Override
@@ -218,7 +230,7 @@
     protected void onDraw(Canvas canvas) {
         super.onDraw(canvas);
 
-        if (mIsScrimShowing && mIsHbmSupported) {
+        if (mShowScrimAndDot && mIsHbmSupported) {
             // Only draw the scrim if HBM is supported.
             canvas.drawRect(mScrimRect, mScrimPaint);
         }
@@ -229,7 +241,15 @@
         if (!TextUtils.isEmpty(mDebugMessage)) {
             canvas.drawText(mDebugMessage, 0, 160, mDebugTextPaint);
         }
-        canvas.drawOval(mSensorRect, mSensorPaint);
+
+        if (mShowScrimAndDot) {
+            // draw dot (white circle)
+            canvas.drawOval(mSensorRect, mSensorPaint);
+        } else {
+            // draw fingerprint icon
+            mFingerprintDrawable.draw(canvas);
+        }
+
         canvas.restore();
     }
 
@@ -264,19 +284,17 @@
         mScrimPaint.setAlpha(alpha);
     }
 
-    boolean isScrimShowing() {
-        return mIsScrimShowing;
+    boolean isShowScrimAndDot() {
+        return mShowScrimAndDot;
     }
 
     void showScrimAndDot() {
-        mIsScrimShowing = true;
-        mSensorPaint.setStyle(Paint.Style.FILL);
+        mShowScrimAndDot = true;
         invalidate();
     }
 
     void hideScrimAndDot() {
-        mIsScrimShowing = false;
-        mSensorPaint.setStyle(Paint.Style.STROKE);
+        mShowScrimAndDot = false;
         invalidate();
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/FaceAuthScreenBrightnessController.kt b/packages/SystemUI/src/com/android/systemui/keyguard/FaceAuthScreenBrightnessController.kt
index a7d17e1..b4137fa 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/FaceAuthScreenBrightnessController.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/FaceAuthScreenBrightnessController.kt
@@ -64,7 +64,8 @@
     private val globalSettings: GlobalSettings,
     private val systemSettings: SystemSettings,
     private val mainHandler: Handler,
-    private val dumpManager: DumpManager
+    private val dumpManager: DumpManager,
+    private val enabled: Boolean
 ) : Dumpable {
 
     private var userDefinedBrightness: Float = 1f
@@ -86,7 +87,7 @@
                 return
             }
             // TODO enable only when receiving a low-light error
-            overridingBrightness = running
+            overridingBrightness = if (enabled) running else false
         }
     }
     private lateinit var whiteOverlay: View
@@ -188,6 +189,7 @@
             println("brightnessAnimationDuration: $brightnessAnimationDuration")
             println("maxScreenBrightness: $maxScreenBrightness")
             println("userDefinedBrightness: $userDefinedBrightness")
+            println("enabled: $enabled")
         }
     }
 }
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java b/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java
index d7b5eea..626abfc 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java
@@ -142,8 +142,9 @@
             return Optional.empty();
         }
 
+        // currently disabled (doesn't ramp up brightness or use scrim) see b/175918367
         return Optional.of(new FaceAuthScreenBrightnessController(
                 notificationShadeWindowController, keyguardUpdateMonitor, resources,
-                globalSetting, systemSettings, handler, dumpManager));
+                globalSetting, systemSettings, handler, dumpManager, false));
     }
 }
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 9e25389..4f85192 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java
@@ -94,7 +94,8 @@
     public MediaOutputController(@NonNull Context context, String packageName,
             boolean aboveStatusbar, MediaSessionManager mediaSessionManager, LocalBluetoothManager
             lbm, ShadeController shadeController, ActivityStarter starter,
-            NotificationEntryManager notificationEntryManager, UiEventLogger uiEventLogger) {
+            NotificationEntryManager notificationEntryManager, UiEventLogger uiEventLogger,
+            MediaRouter2Manager routerManager) {
         mContext = context;
         mPackageName = packageName;
         mMediaSessionManager = mediaSessionManager;
@@ -106,7 +107,7 @@
         mLocalMediaManager = new LocalMediaManager(mContext, lbm, imm, packageName);
         mMetricLogger = new MediaOutputMetricLogger(mContext, mPackageName);
         mUiEventLogger = uiEventLogger;
-        mRouterManager = MediaRouter2Manager.getInstance(mContext);
+        mRouterManager = routerManager;
     }
 
     void start(@NonNull Callback cb) {
@@ -137,7 +138,9 @@
         mLocalMediaManager.stopScan();
         mLocalMediaManager.registerCallback(this);
         mLocalMediaManager.startScan();
-        mRouterManager.startScan();
+        if (mRouterManager != null) {
+            mRouterManager.startScan();
+        }
     }
 
     void stop() {
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialogFactory.kt b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialogFactory.kt
index 0f340a5..e1a504c 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialogFactory.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialogFactory.kt
@@ -18,6 +18,7 @@
 
 import android.content.Context
 import android.media.session.MediaSessionManager
+import android.media.MediaRouter2Manager
 import com.android.internal.logging.UiEventLogger
 import com.android.settingslib.bluetooth.LocalBluetoothManager
 import com.android.systemui.plugins.ActivityStarter
@@ -35,7 +36,8 @@
     private val shadeController: ShadeController,
     private val starter: ActivityStarter,
     private val notificationEntryManager: NotificationEntryManager,
-    private val uiEventLogger: UiEventLogger
+    private val uiEventLogger: UiEventLogger,
+    private val routerManager: MediaRouter2Manager
 ) {
     companion object {
         var mediaOutputDialog: MediaOutputDialog? = null
@@ -46,7 +48,7 @@
         mediaOutputDialog?.dismiss()
         mediaOutputDialog = MediaOutputController(context, packageName, aboveStatusBar,
                 mediaSessionManager, lbm, shadeController, starter, notificationEntryManager,
-                uiEventLogger).run {
+                uiEventLogger, routerManager).run {
             MediaOutputDialog(context, aboveStatusBar, this, uiEventLogger)
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceActivity.java b/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceActivity.java
index 62de939..2ad12b9 100644
--- a/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceActivity.java
@@ -44,7 +44,6 @@
 import com.android.systemui.people.widget.PeopleSpaceWidgetProvider;
 
 import java.util.List;
-import java.util.Map;
 
 /**
  * Shows the user their tiles for their priority People (go/live-status).
@@ -96,13 +95,12 @@
      */
     private void setTileViewsWithPriorityConversations() {
         try {
-            List<Map.Entry<Long, PeopleSpaceTile>> tiles = PeopleSpaceUtils.getTiles(
+            List<PeopleSpaceTile> tiles = PeopleSpaceUtils.getTiles(
                     mContext, mNotificationManager, mPeopleManager, mLauncherApps);
-            for (Map.Entry<Long, PeopleSpaceTile> entry : tiles) {
-                PeopleSpaceTile tile = entry.getValue();
+            for (PeopleSpaceTile tile : tiles) {
                 PeopleSpaceTileView tileView = new PeopleSpaceTileView(mContext, mPeopleSpaceLayout,
                         tile.getId());
-                setTileView(tileView, tile, entry.getKey());
+                setTileView(tileView, tile);
             }
         } catch (Exception e) {
             Log.e(TAG, "Couldn't retrieve conversations", e);
@@ -110,12 +108,12 @@
     }
 
     /** Sets {@code tileView} with the data in {@code conversation}. */
-    private void setTileView(PeopleSpaceTileView tileView, PeopleSpaceTile tile,
-            long lastInteraction) {
+    private void setTileView(PeopleSpaceTileView tileView, PeopleSpaceTile tile) {
         try {
             String pkg = tile.getPackageName();
             String status =
-                    PeopleSpaceUtils.getLastInteractionString(mContext, lastInteraction);
+                    PeopleSpaceUtils.getLastInteractionString(mContext,
+                            tile.getLastInteractionTimestamp(), true);
             tileView.setStatus(status);
 
             tileView.setName(tile.getUserName().toString());
diff --git a/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceUtils.java b/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceUtils.java
index 7fc24f6..f1a57bf 100644
--- a/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceUtils.java
+++ b/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceUtils.java
@@ -29,6 +29,8 @@
 import android.content.Intent;
 import android.content.SharedPreferences;
 import android.content.pm.LauncherApps;
+import android.database.Cursor;
+import android.database.SQLException;
 import android.graphics.Bitmap;
 import android.graphics.Canvas;
 import android.graphics.drawable.BitmapDrawable;
@@ -41,7 +43,7 @@
 import android.os.Parcelable;
 import android.os.ServiceManager;
 import android.os.UserHandle;
-import android.preference.PreferenceManager;
+import android.provider.ContactsContract;
 import android.provider.Settings;
 import android.service.notification.ConversationChannelWrapper;
 import android.service.notification.StatusBarNotification;
@@ -49,21 +51,30 @@
 import android.view.View;
 import android.widget.RemoteViews;
 
+import androidx.preference.PreferenceManager;
+
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.logging.UiEvent;
 import com.android.internal.logging.UiEventLogger;
 import com.android.internal.util.ArrayUtils;
+import com.android.settingslib.utils.ThreadUtils;
 import com.android.systemui.R;
 import com.android.systemui.people.widget.LaunchConversationActivity;
 import com.android.systemui.people.widget.PeopleSpaceWidgetProvider;
 
+import java.text.SimpleDateFormat;
 import java.time.Duration;
+import java.util.ArrayList;
 import java.util.Collections;
 import java.util.Comparator;
+import java.util.Date;
+import java.util.HashMap;
 import java.util.List;
 import java.util.Locale;
 import java.util.Map;
 import java.util.Optional;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
 import java.util.stream.Collectors;
 import java.util.stream.Stream;
 
@@ -77,6 +88,11 @@
     private static final int ONE_DAY = 1;
     public static final String OPTIONS_PEOPLE_SPACE_TILE = "options_people_space_tile";
 
+    private static final Pattern DOUBLE_EXCLAMATION_PATTERN = Pattern.compile("[!][!]+");
+    private static final Pattern DOUBLE_QUESTION_PATTERN = Pattern.compile("[?][?]+");
+    private static final Pattern ANY_DOUBLE_MARK_PATTERN = Pattern.compile("[!?][!?]+");
+    private static final Pattern MIXED_MARK_PATTERN = Pattern.compile("![?].*|.*[?]!");
+
     /** Represents whether {@link StatusBarNotification} was posted or removed. */
     public enum NotificationAction {
         POSTED,
@@ -107,7 +123,7 @@
     }
 
     /** Returns a list of map entries corresponding to user's conversations. */
-    public static List<Map.Entry<Long, PeopleSpaceTile>> getTiles(
+    public static List<PeopleSpaceTile> getTiles(
             Context context, INotificationManager notificationManager, IPeopleManager peopleManager,
             LauncherApps launcherApps)
             throws Exception {
@@ -115,70 +131,72 @@
                 Settings.Global.PEOPLE_SPACE_CONVERSATION_TYPE, 0) == 1;
         List<ConversationChannelWrapper> conversations = notificationManager.getConversations(
                 true).getList();
-        List<Map.Entry<Long, PeopleSpaceTile>> tiles = getSortedTiles(peopleManager,
-                conversations.stream().map(c ->
-                        new PeopleSpaceTile.Builder(c.getShortcutInfo(), launcherApps).build()));
+        List<PeopleSpaceTile> tiles = getSortedTiles(peopleManager,
+                conversations.stream().filter(c -> c.getShortcutInfo() != null).map(
+                        c -> new PeopleSpaceTile.Builder(c.getShortcutInfo(),
+                                launcherApps).build()));
         if (!showOnlyPriority) {
             if (DEBUG) Log.d(TAG, "Add recent conversations");
             List<ConversationChannel> recentConversations =
                     peopleManager.getRecentConversations().getList();
-            List<Map.Entry<Long, PeopleSpaceTile>> recentTiles =
-                    getSortedTiles(peopleManager, recentConversations.stream().map(c ->
-                            new PeopleSpaceTile
-                                    .Builder(c.getShortcutInfo(), launcherApps)
-                                    .build()));
+            List<PeopleSpaceTile> recentTiles =
+                    getSortedTiles(peopleManager,
+                            recentConversations
+                                    .stream()
+                                    .filter(
+                                            c -> c.getShortcutInfo() != null)
+                                    .map(
+                                            c -> new PeopleSpaceTile.Builder(c.getShortcutInfo(),
+                                                    launcherApps).build()));
             tiles.addAll(recentTiles);
         }
         return tiles;
     }
 
-    /** Updates {@code appWidgetIds} with their associated conversation stored. */
+    /**
+     * Updates {@code appWidgetIds} with their associated conversation stored, handling a
+     * notification being posted or removed.
+     */
     public static void updateSingleConversationWidgets(Context context, int[] appWidgetIds,
             AppWidgetManager appWidgetManager, INotificationManager notificationManager) {
         IPeopleManager peopleManager = IPeopleManager.Stub.asInterface(
                 ServiceManager.getService(Context.PEOPLE_SERVICE));
         LauncherApps launcherApps = context.getSystemService(LauncherApps.class);
         SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(context);
+        Map<Integer, PeopleSpaceTile> widgetIdToTile = new HashMap<>();
         try {
-            List<Map.Entry<Long, PeopleSpaceTile>> tiles =
+            List<PeopleSpaceTile> tiles =
                     PeopleSpaceUtils.getTiles(context, notificationManager,
                             peopleManager, launcherApps);
-
             for (int appWidgetId : appWidgetIds) {
                 String shortcutId = sp.getString(String.valueOf(appWidgetId), null);
                 if (DEBUG) {
-                    Log.d(TAG, "Set widget: " + appWidgetId + " with shortcut ID: " + shortcutId);
+                    Log.d(TAG, "Widget ID: " + appWidgetId + " Shortcut ID: " + shortcutId);
                 }
-                Optional<Map.Entry<Long, PeopleSpaceTile>> entry = tiles.stream().filter(
-                        e -> e.getValue().getId().equals(shortcutId)).findFirst();
+
+                Optional<PeopleSpaceTile> entry = tiles.stream().filter(
+                        e -> e.getId().equals(shortcutId)).findFirst();
+
                 if (!entry.isPresent() || shortcutId == null) {
                     if (DEBUG) Log.d(TAG, "Matching conversation not found for shortcut ID");
                     //TODO: Delete app widget id when crash is fixed (b/175486868)
                     continue;
                 }
-                PeopleSpaceTile tile =
-                        augmentTileFromStorage(entry.get().getValue(), appWidgetManager,
-                                appWidgetId);
-
-                RemoteViews views = createRemoteViews(context, tile, entry.get().getKey(),
+                // Augment current tile based on stored fields.
+                PeopleSpaceTile tile = augmentTileFromStorage(entry.get(), appWidgetManager,
                         appWidgetId);
 
+                RemoteViews views = createRemoteViews(context, tile, appWidgetId);
+
                 // Tell the AppWidgetManager to perform an update on the current app widget.
                 appWidgetManager.updateAppWidget(appWidgetId, views);
+
+                widgetIdToTile.put(appWidgetId, tile);
             }
         } catch (Exception e) {
-            Log.e(TAG, "Exception updating single conversation widgets: " + e);
+            Log.e(TAG, "Failed to retrieve conversations to set tiles: " + e);
         }
-    }
-
-    /** Returns a list sorted by ascending last interaction time from {@code stream}. */
-    private static List<Map.Entry<Long, PeopleSpaceTile>> getSortedTiles(
-            IPeopleManager peopleManager, Stream<PeopleSpaceTile> stream) {
-        return stream
-                .filter(c -> shouldKeepConversation(c))
-                .map(c -> Map.entry(getLastInteraction(peopleManager, c), c))
-                .sorted((c1, c2) -> (c2.getKey().compareTo(c1.getKey())))
-                .collect(Collectors.toList());
+        getBirthdaysOnBackgroundThread(context, appWidgetManager, widgetIdToTile, appWidgetIds);
     }
 
     /** Augment {@link PeopleSpaceTile} with fields from stored tile. */
@@ -191,6 +209,7 @@
             return tile;
         }
         return tile.toBuilder()
+                .setStatusText(storedTile.getStatusText())
                 .setNotificationKey(storedTile.getNotificationKey())
                 .setNotificationContent(storedTile.getNotificationContent())
                 .setNotificationDataUri(storedTile.getNotificationDataUri())
@@ -227,37 +246,67 @@
                     .setNotificationDataUri(null)
                     .build();
         }
+        updateAppWidgetOptions(appWidgetManager, appWidgetId, storedTile);
+    }
+
+    private static void updateAppWidgetOptions(AppWidgetManager appWidgetManager, int appWidgetId,
+            PeopleSpaceTile tile) {
         Bundle newOptions = new Bundle();
-        newOptions.putParcelable(OPTIONS_PEOPLE_SPACE_TILE, storedTile);
+        newOptions.putParcelable(OPTIONS_PEOPLE_SPACE_TILE, tile);
         appWidgetManager.updateAppWidgetOptions(appWidgetId, newOptions);
     }
 
-    private static RemoteViews createRemoteViews(Context context, PeopleSpaceTile tile,
-            long lastInteraction, int appWidgetId) throws Exception {
-        // TODO: If key is null or if text and data uri are null.
-        if (tile.getNotificationKey() == null) {
-            return createLastInteractionRemoteViews(context, tile, lastInteraction, appWidgetId);
+    /** Creates a {@link RemoteViews} for {@code tile}. */
+    private static RemoteViews createRemoteViews(Context context,
+            PeopleSpaceTile tile, int appWidgetId) {
+        RemoteViews views;
+        if (tile.getNotificationKey() != null) {
+            views = createNotificationRemoteViews(context, tile);
+        } else if (tile.getStatusText() != null) {
+            views = createStatusRemoteViews(context, tile);
+        } else {
+            views = createLastInteractionRemoteViews(context, tile);
         }
-        return createNotificationRemoteViews(context, tile, lastInteraction, appWidgetId);
+        return setCommonRemoteViewsFields(context, views, tile, appWidgetId);
     }
 
-    private static RemoteViews createLastInteractionRemoteViews(Context context,
-            PeopleSpaceTile tile, long lastInteraction, int appWidgetId)
-            throws Exception {
-        RemoteViews views = new RemoteViews(
-                    context.getPackageName(), R.layout.people_space_large_avatar_tile);
-        String status = PeopleSpaceUtils.getLastInteractionString(
-                context, lastInteraction);
-        views.setTextViewText(R.id.status, status);
+    private static RemoteViews setCommonRemoteViewsFields(Context context, RemoteViews views,
+            PeopleSpaceTile tile, int appWidgetId) {
+        try {
+            views.setTextViewText(R.id.name, tile.getUserName().toString());
+            views.setImageViewBitmap(
+                    R.id.package_icon,
+                    PeopleSpaceUtils.convertDrawableToBitmap(
+                            context.getPackageManager().getApplicationIcon(
+                                    tile.getPackageName())
+                    )
+            );
+            views.setImageViewIcon(R.id.person_icon, tile.getUserIcon());
 
-        views = setCommonRemoteViewsFields(context, views, tile, appWidgetId);
-        return views;
+            Intent activityIntent = new Intent(context, LaunchConversationActivity.class);
+            activityIntent.addFlags(
+                    Intent.FLAG_ACTIVITY_NEW_TASK
+                            | Intent.FLAG_ACTIVITY_CLEAR_TASK
+                            | Intent.FLAG_ACTIVITY_NO_HISTORY
+                            | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
+            activityIntent.putExtra(PeopleSpaceWidgetProvider.EXTRA_TILE_ID, tile.getId());
+            activityIntent.putExtra(
+                    PeopleSpaceWidgetProvider.EXTRA_PACKAGE_NAME, tile.getPackageName());
+            activityIntent.putExtra(PeopleSpaceWidgetProvider.EXTRA_UID, tile.getUid());
+            views.setOnClickPendingIntent(R.id.item, PendingIntent.getActivity(
+                    context,
+                    appWidgetId,
+                    activityIntent,
+                    PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_MUTABLE));
+            return views;
+        } catch (Exception e) {
+            Log.e(TAG, "Failed to set common fields: " + e);
+        }
+        return null;
     }
 
     private static RemoteViews createNotificationRemoteViews(Context context,
-            PeopleSpaceTile tile, long lastInteraction, int appWidgetId)
-            throws Exception {
-
+            PeopleSpaceTile tile) {
         RemoteViews views = new RemoteViews(
                 context.getPackageName(), R.layout.people_space_small_avatar_tile);
         Uri image = tile.getNotificationDataUri();
@@ -267,46 +316,85 @@
             views.setViewVisibility(R.id.image, View.VISIBLE);
             views.setViewVisibility(R.id.content, View.GONE);
         } else {
-            views.setTextViewText(R.id.content, tile.getNotificationContent());
+            CharSequence content = tile.getNotificationContent();
+            views = setPunctuationRemoteViewsFields(views, content);
+            views.setTextViewText(R.id.content, content);
             views.setViewVisibility(R.id.content, View.VISIBLE);
             views.setViewVisibility(R.id.image, View.GONE);
         }
-
-        views = setCommonRemoteViewsFields(context, views, tile, appWidgetId);
+        views.setTextViewText(R.id.time, PeopleSpaceUtils.getLastInteractionString(
+                context, tile.getLastInteractionTimestamp(), false));
         return views;
     }
 
-    private static RemoteViews setCommonRemoteViewsFields(
-            Context context, RemoteViews views, PeopleSpaceTile tile, int appWidgetId)
-            throws Exception {
-        views.setTextViewText(R.id.name, tile.getUserName().toString());
-        views.setImageViewBitmap(
-                R.id.package_icon,
-                PeopleSpaceUtils.convertDrawableToBitmap(
-                        context.getPackageManager().getApplicationIcon(tile.getPackageName())
-                )
-        );
-        views.setImageViewIcon(R.id.person_icon, tile.getUserIcon());
-
-        Intent activityIntent = new Intent(context, LaunchConversationActivity.class);
-        activityIntent.addFlags(
-                Intent.FLAG_ACTIVITY_NEW_TASK
-                        | Intent.FLAG_ACTIVITY_CLEAR_TASK
-                        | Intent.FLAG_ACTIVITY_NO_HISTORY
-                        | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
-        activityIntent.putExtra(PeopleSpaceWidgetProvider.EXTRA_TILE_ID, tile.getId());
-        activityIntent.putExtra(
-                PeopleSpaceWidgetProvider.EXTRA_PACKAGE_NAME, tile.getPackageName());
-        activityIntent.putExtra(PeopleSpaceWidgetProvider.EXTRA_UID, tile.getUid());
-        views.setOnClickPendingIntent(R.id.item, PendingIntent.getActivity(
-                context,
-                appWidgetId,
-                activityIntent,
-                PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_MUTABLE));
+    private static RemoteViews createStatusRemoteViews(Context context,
+            PeopleSpaceTile tile) {
+        RemoteViews views = new RemoteViews(
+                context.getPackageName(), R.layout.people_space_large_avatar_tile);
+        views.setTextViewText(R.id.status, tile.getStatusText());
         return views;
     }
 
+    private static RemoteViews createLastInteractionRemoteViews(Context context,
+            PeopleSpaceTile tile) {
+        RemoteViews views = new RemoteViews(
+                context.getPackageName(), R.layout.people_space_large_avatar_tile);
+        String status = PeopleSpaceUtils.getLastInteractionString(
+                context, tile.getLastInteractionTimestamp(), true);
+        views.setTextViewText(R.id.status, status);
+        return views;
+    }
+
+    private static RemoteViews setPunctuationRemoteViewsFields(
+            RemoteViews views, CharSequence content) {
+        String punctuation = getBackgroundTextFromMessage(content.toString());
+        int visibility = View.GONE;
+        if (punctuation != null) {
+            visibility = View.VISIBLE;
+        }
+        views.setTextViewText(R.id.punctuation1, punctuation);
+        views.setTextViewText(R.id.punctuation2, punctuation);
+        views.setTextViewText(R.id.punctuation3, punctuation);
+        views.setTextViewText(R.id.punctuation4, punctuation);
+        views.setTextViewText(R.id.punctuation5, punctuation);
+        views.setTextViewText(R.id.punctuation6, punctuation);
+
+        views.setViewVisibility(R.id.punctuation1, visibility);
+        views.setViewVisibility(R.id.punctuation2, visibility);
+        views.setViewVisibility(R.id.punctuation3, visibility);
+        views.setViewVisibility(R.id.punctuation4, visibility);
+        views.setViewVisibility(R.id.punctuation5, visibility);
+        views.setViewVisibility(R.id.punctuation6, visibility);
+
+        return views;
+    }
+
+    /** Gets character for tile background decoration based on notification content. */
+    @VisibleForTesting
+    static String getBackgroundTextFromMessage(String message) {
+        if (!ANY_DOUBLE_MARK_PATTERN.matcher(message).find()) {
+            return null;
+        }
+        if (MIXED_MARK_PATTERN.matcher(message).find()) {
+            return "!?";
+        }
+        Matcher doubleQuestionMatcher = DOUBLE_QUESTION_PATTERN.matcher(message);
+        if (!doubleQuestionMatcher.find()) {
+            return "!";
+        }
+        Matcher doubleExclamationMatcher = DOUBLE_EXCLAMATION_PATTERN.matcher(message);
+        if (!doubleExclamationMatcher.find()) {
+            return "?";
+        }
+        // If we have both "!!" and "??", return the one that comes first.
+        if (doubleQuestionMatcher.start() < doubleExclamationMatcher.start()) {
+            return "?";
+        }
+        return "!";
+    }
+
     /** Gets the most recent {@link Notification.MessagingStyle.Message} from the notification. */
+    @VisibleForTesting
     public static Notification.MessagingStyle.Message getLastMessagingStyleMessage(
             StatusBarNotification sbn) {
         Notification notification = sbn.getNotification();
@@ -327,6 +415,18 @@
         return null;
     }
 
+    /** Returns a list sorted by ascending last interaction time from {@code stream}. */
+    private static List<PeopleSpaceTile> getSortedTiles(IPeopleManager peopleManager,
+            Stream<PeopleSpaceTile> stream) {
+        return stream
+                .filter(c -> shouldKeepConversation(c))
+                .map(c -> c.toBuilder().setLastInteractionTimestamp(
+                        getLastInteraction(peopleManager, c)).build())
+                .sorted((c1, c2) -> new Long(c2.getLastInteractionTimestamp()).compareTo(
+                        new Long(c1.getLastInteractionTimestamp())))
+                .collect(Collectors.toList());
+    }
+
     /** Returns the last interaction time with the user specified by {@code PeopleSpaceTile}. */
     private static Long getLastInteraction(IPeopleManager peopleManager,
             PeopleSpaceTile tile) {
@@ -369,7 +469,8 @@
     }
 
     /** Returns a readable status describing the {@code lastInteraction}. */
-    public static String getLastInteractionString(Context context, long lastInteraction) {
+    public static String getLastInteractionString(Context context, long lastInteraction,
+            boolean includeLastChatted) {
         if (lastInteraction == 0L) {
             Log.e(TAG, "Could not get valid last interaction");
             return context.getString(R.string.basic_status);
@@ -379,18 +480,25 @@
         MeasureFormat formatter = MeasureFormat.getInstance(Locale.getDefault(),
                 MeasureFormat.FormatWidth.WIDE);
         if (durationSinceLastInteraction.toHours() < MIN_HOUR) {
-            return context.getString(R.string.last_interaction_status_less_than,
+            return context.getString(includeLastChatted ? R.string.last_interaction_status_less_than
+                            : R.string.less_than_timestamp,
                     formatter.formatMeasures(new Measure(MIN_HOUR, MeasureUnit.HOUR)));
         } else if (durationSinceLastInteraction.toDays() < ONE_DAY) {
-            return context.getString(R.string.last_interaction_status, formatter.formatMeasures(
-                    new Measure(durationSinceLastInteraction.toHours(), MeasureUnit.HOUR)));
+            return context.getString(
+                    includeLastChatted ? R.string.last_interaction_status : R.string.timestamp,
+                    formatter.formatMeasures(
+                            new Measure(durationSinceLastInteraction.toHours(), MeasureUnit.HOUR)));
         } else if (durationSinceLastInteraction.toDays() < DAYS_IN_A_WEEK) {
-            return context.getString(R.string.last_interaction_status, formatter.formatMeasures(
-                    new Measure(durationSinceLastInteraction.toDays(), MeasureUnit.DAY)));
+            return context.getString(
+                    includeLastChatted ? R.string.last_interaction_status : R.string.timestamp,
+                    formatter.formatMeasures(
+                            new Measure(durationSinceLastInteraction.toDays(), MeasureUnit.DAY)));
         } else {
             return context.getString(durationSinceLastInteraction.toDays() == DAYS_IN_A_WEEK
-                            ? R.string.last_interaction_status :
-                            R.string.last_interaction_status_over,
+                            ? (includeLastChatted ? R.string.last_interaction_status :
+                            R.string.timestamp) :
+                            (includeLastChatted ? R.string.last_interaction_status_over
+                                    : R.string.over_timestamp),
                     formatter.formatMeasures(
                             new Measure(durationSinceLastInteraction.toDays() / DAYS_IN_A_WEEK,
                                     MeasureUnit.WEEK)));
@@ -411,4 +519,139 @@
         return tile != null && tile.getUserName().length() != 0;
     }
 
+    private static boolean hasBirthdayStatus(PeopleSpaceTile tile, Context context) {
+        return tile.getStatusText() != null && tile.getStatusText().equals(
+                context.getString(R.string.birthday_status));
+    }
+
+
+    /** Calls to retrieve birthdays on a background thread. */
+    private static void getBirthdaysOnBackgroundThread(Context context,
+            AppWidgetManager appWidgetManager,
+            Map<Integer, PeopleSpaceTile> peopleSpaceTiles, int[] appWidgetIds) {
+        ThreadUtils.postOnBackgroundThread(
+                () -> getBirthdays(context, appWidgetManager, peopleSpaceTiles, appWidgetIds));
+    }
+
+    /** Queries the Contacts DB for any birthdays today. */
+    @VisibleForTesting
+    public static void getBirthdays(Context context, AppWidgetManager appWidgetManager,
+            Map<Integer, PeopleSpaceTile> widgetIdToTile, int[] appWidgetIds) {
+        if (DEBUG) Log.d(TAG, "Get birthdays");
+        if (appWidgetIds.length == 0) return;
+        List<String> lookupKeysWithBirthdaysToday = getContactLookupKeysWithBirthdaysToday(context);
+        for (int appWidgetId : appWidgetIds) {
+            PeopleSpaceTile storedTile = widgetIdToTile.get(appWidgetId);
+            if (storedTile == null || storedTile.getContactUri() == null) {
+                if (DEBUG) Log.d(TAG, "No contact uri for: " + storedTile);
+                removeBirthdayStatusIfPresent(appWidgetManager, context, storedTile, appWidgetId);
+                continue;
+            }
+            if (lookupKeysWithBirthdaysToday.isEmpty()) {
+                if (DEBUG) Log.d(TAG, "No birthdays today");
+                removeBirthdayStatusIfPresent(appWidgetManager, context, storedTile, appWidgetId);
+                continue;
+            }
+            updateTileWithBirthday(context, appWidgetManager, lookupKeysWithBirthdaysToday,
+                    storedTile,
+                    appWidgetId);
+        }
+    }
+
+    /** Removes the birthday status if present in {@code storedTile} and pushes the update. */
+    private static void removeBirthdayStatusIfPresent(AppWidgetManager appWidgetManager,
+            Context context, PeopleSpaceTile storedTile, int appWidgetId) {
+        if (hasBirthdayStatus(storedTile, context)) {
+            if (DEBUG) Log.d(TAG, "Remove " + storedTile.getUserName() + "'s birthday");
+            updateAppWidgetOptionsAndView(appWidgetManager, context, appWidgetId,
+                    storedTile.toBuilder()
+                            .setStatusText(null)
+                            .build());
+        }
+    }
+
+    /**
+     * Update {@code storedTile} if the contact has a lookup key matched to any {@code
+     * lookupKeysWithBirthdays}.
+     */
+    private static void updateTileWithBirthday(Context context, AppWidgetManager appWidgetManager,
+            List<String> lookupKeysWithBirthdaysToday, PeopleSpaceTile storedTile,
+            int appWidgetId) {
+        Cursor cursor = null;
+        try {
+            cursor = context.getContentResolver().query(storedTile.getContactUri(),
+                    null, null, null, null);
+            while (cursor != null && cursor.moveToNext()) {
+                String storedLookupKey = cursor.getString(
+                        cursor.getColumnIndex(ContactsContract.CommonDataKinds.Event.LOOKUP_KEY));
+                if (!storedLookupKey.isEmpty() && lookupKeysWithBirthdaysToday.contains(
+                        storedLookupKey)) {
+                    if (DEBUG) Log.d(TAG, storedTile.getUserName() + "'s birthday today!");
+                    updateAppWidgetOptionsAndView(appWidgetManager, context, appWidgetId,
+                            storedTile.toBuilder()
+                                    .setStatusText(context.getString(R.string.birthday_status))
+                                    .build());
+                    return;
+                }
+            }
+        } catch (SQLException e) {
+            Log.e(TAG, "Failed to query contact: " + e);
+        } finally {
+            if (cursor != null) {
+                cursor.close();
+            }
+        }
+        removeBirthdayStatusIfPresent(appWidgetManager, context, storedTile, appWidgetId);
+    }
+
+    /** Update app widget options and the current view. */
+    private static void updateAppWidgetOptionsAndView(AppWidgetManager appWidgetManager,
+            Context context, int appWidgetId, PeopleSpaceTile tile) {
+        updateAppWidgetOptions(appWidgetManager, appWidgetId, tile);
+        RemoteViews views = createRemoteViews(context,
+                tile, appWidgetId);
+        appWidgetManager.updateAppWidget(appWidgetId, views);
+    }
+
+    /**
+     * Returns lookup keys for all contacts with a birthday today.
+     *
+     * <p>Birthdays are queried from a different table within the Contacts DB than the table for
+     * the Contact Uri provided by most messaging apps. Matching by the contact ID is then quite
+     * fragile as the row IDs across the different tables are not guaranteed to stay aligned, so we
+     * match the data by {@link ContactsContract.ContactsColumns#LOOKUP_KEY} key to ensure proper
+     * matching across all the Contacts DB tables.
+     */
+    private static List<String> getContactLookupKeysWithBirthdaysToday(Context context) {
+        List<String> lookupKeysWithBirthdaysToday = new ArrayList<>(1);
+        String today = new SimpleDateFormat("MM-dd").format(new Date());
+        String[] projection = new String[]{
+                ContactsContract.CommonDataKinds.Event.LOOKUP_KEY,
+                ContactsContract.CommonDataKinds.Event.START_DATE};
+        String where =
+                ContactsContract.Data.MIMETYPE
+                        + "= ? AND " + ContactsContract.CommonDataKinds.Event.TYPE + "="
+                        + ContactsContract.CommonDataKinds.Event.TYPE_BIRTHDAY + " AND substr("
+                        + ContactsContract.CommonDataKinds.Event.START_DATE + ",6) = ?";
+        String[] selection =
+                new String[]{ContactsContract.CommonDataKinds.Event.CONTENT_ITEM_TYPE, today};
+        Cursor cursor = null;
+        try {
+            cursor = context.getContentResolver().query(ContactsContract.Data.CONTENT_URI,
+                    projection, where, selection, null);
+            while (cursor != null && cursor.moveToNext()) {
+                String lookupKey = cursor.getString(
+                        cursor.getColumnIndex(ContactsContract.CommonDataKinds.Event.LOOKUP_KEY));
+                lookupKeysWithBirthdaysToday.add(lookupKey);
+            }
+        } catch (SQLException e) {
+            Log.e(TAG, "Failed to query birthdays: " + e);
+        } finally {
+            if (cursor != null) {
+                cursor.close();
+            }
+        }
+        return lookupKeysWithBirthdaysToday;
+    }
 }
+
diff --git a/packages/SystemUI/src/com/android/systemui/people/widget/PeopleSpaceWidgetRemoteViewsFactory.java b/packages/SystemUI/src/com/android/systemui/people/widget/PeopleSpaceWidgetRemoteViewsFactory.java
index 1e6c213..fb33aff 100644
--- a/packages/SystemUI/src/com/android/systemui/people/widget/PeopleSpaceWidgetRemoteViewsFactory.java
+++ b/packages/SystemUI/src/com/android/systemui/people/widget/PeopleSpaceWidgetRemoteViewsFactory.java
@@ -34,7 +34,6 @@
 
 import java.util.ArrayList;
 import java.util.List;
-import java.util.Map;
 
 /** People Space Widget RemoteViewsFactory class. */
 public class PeopleSpaceWidgetRemoteViewsFactory implements RemoteViewsService.RemoteViewsFactory {
@@ -45,7 +44,7 @@
     private INotificationManager mNotificationManager;
     private PackageManager mPackageManager;
     private LauncherApps mLauncherApps;
-    private List<Map.Entry<Long, PeopleSpaceTile>> mTiles = new ArrayList<>();
+    private List<PeopleSpaceTile> mTiles = new ArrayList<>();
     private Context mContext;
 
     public PeopleSpaceWidgetRemoteViewsFactory(Context context, Intent intent) {
@@ -100,11 +99,10 @@
         RemoteViews personView = new RemoteViews(mContext.getPackageName(),
                 R.layout.people_space_widget_item);
         try {
-            Map.Entry<Long, PeopleSpaceTile> entry = mTiles.get(i);
-            PeopleSpaceTile tile = entry.getValue();
-            long lastInteraction = entry.getKey();
+            PeopleSpaceTile tile = mTiles.get(i);
 
-            String status = PeopleSpaceUtils.getLastInteractionString(mContext, lastInteraction);
+            String status = PeopleSpaceUtils.getLastInteractionString(mContext,
+                    tile.getLastInteractionTimestamp(), true);
 
             personView.setTextViewText(R.id.status, status);
             personView.setTextViewText(R.id.name, tile.getUserName().toString());
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java
index 2076cbf..7ec2691 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java
@@ -20,10 +20,8 @@
 import static android.provider.Settings.Global.ZEN_MODE_OFF;
 
 import android.app.Dialog;
-import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
-import android.content.IntentFilter;
 import android.content.SharedPreferences;
 import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
 import android.content.pm.ApplicationInfo;
@@ -53,7 +51,6 @@
 import com.android.systemui.Prefs;
 import com.android.systemui.R;
 import com.android.systemui.SysUIToast;
-import com.android.systemui.broadcast.BroadcastDispatcher;
 import com.android.systemui.dagger.qualifiers.Background;
 import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.plugins.ActivityStarter;
@@ -78,17 +75,12 @@
     private static final Intent ZEN_PRIORITY_SETTINGS =
             new Intent(Settings.ACTION_ZEN_MODE_PRIORITY_SETTINGS);
 
-    private static final String ACTION_SET_VISIBLE = "com.android.systemui.dndtile.SET_VISIBLE";
-    private static final String EXTRA_VISIBLE = "visible";
-
     private final ZenModeController mController;
     private final DndDetailAdapter mDetailAdapter;
     private final SharedPreferences mSharedPreferences;
-    private final BroadcastDispatcher mBroadcastDispatcher;
 
     private boolean mListening;
     private boolean mShowingDetail;
-    private boolean mReceiverRegistered;
 
     @Inject
     public DndTile(
@@ -100,7 +92,6 @@
             ActivityStarter activityStarter,
             QSLogger qsLogger,
             ZenModeController zenModeController,
-            BroadcastDispatcher broadcastDispatcher,
             @Main SharedPreferences sharedPreferences
     ) {
         super(host, backgroundLooper, mainHandler, metricsLogger, statusBarStateController,
@@ -108,21 +99,9 @@
         mController = zenModeController;
         mSharedPreferences = sharedPreferences;
         mDetailAdapter = new DndDetailAdapter();
-        mBroadcastDispatcher = broadcastDispatcher;
-        broadcastDispatcher.registerReceiver(mReceiver, new IntentFilter(ACTION_SET_VISIBLE));
-        mReceiverRegistered = true;
         mController.observe(getLifecycle(), mZenCallback);
     }
 
-    @Override
-    protected void handleDestroy() {
-        super.handleDestroy();
-        if (mReceiverRegistered) {
-            mBroadcastDispatcher.unregisterReceiver(mReceiver);
-            mReceiverRegistered = false;
-        }
-    }
-
     public static void setVisible(Context context, boolean visible) {
         Prefs.putBoolean(context, Prefs.Key.DND_TILE_VISIBLE, visible);
     }
@@ -348,15 +327,6 @@
         }
     };
 
-    private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
-        @Override
-        public void onReceive(Context context, Intent intent) {
-            final boolean visible = intent.getBooleanExtra(EXTRA_VISIBLE, false);
-            setVisible(mContext, visible);
-            refreshState();
-        }
-    };
-
     private final class DndDetailAdapter implements DetailAdapter, OnAttachStateChangeListener {
 
         private ZenModePanel mZenPanel;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
index 7bac007..20efa32 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
@@ -197,7 +197,6 @@
             viewState.hasItemsInStableShelf = lastViewState.inShelf;
             viewState.hidden = !mAmbientState.isShadeExpanded()
                     || mAmbientState.isQsCustomizerShowing();
-            viewState.maxShelfEnd = maxShelfEnd;
         } else {
             viewState.hidden = true;
             viewState.location = ExpandableViewState.LOCATION_GONE;
@@ -823,10 +822,6 @@
         return - (getIntrinsicHeight() - mStatusBarHeight) / 2;
     }
 
-    public int getNotificationMergeSize() {
-        return getIntrinsicHeight();
-    }
-
     @Override
     public boolean hasNoContentHeight() {
         return true;
@@ -1018,7 +1013,6 @@
     private class ShelfState extends ExpandableViewState {
         private float openedAmount;
         private boolean hasItemsInStableShelf;
-        private float maxShelfEnd;
 
         @Override
         public void applyToView(View view) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/AppOpsCoordinator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/AppOpsCoordinator.java
index 998ae9e..c7ac403 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/AppOpsCoordinator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/AppOpsCoordinator.java
@@ -30,8 +30,12 @@
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifFilter;
 import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifSectioner;
+import com.android.systemui.statusbar.notification.collection.notifcollection.NotifLifetimeExtender;
 import com.android.systemui.util.concurrency.DelayableExecutor;
 
+import java.util.HashMap;
+import java.util.Map;
+
 import javax.inject.Inject;
 
 /**
@@ -71,6 +75,9 @@
     public void attach(NotifPipeline pipeline) {
         mNotifPipeline = pipeline;
 
+        // extend the lifetime of foreground notification services to show for at least 5 seconds
+        mNotifPipeline.addNotificationLifetimeExtender(mForegroundLifetimeExtender);
+
         // filter out foreground service notifications that aren't necessary anymore
         mNotifPipeline.addPreGroupFilter(mNotifFilter);
 
@@ -112,6 +119,64 @@
     };
 
     /**
+     * Extends the lifetime of foreground notification services such that they show for at least
+     * five seconds
+     */
+    private final NotifLifetimeExtender mForegroundLifetimeExtender =
+            new NotifLifetimeExtender() {
+        private static final int MIN_FGS_TIME_MS = 5000;
+        private OnEndLifetimeExtensionCallback mEndCallback;
+        private Map<NotificationEntry, Runnable> mEndRunnables = new HashMap<>();
+
+        @Override
+        public String getName() {
+            return TAG;
+        }
+
+        @Override
+        public void setCallback(OnEndLifetimeExtensionCallback callback) {
+            mEndCallback = callback;
+        }
+
+        @Override
+        public boolean shouldExtendLifetime(NotificationEntry entry, int reason) {
+            if ((entry.getSbn().getNotification().flags
+                    & Notification.FLAG_FOREGROUND_SERVICE) == 0) {
+                return false;
+            }
+
+            final long currTime = System.currentTimeMillis();
+            final boolean extendLife = currTime - entry.getSbn().getPostTime() < MIN_FGS_TIME_MS;
+
+            if (extendLife) {
+                if (!mEndRunnables.containsKey(entry)) {
+                    final Runnable endExtensionRunnable = () -> {
+                        mEndRunnables.remove(entry);
+                        mEndCallback.onEndLifetimeExtension(
+                                mForegroundLifetimeExtender,
+                                entry);
+                    };
+
+                    final Runnable cancelRunnable = mMainExecutor.executeDelayed(
+                            endExtensionRunnable,
+                            MIN_FGS_TIME_MS - (currTime - entry.getSbn().getPostTime()));
+                    mEndRunnables.put(entry, cancelRunnable);
+                }
+            }
+
+            return extendLife;
+        }
+
+        @Override
+        public void cancelLifetimeExtension(NotificationEntry entry) {
+            Runnable cancelRunnable = mEndRunnables.remove(entry);
+            if (cancelRunnable != null) {
+                cancelRunnable.run();
+            }
+        }
+    };
+
+    /**
      * Puts foreground service notifications into its own section.
      */
     private final NotifSectioner mNotifSectioner = new NotifSectioner("ForegroundService") {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
index 0dc824f..9e8385b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
@@ -632,10 +632,15 @@
 
         if (DEBUG) {
             int y = mTopPadding;
+            mDebugPaint.setColor(Color.RED);
             canvas.drawLine(0, y, getWidth(), y, mDebugPaint);
+
             y = getLayoutHeight();
+            mDebugPaint.setColor(Color.YELLOW);
             canvas.drawLine(0, y, getWidth(), y, mDebugPaint);
+
             y = getHeight() - getEmptyBottomMargin();
+            mDebugPaint.setColor(Color.GREEN);
             canvas.drawLine(0, y, getWidth(), y, mDebugPaint);
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
index 4ca9c5d..db0713c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
@@ -289,8 +289,6 @@
                     SysUiStatsLog.KEYGUARD_BOUNCER_STATE_CHANGED__STATE__HIDDEN);
             mDismissCallbackRegistry.notifyDismissCancelled();
         }
-        mExpansion = EXPANSION_HIDDEN;
-        dispatchExpansionChanged();
         mIsScrimmed = false;
         mFalsingCollector.onBouncerHidden();
         mCallback.onBouncerVisiblityChanged(false /* shown */);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java
index b9e8d74..6da5d1b9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java
@@ -164,10 +164,10 @@
     public void setup(int statusBarMinHeight, int maxShadeBottom, int notificationStackHeight,
             float panelExpansion, int parentHeight, int keyguardStatusHeight, int clockPreferredY,
             boolean hasCustomClock, boolean hasVisibleNotifs, float dark, float emptyDragAmount,
-            boolean bypassEnabled, int unlockedStackScrollerPadding, boolean udfpsEnrolled,
+            boolean bypassEnabled, int unlockedStackScrollerPadding, boolean showLockIcon,
             float qsExpansion) {
-        mMinTopMargin = statusBarMinHeight + (udfpsEnrolled ? mContainerTopPaddingWithoutLockIcon :
-                mContainerTopPaddingWithLockIcon);
+        mMinTopMargin = statusBarMinHeight + (showLockIcon
+                ? mContainerTopPaddingWithLockIcon : mContainerTopPaddingWithoutLockIcon);
         mMaxShadeBottom = maxShadeBottom;
         mNotificationStackHeight = notificationStackHeight;
         mPanelExpansion = panelExpansion;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenLockIconController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenLockIconController.java
index 6bdc303..ab0366e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenLockIconController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenLockIconController.java
@@ -501,7 +501,7 @@
         if (mBlockUpdates && canBlockUpdates()) {
             shouldUpdate = false;
         }
-        if (shouldUpdate && mLockIcon != null) {
+        if (shouldUpdate && mLockIcon != null && mLockIcon.getVisibility() != GONE) {
             mLockIcon.update(state,
                     mStatusBarStateController.isDozing(), mKeyguardJustShown);
         }
@@ -549,16 +549,14 @@
             return false;
         }
 
-        if (mKeyguardUpdateMonitor.isUdfpsEnrolled()) {
-            boolean changed = mLockIcon.getVisibility() == GONE;
+        if (!mKeyguardUpdateMonitor.shouldShowLockIcon()) {
+            boolean changed = mLockIcon.getVisibility() != GONE;
             mLockIcon.setVisibility(GONE);
             return changed;
         }
 
         boolean onAodOrDocked = mStatusBarStateController.isDozing() || mDocked;
-        boolean invisible = onAodOrDocked || mWakeAndUnlockRunning || mShowingLaunchAffordance
-                || (mKeyguardSecurityModel.getSecurityMode(KeyguardUpdateMonitor.getCurrentUser())
-                == KeyguardSecurityModel.SecurityMode.None);
+        boolean invisible = onAodOrDocked || mWakeAndUnlockRunning || mShowingLaunchAffordance;
         boolean fingerprintOrBypass = mFingerprintUnlock
                 || mKeyguardBypassController.getBypassEnabled();
         if (fingerprintOrBypass && !mBouncerShowingScrimmed) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
index 8d3b128..ba08e76 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
@@ -912,7 +912,8 @@
                     clockPreferredY, hasCustomClock(),
                     hasVisibleNotifications, mInterpolatedDarkAmount, mEmptyDragAmount,
                     bypassEnabled, getUnlockedStackScrollerPadding(),
-                    mUpdateMonitor.isUdfpsEnrolled(), getQsExpansionFraction());
+                    mUpdateMonitor.shouldShowLockIcon(),
+                    getQsExpansionFraction());
             mClockPositionAlgorithm.run(mClockPositionResult);
             mKeyguardStatusViewController.updatePosition(
                     mClockPositionResult.clockX, mClockPositionResult.clockY,
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 ab96a6d..f8e361f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
@@ -1003,7 +1003,6 @@
     }
 
     private void updateThemeColors() {
-        if (mScrimBehind == null) return;
         int background = Utils.getColorAttr(mScrimBehind.getContext(),
                 android.R.attr.colorBackgroundFloating).getDefaultColor();
         int accent = Utils.getColorAccent(mScrimBehind.getContext()).getDefaultColor();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NextAlarmControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NextAlarmControllerImpl.java
index 272c494..22fd93e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NextAlarmControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NextAlarmControllerImpl.java
@@ -25,11 +25,15 @@
 
 import androidx.annotation.NonNull;
 
+import com.android.systemui.Dumpable;
+import com.android.systemui.broadcast.BroadcastDispatcher;
 import com.android.systemui.dagger.SysUISingleton;
+import com.android.systemui.dump.DumpManager;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
 import java.util.ArrayList;
+import java.util.Date;
 
 import javax.inject.Inject;
 
@@ -38,7 +42,7 @@
  */
 @SysUISingleton
 public class NextAlarmControllerImpl extends BroadcastReceiver
-        implements NextAlarmController {
+        implements NextAlarmController, Dumpable {
 
     private final ArrayList<NextAlarmChangeCallback> mChangeCallbacks = new ArrayList<>();
 
@@ -48,18 +52,34 @@
     /**
      */
     @Inject
-    public NextAlarmControllerImpl(Context context) {
-        mAlarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
+    public NextAlarmControllerImpl(
+            AlarmManager alarmManager,
+            BroadcastDispatcher broadcastDispatcher,
+            DumpManager dumpManager) {
+        dumpManager.registerDumpable("NextAlarmController", this);
+        mAlarmManager = alarmManager;
         IntentFilter filter = new IntentFilter();
         filter.addAction(Intent.ACTION_USER_SWITCHED);
         filter.addAction(AlarmManager.ACTION_NEXT_ALARM_CLOCK_CHANGED);
-        context.registerReceiverAsUser(this, UserHandle.ALL, filter, null, null);
+        broadcastDispatcher.registerReceiver(this, filter, null, UserHandle.ALL);
         updateNextAlarm();
     }
 
+    @Override
     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
-        pw.println("NextAlarmController state:");
-        pw.print("  mNextAlarm="); pw.println(mNextAlarm);
+        pw.print("mNextAlarm=");
+        if (mNextAlarm != null) {
+            pw.println(new Date(mNextAlarm.getTriggerTime()));
+            pw.print("  PendingIntentPkg=");
+            pw.println(mNextAlarm.getShowIntent().getCreatorPackage());
+        } else {
+            pw.println("null");
+        }
+
+        pw.println("Registered Callbacks:");
+        for (NextAlarmChangeCallback callback : mChangeCallbacks) {
+            pw.print("    "); pw.println(callback.toString());
+        }
     }
 
     @Override
diff --git a/packages/SystemUI/tests/src/com/android/systemui/ForegroundServiceControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/ForegroundServiceControllerTest.java
index 6c3b37e..e967a5d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/ForegroundServiceControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/ForegroundServiceControllerTest.java
@@ -24,7 +24,10 @@
 
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
@@ -51,6 +54,8 @@
 import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
 import com.android.systemui.util.time.FakeSystemClock;
 
+import junit.framework.Assert;
+
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -79,7 +84,8 @@
         MockitoAnnotations.initMocks(this);
         mFsc = new ForegroundServiceController(mAppOpsController, mMainHandler);
         mListener = new ForegroundServiceNotificationListener(
-                mContext, mFsc, mEntryManager, mNotifPipeline, mClock);
+                mContext, mFsc, mEntryManager, mNotifPipeline,
+                mock(ForegroundServiceLifetimeExtender.class), mClock);
         ArgumentCaptor<NotificationEntryListener> entryListenerCaptor =
                 ArgumentCaptor.forClass(NotificationEntryListener.class);
         verify(mEntryManager).addNotificationEntryListener(
diff --git a/packages/SystemUI/tests/src/com/android/systemui/ForegroundServiceNotificationListenerTest.java b/packages/SystemUI/tests/src/com/android/systemui/ForegroundServiceNotificationListenerTest.java
new file mode 100644
index 0000000..9a40421
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/ForegroundServiceNotificationListenerTest.java
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui;
+
+import static com.android.systemui.ForegroundServiceLifetimeExtender.MIN_FGS_TIME_MS;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import android.app.Notification;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.systemui.statusbar.NotificationInteractionTracker;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
+import com.android.systemui.util.time.FakeSystemClock;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class ForegroundServiceNotificationListenerTest extends SysuiTestCase {
+    private ForegroundServiceLifetimeExtender mExtender;
+    private NotificationEntry mEntry;
+    private Notification mNotif;
+    private final FakeSystemClock mClock = new FakeSystemClock();
+
+    @Mock
+    private NotificationInteractionTracker mInteractionTracker;
+
+    @Before
+    public void setup() {
+        MockitoAnnotations.initMocks(this);
+        mExtender = new ForegroundServiceLifetimeExtender(mInteractionTracker, mClock);
+
+        mNotif = new Notification.Builder(mContext, "")
+                .setSmallIcon(R.drawable.ic_person)
+                .setContentTitle("Title")
+                .setContentText("Text")
+                .build();
+
+        mEntry = new NotificationEntryBuilder()
+                .setCreationTime(mClock.uptimeMillis())
+                .setNotification(mNotif)
+                .build();
+    }
+
+    /**
+     * ForegroundServiceLifetimeExtenderTest
+     */
+    @Test
+    public void testShouldExtendLifetime_should_foreground() {
+        // Extend the lifetime of a FGS notification iff it has not been visible
+        // for the minimum time
+        mNotif.flags |= Notification.FLAG_FOREGROUND_SERVICE;
+
+        // No time has elapsed, keep showing
+        assertTrue(mExtender.shouldExtendLifetime(mEntry));
+    }
+
+    @Test
+    public void testShouldExtendLifetime_shouldNot_foreground() {
+        mNotif.flags |= Notification.FLAG_FOREGROUND_SERVICE;
+
+        // Entry was created at mClock.uptimeMillis(), advance it MIN_FGS_TIME_MS + 1
+        mClock.advanceTime(MIN_FGS_TIME_MS + 1);
+        assertFalse(mExtender.shouldExtendLifetime(mEntry));
+    }
+
+    @Test
+    public void testShouldExtendLifetime_shouldNot_notForeground() {
+        mNotif.flags = 0;
+
+        // Entry was created at mClock.uptimeMillis(), advance it MIN_FGS_TIME_MS + 1
+        mClock.advanceTime(MIN_FGS_TIME_MS + 1);
+        assertFalse(mExtender.shouldExtendLifetime(mEntry));
+    }
+
+    @Test
+    public void testShouldExtendLifetime_shouldNot_interruped() {
+        // GIVEN a notification that would trigger lifetime extension
+        mNotif.flags |= Notification.FLAG_FOREGROUND_SERVICE;
+
+        // GIVEN the notification has alerted
+        mEntry.setInterruption();
+
+        // THEN the notification does not need to have its lifetime extended by this extender
+        assertFalse(mExtender.shouldExtendLifetime(mEntry));
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
index 648c319..7f8372e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
@@ -175,7 +175,7 @@
     @Test
     public void fingerDown() throws RemoteException {
         // Configure UdfpsView to accept the ACTION_DOWN event
-        when(mUdfpsView.isScrimShowing()).thenReturn(false);
+        when(mUdfpsView.isShowScrimAndDot()).thenReturn(false);
         when(mUdfpsView.isValidTouch(anyFloat(), anyFloat(), anyFloat())).thenReturn(true);
 
         // GIVEN that the overlay is showing
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/FaceAuthScreenBrightnessControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/FaceAuthScreenBrightnessControllerTest.kt
index 73a7ca9..cb05a6b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/FaceAuthScreenBrightnessControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/FaceAuthScreenBrightnessControllerTest.kt
@@ -83,7 +83,7 @@
         MockitoAnnotations.initMocks(this)
         faceAuthScreenBrightnessController = object : FaceAuthScreenBrightnessController(
                 notificationShadeWindowController, keyguardUpdateMonitor, resources, globalSettings,
-                systemSettings, mainHandler, dumpManager) {
+                systemSettings, mainHandler, dumpManager, true) {
             override fun createAnimator(start: Float, end: Float) = animator
         }
         `when`(systemSettings.getFloat(eq(SCREEN_BRIGHTNESS_FLOAT))).thenReturn(INITIAL_BRIGHTNESS)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputBaseDialogTest.java b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputBaseDialogTest.java
index fd5d996..c00b394 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputBaseDialogTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputBaseDialogTest.java
@@ -24,6 +24,7 @@
 import static org.mockito.Mockito.when;
 
 import android.content.Context;
+import android.media.MediaRouter2Manager;
 import android.media.session.MediaSessionManager;
 import android.os.Bundle;
 import android.testing.AndroidTestingRunner;
@@ -63,6 +64,7 @@
     private NotificationEntryManager mNotificationEntryManager =
             mock(NotificationEntryManager.class);
     private final UiEventLogger mUiEventLogger = mock(UiEventLogger.class);
+    private final MediaRouter2Manager mRouterManager = mock(MediaRouter2Manager.class);
 
     private MediaOutputBaseDialogImpl mMediaOutputBaseDialogImpl;
     private MediaOutputController mMediaOutputController;
@@ -75,7 +77,7 @@
     public void setUp() {
         mMediaOutputController = new MediaOutputController(mContext, TEST_PACKAGE, false,
                 mMediaSessionManager, mLocalBluetoothManager, mShadeController, mStarter,
-                mNotificationEntryManager, mUiEventLogger);
+                mNotificationEntryManager, mUiEventLogger, mRouterManager);
         mMediaOutputBaseDialogImpl = new MediaOutputBaseDialogImpl(mContext,
                 mMediaOutputController);
         mMediaOutputBaseDialogImpl.onCreate(new Bundle());
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputControllerTest.java
index d1a617b..c1a3994 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputControllerTest.java
@@ -32,6 +32,7 @@
 import android.graphics.drawable.Icon;
 import android.media.MediaDescription;
 import android.media.MediaMetadata;
+import android.media.MediaRouter2Manager;
 import android.media.RoutingSessionInfo;
 import android.media.session.MediaController;
 import android.media.session.MediaSessionManager;
@@ -91,6 +92,7 @@
     private NotificationEntryManager mNotificationEntryManager =
             mock(NotificationEntryManager.class);
     private final UiEventLogger mUiEventLogger = mock(UiEventLogger.class);
+    private final MediaRouter2Manager mRouter2Manager = mock(MediaRouter2Manager.class);
 
     private Context mSpyContext;
     private MediaOutputController mMediaOutputController;
@@ -113,7 +115,7 @@
 
         mMediaOutputController = new MediaOutputController(mSpyContext, TEST_PACKAGE_NAME, false,
                 mMediaSessionManager, mLocalBluetoothManager, mShadeController, mStarter,
-                mNotificationEntryManager, mUiEventLogger);
+                mNotificationEntryManager, mUiEventLogger, mRouter2Manager);
         mLocalMediaManager = spy(mMediaOutputController.mLocalMediaManager);
         mMediaOutputController.mLocalMediaManager = mLocalMediaManager;
         MediaDescription.Builder builder = new MediaDescription.Builder();
@@ -157,7 +159,7 @@
     public void start_withoutPackageName_verifyMediaControllerInit() {
         mMediaOutputController = new MediaOutputController(mSpyContext, null, false,
                 mMediaSessionManager, mLocalBluetoothManager, mShadeController, mStarter,
-                mNotificationEntryManager, mUiEventLogger);
+                mNotificationEntryManager, mUiEventLogger, mRouter2Manager);
 
         mMediaOutputController.start(mCb);
 
@@ -178,7 +180,7 @@
     public void stop_withoutPackageName_verifyMediaControllerDeinit() {
         mMediaOutputController = new MediaOutputController(mSpyContext, null, false,
                 mMediaSessionManager, mLocalBluetoothManager, mShadeController, mStarter,
-                mNotificationEntryManager, mUiEventLogger);
+                mNotificationEntryManager, mUiEventLogger, mRouter2Manager);
 
         mMediaOutputController.start(mCb);
 
@@ -449,7 +451,7 @@
     public void getNotificationLargeIcon_withoutPackageName_returnsNull() {
         mMediaOutputController = new MediaOutputController(mSpyContext, null, false,
                 mMediaSessionManager, mLocalBluetoothManager, mShadeController, mStarter,
-                mNotificationEntryManager, mUiEventLogger);
+                mNotificationEntryManager, mUiEventLogger, mRouter2Manager);
 
         assertThat(mMediaOutputController.getNotificationIcon()).isNull();
     }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputDialogTest.java b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputDialogTest.java
index 86f6bde..e47a5e7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputDialogTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputDialogTest.java
@@ -24,6 +24,7 @@
 import static org.mockito.Mockito.when;
 
 import android.media.MediaRoute2Info;
+import android.media.MediaRouter2Manager;
 import android.media.session.MediaSessionManager;
 import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
@@ -65,6 +66,7 @@
     private final NotificationEntryManager mNotificationEntryManager =
             mock(NotificationEntryManager.class);
     private final UiEventLogger mUiEventLogger = mock(UiEventLogger.class);
+    private final MediaRouter2Manager mRouterManager = mock(MediaRouter2Manager.class);
 
     private MediaOutputDialog mMediaOutputDialog;
     private MediaOutputController mMediaOutputController;
@@ -74,7 +76,7 @@
     public void setUp() {
         mMediaOutputController = new MediaOutputController(mContext, TEST_PACKAGE, false,
                 mMediaSessionManager, mLocalBluetoothManager, mShadeController, mStarter,
-                mNotificationEntryManager, mUiEventLogger);
+                mNotificationEntryManager, mUiEventLogger, mRouterManager);
         mMediaOutputController.mLocalMediaManager = mLocalMediaManager;
         mMediaOutputDialog = new MediaOutputDialog(mContext, false,
                 mMediaOutputController, mUiEventLogger);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputGroupDialogTest.java b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputGroupDialogTest.java
index c296ff5..6111099 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputGroupDialogTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputGroupDialogTest.java
@@ -21,6 +21,7 @@
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
 
+import android.media.MediaRouter2Manager;
 import android.media.session.MediaSessionManager;
 import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
@@ -64,6 +65,7 @@
     private NotificationEntryManager mNotificationEntryManager =
             mock(NotificationEntryManager.class);
     private final UiEventLogger mUiEventLogger = mock(UiEventLogger.class);
+    private final MediaRouter2Manager mRouterManager = mock(MediaRouter2Manager.class);
 
     private MediaOutputGroupDialog mMediaOutputGroupDialog;
     private MediaOutputController mMediaOutputController;
@@ -73,7 +75,7 @@
     public void setUp() {
         mMediaOutputController = new MediaOutputController(mContext, TEST_PACKAGE, false,
                 mMediaSessionManager, mLocalBluetoothManager, mShadeController, mStarter,
-                mNotificationEntryManager, mUiEventLogger);
+                mNotificationEntryManager, mUiEventLogger, mRouterManager);
         mMediaOutputController.mLocalMediaManager = mLocalMediaManager;
         mMediaOutputGroupDialog = new MediaOutputGroupDialog(mContext, false,
                 mMediaOutputController);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/people/PeopleSpaceUtilsTest.java b/packages/SystemUI/tests/src/com/android/systemui/people/PeopleSpaceUtilsTest.java
index e934f84..644373c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/people/PeopleSpaceUtilsTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/people/PeopleSpaceUtilsTest.java
@@ -21,7 +21,13 @@
 import static com.google.common.truth.Truth.assertThat;
 
 import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.ArgumentMatchers.isNull;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
 import android.app.Notification;
@@ -29,11 +35,16 @@
 import android.app.people.PeopleSpaceTile;
 import android.appwidget.AppWidgetManager;
 import android.content.ContentResolver;
+import android.content.Context;
 import android.content.Intent;
+import android.content.pm.LauncherApps;
+import android.content.pm.ShortcutInfo;
+import android.database.Cursor;
 import android.graphics.drawable.Icon;
 import android.net.Uri;
 import android.os.Bundle;
 import android.os.RemoteException;
+import android.provider.ContactsContract;
 import android.provider.Settings;
 import android.service.notification.StatusBarNotification;
 import android.testing.AndroidTestingRunner;
@@ -52,6 +63,8 @@
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 
+import java.util.Map;
+
 @SmallTest
 @RunWith(AndroidTestingRunner.class)
 public class PeopleSpaceUtilsTest extends SysuiTestCase {
@@ -61,6 +74,32 @@
     private static final String SHORTCUT_ID = "101";
     private static final String NOTIFICATION_KEY = "notification_key";
     private static final String NOTIFICATION_CONTENT = "notification_content";
+    private static final String TEST_LOOKUP_KEY = "lookup_key";
+    private static final int TEST_COLUMN_INDEX = 1;
+    private static final Uri URI = Uri.parse("fake_uri");
+    private static final Icon ICON = Icon.createWithResource("package", R.drawable.ic_android);
+    private static final Person PERSON = new Person.Builder()
+            .setName("name")
+            .setKey("abc")
+            .setUri(URI.toString())
+            .setBot(false)
+            .build();
+    private static final PeopleSpaceTile PERSON_TILE =
+            new PeopleSpaceTile
+                    .Builder(SHORTCUT_ID, "username", ICON, new Intent())
+                    .setNotificationKey(NOTIFICATION_KEY)
+                    .setNotificationContent(NOTIFICATION_CONTENT)
+                    .setNotificationDataUri(URI)
+                    .build();
+
+    private final ShortcutInfo mShortcutInfo = new ShortcutInfo.Builder(mContext,
+            SHORTCUT_ID).setLongLabel(
+            "name").setPerson(PERSON)
+            .build();
+    private final ShortcutInfo mShortcutInfoWithoutPerson = new ShortcutInfo.Builder(mContext,
+            SHORTCUT_ID).setLongLabel(
+            "name")
+            .build();
 
     @Mock
     private NotificationListener mListenerService;
@@ -68,26 +107,12 @@
     private IAppWidgetService mIAppWidgetService;
     @Mock
     private AppWidgetManager mAppWidgetManager;
-
-    private static Icon sIcon = Icon.createWithResource("package", R.drawable.ic_android);
-    private static Uri sUri = new Uri.Builder()
-            .scheme(ContentResolver.SCHEME_CONTENT)
-            .authority("something")
-            .path("test")
-            .build();
-    private static Person sPerson = new Person.Builder()
-            .setName("name")
-            .setKey("abc")
-            .setUri("uri")
-            .setBot(false)
-            .build();
-    private static PeopleSpaceTile sPeopleSpaceTile =
-            new PeopleSpaceTile
-                    .Builder(SHORTCUT_ID, "username", sIcon, new Intent())
-                    .setNotificationKey(NOTIFICATION_KEY)
-                    .setNotificationContent(NOTIFICATION_CONTENT)
-                    .setNotificationDataUri(sUri)
-                    .build();
+    @Mock
+    private Cursor mMockCursor;
+    @Mock
+    private ContentResolver mMockContentResolver;
+    @Mock
+    private Context mMockContext;
 
     @Before
     public void setUp() throws RemoteException {
@@ -97,13 +122,19 @@
 
         int[] widgetIdsArray = {WIDGET_ID_WITH_SHORTCUT, WIDGET_ID_WITHOUT_SHORTCUT};
         Bundle options = new Bundle();
-        options.putParcelable(OPTIONS_PEOPLE_SPACE_TILE, sPeopleSpaceTile);
+        options.putParcelable(OPTIONS_PEOPLE_SPACE_TILE, PERSON_TILE);
 
         when(mIAppWidgetService.getAppWidgetIds(any())).thenReturn(widgetIdsArray);
         when(mAppWidgetManager.getAppWidgetOptions(eq(WIDGET_ID_WITH_SHORTCUT)))
                 .thenReturn(options);
         when(mAppWidgetManager.getAppWidgetOptions(eq(WIDGET_ID_WITHOUT_SHORTCUT)))
                 .thenReturn(new Bundle());
+
+        when(mMockContext.getContentResolver()).thenReturn(mMockContentResolver);
+        when(mMockContentResolver.query(any(Uri.class), any(), anyString(), any(),
+                isNull())).thenReturn(mMockCursor);
+        when(mMockContext.getString(R.string.birthday_status)).thenReturn(
+                mContext.getString(R.string.birthday_status));
     }
 
     @Test
@@ -124,15 +155,104 @@
     }
 
     @Test
+    public void testGetBackgroundTextFromMessageNoPunctuation() {
+        String backgroundText = PeopleSpaceUtils.getBackgroundTextFromMessage("test");
+
+        assertThat(backgroundText).isNull();
+    }
+
+    @Test
+    public void testGetBackgroundTextFromMessageSingleExclamation() {
+        String backgroundText = PeopleSpaceUtils.getBackgroundTextFromMessage("test!");
+
+        assertThat(backgroundText).isNull();
+    }
+
+    @Test
+    public void testGetBackgroundTextFromMessageSingleQuestion() {
+        String backgroundText = PeopleSpaceUtils.getBackgroundTextFromMessage("?test");
+
+        assertThat(backgroundText).isNull();
+    }
+
+    @Test
+    public void testGetBackgroundTextFromMessageSeparatedMarks() {
+        String backgroundText = PeopleSpaceUtils.getBackgroundTextFromMessage("test! right!");
+
+        assertThat(backgroundText).isNull();
+    }
+
+    @Test
+    public void testGetBackgroundTextFromMessageDoubleExclamation() {
+        String backgroundText = PeopleSpaceUtils.getBackgroundTextFromMessage("!!test");
+
+        assertThat(backgroundText).isEqualTo("!");
+    }
+
+    @Test
+    public void testGetBackgroundTextFromMessageDoubleQuestion() {
+        String backgroundText = PeopleSpaceUtils.getBackgroundTextFromMessage("test??");
+
+        assertThat(backgroundText).isEqualTo("?");
+    }
+
+    @Test
+    public void testGetBackgroundTextFromMessageMixed() {
+        String backgroundText = PeopleSpaceUtils.getBackgroundTextFromMessage("test?!");
+
+        assertThat(backgroundText).isEqualTo("!?");
+    }
+
+    @Test
+    public void testGetBackgroundTextFromMessageMixedInTheMiddle() {
+        String backgroundText = PeopleSpaceUtils.getBackgroundTextFromMessage(
+                "test!? in the middle");
+
+        assertThat(backgroundText).isEqualTo("!?");
+    }
+
+    @Test
+    public void testGetBackgroundTextFromMessageMixedDifferentOrder() {
+        String backgroundText = PeopleSpaceUtils.getBackgroundTextFromMessage(
+                "test!? in the middle");
+
+        assertThat(backgroundText).isEqualTo("!?");
+    }
+
+    @Test
+    public void testGetBackgroundTextFromMessageMultiple() {
+        String backgroundText = PeopleSpaceUtils.getBackgroundTextFromMessage(
+                "test!?!!? in the middle");
+
+        assertThat(backgroundText).isEqualTo("!?");
+    }
+
+    @Test
+    public void testGetBackgroundTextFromMessageQuestionFirst() {
+        String backgroundText = PeopleSpaceUtils.getBackgroundTextFromMessage(
+                "test?? in the middle!!");
+
+        assertThat(backgroundText).isEqualTo("?");
+    }
+
+    @Test
+    public void testGetBackgroundTextFromMessageExclamationFirst() {
+        String backgroundText = PeopleSpaceUtils.getBackgroundTextFromMessage(
+                "test!! in the middle??");
+
+        assertThat(backgroundText).isEqualTo("!");
+    }
+
+    @Test
     public void testGetLastMessagingStyleMessage() {
         Notification notification = new Notification.Builder(mContext, "test")
                 .setContentTitle("TEST_TITLE")
                 .setContentText("TEST_TEXT")
                 .setShortcutId(SHORTCUT_ID)
-                .setStyle(new Notification.MessagingStyle(sPerson)
-                        .addMessage(new Notification.MessagingStyle.Message("text1", 0, sPerson))
-                        .addMessage(new Notification.MessagingStyle.Message("text2", 20, sPerson))
-                        .addMessage(new Notification.MessagingStyle.Message("text3", 10, sPerson))
+                .setStyle(new Notification.MessagingStyle(PERSON)
+                        .addMessage(new Notification.MessagingStyle.Message("text1", 0, PERSON))
+                        .addMessage(new Notification.MessagingStyle.Message("text2", 20, PERSON))
+                        .addMessage(new Notification.MessagingStyle.Message("text3", 10, PERSON))
                 )
                 .build();
         StatusBarNotification sbn = new SbnBuilder()
@@ -149,21 +269,21 @@
     public void testAugmentTileFromStorageWithNotification() {
         PeopleSpaceTile tile =
                 new PeopleSpaceTile
-                        .Builder("id", "userName", sIcon, new Intent())
+                        .Builder("id", "userName", ICON, new Intent())
                         .build();
         PeopleSpaceTile actual = PeopleSpaceUtils
                 .augmentTileFromStorage(tile, mAppWidgetManager, WIDGET_ID_WITH_SHORTCUT);
 
         assertThat(actual.getNotificationKey()).isEqualTo(NOTIFICATION_KEY);
         assertThat(actual.getNotificationContent()).isEqualTo(NOTIFICATION_CONTENT);
-        assertThat(actual.getNotificationDataUri()).isEqualTo(sUri);
+        assertThat(actual.getNotificationDataUri()).isEqualTo(URI);
     }
 
     @Test
     public void testAugmentTileFromStorageWithoutNotification() {
         PeopleSpaceTile tile =
                 new PeopleSpaceTile
-                        .Builder("id", "userName", sIcon, new Intent())
+                        .Builder("id", "userName", ICON, new Intent())
                         .build();
         PeopleSpaceTile actual = PeopleSpaceUtils
                 .augmentTileFromStorage(tile, mAppWidgetManager, WIDGET_ID_WITHOUT_SHORTCUT);
@@ -172,4 +292,98 @@
         assertThat(actual.getNotificationKey()).isEqualTo(null);
         assertThat(actual.getNotificationDataUri()).isEqualTo(null);
     }
+
+    @Test
+    public void testDoNotUpdateSingleConversationAppWidgetWhenNotBirthday() {
+        int[] widgetIdsArray = {WIDGET_ID_WITH_SHORTCUT};
+        when(mMockCursor.moveToNext()).thenReturn(true, false);
+        when(mMockCursor.getString(eq(TEST_COLUMN_INDEX))).thenReturn(TEST_LOOKUP_KEY);
+        when(mMockCursor.getColumnIndex(eq(ContactsContract.CommonDataKinds.Event.LOOKUP_KEY)
+        )).thenReturn(TEST_COLUMN_INDEX);
+
+        // Existing tile does not have birthday status.
+        Map<Integer, PeopleSpaceTile> widgetIdToTile = Map.of(WIDGET_ID_WITH_SHORTCUT,
+                new PeopleSpaceTile.Builder(mShortcutInfoWithoutPerson,
+                        mContext.getSystemService(LauncherApps.class)).build());
+        PeopleSpaceUtils.getBirthdays(mMockContext, mAppWidgetManager,
+                widgetIdToTile, widgetIdsArray);
+
+        verify(mAppWidgetManager, never()).updateAppWidget(eq(WIDGET_ID_WITH_SHORTCUT),
+                any());
+    }
+
+    @Test
+    public void testUpdateSingleConversationAppWidgetWithoutPersonContactUriToRemoveBirthday() {
+        int[] widgetIdsArray = {WIDGET_ID_WITH_SHORTCUT};
+        when(mMockCursor.moveToNext()).thenReturn(true, false);
+        when(mMockCursor.getString(eq(TEST_COLUMN_INDEX))).thenReturn(TEST_LOOKUP_KEY);
+        when(mMockCursor.getColumnIndex(eq(ContactsContract.CommonDataKinds.Event.LOOKUP_KEY)
+        )).thenReturn(TEST_COLUMN_INDEX);
+
+        // Existing tile has a birthday status.
+        Map<Integer, PeopleSpaceTile> widgetIdToTile = Map.of(WIDGET_ID_WITH_SHORTCUT,
+                new PeopleSpaceTile.Builder(mShortcutInfoWithoutPerson,
+                        mContext.getSystemService(LauncherApps.class)).setStatusText(
+                        mContext.getString(R.string.birthday_status)).build());
+        PeopleSpaceUtils.getBirthdays(mMockContext, mAppWidgetManager,
+                widgetIdToTile, widgetIdsArray);
+
+        verify(mAppWidgetManager, times(1)).updateAppWidget(eq(WIDGET_ID_WITH_SHORTCUT),
+                any());
+    }
+
+    @Test
+    public void testUpdateSingleConversationAppWidgetToRemoveBirthdayWhenNoLongerBirthday() {
+        int[] widgetIdsArray = {WIDGET_ID_WITH_SHORTCUT};
+        Cursor mockPersonUriCursor = mock(Cursor.class);
+        Cursor mockBirthdaysUriCursor = mock(Cursor.class);
+        when(mockPersonUriCursor.moveToNext()).thenReturn(true, false);
+        when(mockBirthdaysUriCursor.moveToNext()).thenReturn(true, false);
+        when(mockBirthdaysUriCursor.getColumnIndex(
+                eq(ContactsContract.CommonDataKinds.Event.LOOKUP_KEY)
+        )).thenReturn(TEST_COLUMN_INDEX);
+        when(mockPersonUriCursor.getColumnIndex(
+                eq(ContactsContract.CommonDataKinds.Event.LOOKUP_KEY)
+        )).thenReturn(TEST_COLUMN_INDEX);
+        // Return different cursors based on the Uri queried.
+        when(mMockContentResolver.query(eq(URI), any(), any(), any(),
+                any())).thenReturn(mockPersonUriCursor);
+        when(mMockContentResolver.query(eq(ContactsContract.Data.CONTENT_URI), any(), any(), any(),
+                any())).thenReturn(mockBirthdaysUriCursor);
+        // Each cursor returns a different lookup key.
+        when(mockBirthdaysUriCursor.getString(eq(TEST_COLUMN_INDEX))).thenReturn(TEST_LOOKUP_KEY);
+        when(mockPersonUriCursor.getString(eq(TEST_COLUMN_INDEX))).thenReturn(
+                TEST_LOOKUP_KEY + "differentlookup");
+
+        // Existing tile has a birthday status.
+        Map<Integer, PeopleSpaceTile> widgetIdToTile = Map.of(WIDGET_ID_WITH_SHORTCUT,
+                new PeopleSpaceTile.Builder(mShortcutInfo,
+                        mContext.getSystemService(LauncherApps.class)).setStatusText(
+                        mContext.getString(R.string.birthday_status)).build());
+        PeopleSpaceUtils.getBirthdays(mMockContext, mAppWidgetManager,
+                widgetIdToTile, widgetIdsArray);
+
+        verify(mAppWidgetManager, times(1)).updateAppWidget(eq(WIDGET_ID_WITH_SHORTCUT),
+                any());
+    }
+
+    @Test
+    public void testUpdateSingleConversationAppWidgetWhenBirthday() {
+        int[] widgetIdsArray = {WIDGET_ID_WITH_SHORTCUT};
+        when(mMockCursor.moveToNext()).thenReturn(true, false, true, false);
+        when(mMockCursor.getString(eq(TEST_COLUMN_INDEX))).thenReturn(TEST_LOOKUP_KEY);
+        when(mMockCursor.getColumnIndex(eq(ContactsContract.CommonDataKinds.Event.LOOKUP_KEY)
+        )).thenReturn(TEST_COLUMN_INDEX);
+
+        // Existing tile has a birthday status.
+        Map<Integer, PeopleSpaceTile> widgetIdToTile = Map.of(WIDGET_ID_WITH_SHORTCUT,
+                new PeopleSpaceTile.Builder(mShortcutInfo,
+                        mContext.getSystemService(LauncherApps.class)).setStatusText(
+                        mContext.getString(R.string.birthday_status)).build());
+        PeopleSpaceUtils.getBirthdays(mMockContext, mAppWidgetManager,
+                widgetIdToTile, widgetIdsArray);
+
+        verify(mAppWidgetManager, times(1)).updateAppWidget(eq(WIDGET_ID_WITH_SHORTCUT),
+                any());
+    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/people/widget/PeopleSpaceWidgetManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/people/widget/PeopleSpaceWidgetManagerTest.java
index cd4f51e..df07b12 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/people/widget/PeopleSpaceWidgetManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/people/widget/PeopleSpaceWidgetManagerTest.java
@@ -37,7 +37,6 @@
 import android.app.Person;
 import android.app.people.PeopleSpaceTile;
 import android.appwidget.AppWidgetManager;
-import android.content.ContentResolver;
 import android.content.Intent;
 import android.content.SharedPreferences;
 import android.content.pm.ParceledListSlice;
@@ -95,6 +94,21 @@
     private static final String OTHER_SHORTCUT_ID = "102";
     private static final String NOTIFICATION_KEY = "notification_key";
     private static final String NOTIFICATION_CONTENT = "notification_content";
+    private static final Uri URI = Uri.parse("fake_uri");
+    private static final Icon ICON = Icon.createWithResource("package", R.drawable.ic_android);
+    private static final Person PERSON = new Person.Builder()
+            .setName("name")
+            .setKey("abc")
+            .setUri(URI.toString())
+            .setBot(false)
+            .build();
+    private static final PeopleSpaceTile PERSON_TILE =
+            new PeopleSpaceTile
+                    .Builder(SHORTCUT_ID, "username", ICON, new Intent())
+                    .setNotificationKey(NOTIFICATION_KEY)
+                    .setNotificationContent(NOTIFICATION_CONTENT)
+                    .setNotificationDataUri(URI)
+                    .build();
 
     private PeopleSpaceWidgetManager mManager;
 
@@ -110,26 +124,6 @@
     @Captor
     private ArgumentCaptor<NotificationHandler> mListenerCaptor;
 
-    private static Icon sIcon = Icon.createWithResource("package", R.drawable.ic_android);
-    private static Uri sUri = new Uri.Builder()
-            .scheme(ContentResolver.SCHEME_CONTENT)
-            .authority("something")
-            .path("test")
-            .build();
-    private static Person sPerson = new Person.Builder()
-            .setName("name")
-            .setKey("abc")
-            .setUri("uri")
-            .setBot(false)
-            .build();
-    private static PeopleSpaceTile sPeopleSpaceTile =
-            new PeopleSpaceTile
-                    .Builder(SHORTCUT_ID, "username", sIcon, new Intent())
-                    .setNotificationKey(NOTIFICATION_KEY)
-                    .setNotificationContent(NOTIFICATION_CONTENT)
-                    .setNotificationDataUri(sUri)
-                    .build();
-
     private final NoManSimulator mNoMan = new NoManSimulator();
     private final FakeSystemClock mClock = new FakeSystemClock();
 
@@ -150,9 +144,9 @@
         SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(mContext);
         SharedPreferences.Editor editor = sp.edit();
         editor.putString(String.valueOf(WIDGET_ID_WITH_SHORTCUT), SHORTCUT_ID);
-        editor.commit();
+        editor.apply();
         Bundle options = new Bundle();
-        options.putParcelable(OPTIONS_PEOPLE_SPACE_TILE, sPeopleSpaceTile);
+        options.putParcelable(OPTIONS_PEOPLE_SPACE_TILE, PERSON_TILE);
 
         when(mAppWidgetManager.getAppWidgetOptions(eq(WIDGET_ID_WITH_SHORTCUT)))
                 .thenReturn(options);
@@ -304,7 +298,6 @@
                 UserHandle.getUserHandleForUid(0), channel, IMPORTANCE_HIGH);
         mClock.advanceTime(MIN_LINGER_DURATION);
 
-        verify(mIAppWidgetService, never()).getAppWidgetIds(any());
         verify(mIAppWidgetService, never()).notifyAppWidgetViewDataChanged(any(), any(), anyInt());
         verify(mAppWidgetManager, never()).updateAppWidget(anyInt(),
                 any(RemoteViews.class));
@@ -456,8 +449,8 @@
                 .setContentTitle("TEST_TITLE")
                 .setContentText("TEST_TEXT")
                 .setShortcutId(shortcutId)
-                .setStyle(new Notification.MessagingStyle(sPerson)
-                        .addMessage(new Notification.MessagingStyle.Message("text3", 10, sPerson))
+                .setStyle(new Notification.MessagingStyle(PERSON)
+                        .addMessage(new Notification.MessagingStyle.Message("text3", 10, PERSON))
                 )
                 .build();
         return new SbnBuilder()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/AppOpsCoordinatorTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/AppOpsCoordinatorTest.java
index 0954621..639e791 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/AppOpsCoordinatorTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/AppOpsCoordinatorTest.java
@@ -31,6 +31,7 @@
 import android.app.Notification;
 import android.os.Bundle;
 import android.os.UserHandle;
+import android.service.notification.NotificationListenerService;
 import android.service.notification.StatusBarNotification;
 import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
@@ -45,6 +46,7 @@
 import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
 import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifFilter;
 import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifSectioner;
+import com.android.systemui.statusbar.notification.collection.notifcollection.NotifLifetimeExtender;
 import com.android.systemui.util.concurrency.FakeExecutor;
 import com.android.systemui.util.time.FakeSystemClock;
 
@@ -69,6 +71,7 @@
     private NotificationEntryBuilder mEntryBuilder;
     private AppOpsCoordinator mAppOpsCoordinator;
     private NotifFilter mForegroundFilter;
+    private NotifLifetimeExtender mForegroundNotifLifetimeExtender;
     private NotifSectioner mFgsSection;
 
     private FakeSystemClock mClock = new FakeSystemClock();
@@ -95,6 +98,13 @@
         verify(mNotifPipeline, times(1)).addPreGroupFilter(filterCaptor.capture());
         mForegroundFilter = filterCaptor.getValue();
 
+        // capture lifetime extender
+        ArgumentCaptor<NotifLifetimeExtender> lifetimeExtenderCaptor =
+                ArgumentCaptor.forClass(NotifLifetimeExtender.class);
+        verify(mNotifPipeline, times(1)).addNotificationLifetimeExtender(
+                lifetimeExtenderCaptor.capture());
+        mForegroundNotifLifetimeExtender = lifetimeExtenderCaptor.getValue();
+
         mFgsSection = mAppOpsCoordinator.getSectioner();
     }
 
@@ -150,6 +160,55 @@
     }
 
     @Test
+    public void extendLifetimeText_notForeground() {
+        // GIVEN the notification doesn't represent a foreground service
+        mEntryBuilder.modifyNotification(mContext)
+                .setFlag(FLAG_FOREGROUND_SERVICE, false);
+
+        // THEN don't extend the lifetime
+        assertFalse(mForegroundNotifLifetimeExtender
+                .shouldExtendLifetime(mEntryBuilder.build(),
+                        NotificationListenerService.REASON_CLICK));
+    }
+
+    @Test
+    public void extendLifetimeText_foregroundNotifRecentlyPosted() {
+        // GIVEN the notification represents a foreground service that was just posted
+        Notification notification = new Notification.Builder(mContext, "test_channel")
+                .setFlag(FLAG_FOREGROUND_SERVICE, true)
+                .build();
+        NotificationEntry entry = mEntryBuilder
+                .setSbn(new StatusBarNotification(TEST_PKG, TEST_PKG, NOTIF_USER_ID, "",
+                        NOTIF_USER_ID, NOTIF_USER_ID, notification,
+                        new UserHandle(NOTIF_USER_ID), "", System.currentTimeMillis()))
+                .setNotification(notification)
+                .build();
+
+        // THEN extend the lifetime
+        assertTrue(mForegroundNotifLifetimeExtender
+                .shouldExtendLifetime(entry, NotificationListenerService.REASON_CLICK));
+    }
+
+    @Test
+    public void extendLifetimeText_foregroundNotifOld() {
+        // GIVEN the notification represents a foreground service that was posted 10 seconds ago
+        Notification notification = new Notification.Builder(mContext, "test_channel")
+                .setFlag(FLAG_FOREGROUND_SERVICE, true)
+                .build();
+        NotificationEntry entry = mEntryBuilder
+                .setSbn(new StatusBarNotification(TEST_PKG, TEST_PKG, NOTIF_USER_ID, "",
+                        NOTIF_USER_ID, NOTIF_USER_ID, notification,
+                        new UserHandle(NOTIF_USER_ID), "",
+                        System.currentTimeMillis() - 10000))
+                .setNotification(notification)
+                .build();
+
+        // THEN don't extend the lifetime because the extended time exceeds MIN_FGS_TIME_MS
+        assertFalse(mForegroundNotifLifetimeExtender
+                .shouldExtendLifetime(entry, NotificationListenerService.REASON_CLICK));
+    }
+
+    @Test
     public void testIncludeFGSInSection_importanceDefault() {
         // GIVEN the notification represents a colorized foreground service with > min importance
         mEntryBuilder
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LockscreenIconControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LockscreenIconControllerTest.java
index 1ac7937..95a3505 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LockscreenIconControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LockscreenIconControllerTest.java
@@ -91,6 +91,7 @@
     public void setUp() {
         MockitoAnnotations.initMocks(this);
 
+        when(mKeyguardUpdateMonitor.shouldShowLockIcon()).thenReturn(true);
         when(mLockIcon.getContext()).thenReturn(mContext);
         mLockIconController = new LockscreenLockIconController(
                 mLockscreenGestureLogger, mKeyguardUpdateMonitor, mLockPatternUtils,
@@ -145,12 +146,10 @@
     }
 
     @Test
-    public void testVisibility_noBouncer() {
-        // no security (ie: no lock screen OR swipe to unlock)
-        when(mKeyguardSecurityModel.getSecurityMode(anyInt())).thenReturn(
-                KeyguardSecurityModel.SecurityMode.None);
+    public void testVisibility_doNotShowLockIcon() {
+        when(mKeyguardUpdateMonitor.shouldShowLockIcon()).thenReturn(false);
 
         mOnAttachStateChangeListener.onViewAttachedToWindow(mLockIcon);
-        verify(mLockIcon).updateIconVisibility(false);
+        verify(mLockIcon).setVisibility(View.GONE);
     }
 }
diff --git a/packages/WallpaperBackup/src/com/android/wallpaperbackup/WallpaperBackupAgent.java b/packages/WallpaperBackup/src/com/android/wallpaperbackup/WallpaperBackupAgent.java
index 52a82dd..5ee30fb7 100644
--- a/packages/WallpaperBackup/src/com/android/wallpaperbackup/WallpaperBackupAgent.java
+++ b/packages/WallpaperBackup/src/com/android/wallpaperbackup/WallpaperBackupAgent.java
@@ -51,7 +51,6 @@
 import java.io.FileInputStream;
 import java.io.FileOutputStream;
 import java.io.IOException;
-import java.nio.charset.StandardCharsets;
 
 public class WallpaperBackupAgent extends BackupAgent {
     private static final String TAG = "WallpaperBackup";
@@ -323,8 +322,7 @@
     private Rect parseCropHint(File wallpaperInfo, String sectionTag) {
         Rect cropHint = new Rect();
         try (FileInputStream stream = new FileInputStream(wallpaperInfo)) {
-            XmlPullParser parser = Xml.newPullParser();
-            parser.setInput(stream, StandardCharsets.UTF_8.name());
+            XmlPullParser parser = Xml.resolvePullParser(stream);
 
             int type;
             do {
@@ -351,8 +349,7 @@
     private ComponentName parseWallpaperComponent(File wallpaperInfo, String sectionTag) {
         ComponentName name = null;
         try (FileInputStream stream = new FileInputStream(wallpaperInfo)) {
-            final XmlPullParser parser = Xml.newPullParser();
-            parser.setInput(stream, StandardCharsets.UTF_8.name());
+            final XmlPullParser parser = Xml.resolvePullParser(stream);
 
             int type;
             do {
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityServiceConnection.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityServiceConnection.java
index 5d67992..2626654 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityServiceConnection.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityServiceConnection.java
@@ -120,8 +120,6 @@
         AccessibilityUserState userState = mUserStateWeakReference.get();
         if (userState == null) return;
         userState.removeServiceLocked(this);
-        userState.resetFocusAppearanceLocked();
-        mSystemSupport.onClientChangeLocked(false);
         mSystemSupport.getFullScreenMagnificationController().resetAllIfNeeded(mId);
         mActivityTaskManagerService.setAllowAppSwitches(mComponentName.flattenToString(), -1,
                 userState.mUserId);
@@ -146,7 +144,6 @@
                 } finally {
                     Binder.restoreCallingIdentity(identity);
                 }
-                userState.resetFocusAppearanceLocked();
                 mSystemSupport.onClientChangeLocked(false);
             }
         }
@@ -313,7 +310,6 @@
             AccessibilityUserState userState = mUserStateWeakReference.get();
             if (userState != null) {
                 userState.serviceDisconnectedLocked(this);
-                userState.resetFocusAppearanceLocked();
             }
             resetLocked();
             mSystemSupport.getFullScreenMagnificationController().resetAllIfNeeded(mId);
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityUserState.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityUserState.java
index 90e2fdf..22efd37 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityUserState.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityUserState.java
@@ -194,7 +194,8 @@
         mUserNonInteractiveUiTimeout = 0;
         mUserInteractiveUiTimeout = 0;
         mMagnificationMode = ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN;
-        resetFocusAppearanceLocked();
+        mFocusStrokeWidth = mFocusStrokeWidthDefaultValue;
+        mFocusColor = mFocusColorDefaultValue;
     }
 
     void addServiceLocked(AccessibilityServiceConnection serviceConnection) {
@@ -924,13 +925,4 @@
         mFocusStrokeWidth = strokeWidth;
         mFocusColor = color;
     }
-
-    /**
-     * Resets the stroke width and color of the focus rectangle to the default value.
-     *
-     */
-    public void resetFocusAppearanceLocked() {
-        mFocusStrokeWidth = mFocusStrokeWidthDefaultValue;
-        mFocusColor = mFocusColorDefaultValue;
-    }
 }
diff --git a/services/accessibility/java/com/android/server/accessibility/ActionReplacingCallback.java b/services/accessibility/java/com/android/server/accessibility/ActionReplacingCallback.java
index a2c7e4f..bafb641 100644
--- a/services/accessibility/java/com/android/server/accessibility/ActionReplacingCallback.java
+++ b/services/accessibility/java/com/android/server/accessibility/ActionReplacingCallback.java
@@ -40,14 +40,10 @@
     private final IAccessibilityInteractionConnectionCallback mServiceCallback;
     private final IAccessibilityInteractionConnection mConnectionWithReplacementActions;
     private final int mInteractionId;
-    private final int mNodeWithReplacementActionsInteractionId;
     private final Object mLock = new Object();
 
     @GuardedBy("mLock")
-    private boolean mRequestForNodeWithReplacementActionFailed;
-
-    @GuardedBy("mLock")
-    AccessibilityNodeInfo mNodeWithReplacementActions;
+    List<AccessibilityNodeInfo> mNodesWithReplacementActions;
 
     @GuardedBy("mLock")
     List<AccessibilityNodeInfo> mNodesFromOriginalWindow;
@@ -55,8 +51,18 @@
     @GuardedBy("mLock")
     AccessibilityNodeInfo mNodeFromOriginalWindow;
 
+    // Keep track of whether or not we've been called back for a single node
     @GuardedBy("mLock")
-    List<AccessibilityNodeInfo> mPrefetchedNodesFromOriginalWindow;
+    boolean mSingleNodeCallbackHappened;
+
+    // Keep track of whether or not we've been called back for multiple node
+    @GuardedBy("mLock")
+    boolean mMultiNodeCallbackHappened;
+
+    // We shouldn't get any more callbacks after we've called back the original service, but
+    // keep track to make sure we catch such strange things
+    @GuardedBy("mLock")
+    boolean mDone;
 
     public ActionReplacingCallback(IAccessibilityInteractionConnectionCallback serviceCallback,
             IAccessibilityInteractionConnection connectionWithReplacementActions,
@@ -64,20 +70,19 @@
         mServiceCallback = serviceCallback;
         mConnectionWithReplacementActions = connectionWithReplacementActions;
         mInteractionId = interactionId;
-        mNodeWithReplacementActionsInteractionId = interactionId + 1;
 
         // Request the root node of the replacing window
         final long identityToken = Binder.clearCallingIdentity();
         try {
             mConnectionWithReplacementActions.findAccessibilityNodeInfoByAccessibilityId(
-                    AccessibilityNodeInfo.ROOT_NODE_ID, null,
-                    mNodeWithReplacementActionsInteractionId, this, 0,
+                    AccessibilityNodeInfo.ROOT_NODE_ID, null, interactionId + 1, this, 0,
                     interrogatingPid, interrogatingTid, null, null);
         } catch (RemoteException re) {
             if (DEBUG) {
                 Slog.e(LOG_TAG, "Error calling findAccessibilityNodeInfoByAccessibilityId()");
             }
-            mRequestForNodeWithReplacementActionFailed = true;
+            // Pretend we already got a (null) list of replacement nodes
+            mMultiNodeCallbackHappened = true;
         } finally {
             Binder.restoreCallingIdentity(identityToken);
         }
@@ -85,73 +90,46 @@
 
     @Override
     public void setFindAccessibilityNodeInfoResult(AccessibilityNodeInfo info, int interactionId) {
-        synchronized (mLock) {
+        boolean readyForCallback;
+        synchronized(mLock) {
             if (interactionId == mInteractionId) {
                 mNodeFromOriginalWindow = info;
-            } else if (interactionId == mNodeWithReplacementActionsInteractionId) {
-                mNodeWithReplacementActions = info;
             } else {
                 Slog.e(LOG_TAG, "Callback with unexpected interactionId");
                 return;
             }
+
+            mSingleNodeCallbackHappened = true;
+            readyForCallback = mMultiNodeCallbackHappened;
         }
-        replaceInfoActionsAndCallServiceIfReady();
+        if (readyForCallback) {
+            replaceInfoActionsAndCallService();
+        }
     }
 
     @Override
     public void setFindAccessibilityNodeInfosResult(List<AccessibilityNodeInfo> infos,
             int interactionId) {
-        synchronized (mLock) {
+        boolean callbackForSingleNode;
+        boolean callbackForMultipleNodes;
+        synchronized(mLock) {
             if (interactionId == mInteractionId) {
                 mNodesFromOriginalWindow = infos;
-            } else if (interactionId == mNodeWithReplacementActionsInteractionId) {
-                setNodeWithReplacementActionsFromList(infos);
+            } else if (interactionId == mInteractionId + 1) {
+                mNodesWithReplacementActions = infos;
             } else {
                 Slog.e(LOG_TAG, "Callback with unexpected interactionId");
                 return;
             }
+            callbackForSingleNode = mSingleNodeCallbackHappened;
+            callbackForMultipleNodes = mMultiNodeCallbackHappened;
+            mMultiNodeCallbackHappened = true;
         }
-        replaceInfoActionsAndCallServiceIfReady();
-    }
-
-    @Override
-    public void setPrefetchAccessibilityNodeInfoResult(List<AccessibilityNodeInfo> infos,
-                                                       int interactionId)
-            throws RemoteException {
-        synchronized (mLock) {
-            if (interactionId == mInteractionId) {
-                mPrefetchedNodesFromOriginalWindow = infos;
-            }  else {
-                Slog.e(LOG_TAG, "Callback with unexpected interactionId");
-                return;
-            }
-        }
-        replaceInfoActionsAndCallServiceIfReady();
-    }
-
-    private void replaceInfoActionsAndCallServiceIfReady() {
-        boolean originalAndReplacementCallsHaveHappened = false;
-        synchronized (mLock) {
-            originalAndReplacementCallsHaveHappened = mNodeWithReplacementActions != null
-                    && (mNodeFromOriginalWindow != null
-                    || mNodesFromOriginalWindow != null
-                    || mPrefetchedNodesFromOriginalWindow != null);
-            originalAndReplacementCallsHaveHappened
-                    |= mRequestForNodeWithReplacementActionFailed;
-        }
-        if (originalAndReplacementCallsHaveHappened) {
+        if (callbackForSingleNode) {
             replaceInfoActionsAndCallService();
-            replaceInfosActionsAndCallService();
-            replacePrefetchInfosActionsAndCallService();
         }
-    }
-
-    private void setNodeWithReplacementActionsFromList(List<AccessibilityNodeInfo> infos) {
-        for (int i = 0; i < infos.size(); i++) {
-            AccessibilityNodeInfo info = infos.get(i);
-            if (info.getSourceNodeId() == AccessibilityNodeInfo.ROOT_NODE_ID) {
-                mNodeWithReplacementActions = info;
-            }
+        if (callbackForMultipleNodes) {
+            replaceInfosActionsAndCallService();
         }
     }
 
@@ -165,10 +143,18 @@
     private void replaceInfoActionsAndCallService() {
         final AccessibilityNodeInfo nodeToReturn;
         synchronized (mLock) {
+            if (mDone) {
+                if (DEBUG) {
+                    Slog.e(LOG_TAG, "Extra callback");
+                }
+                return;
+            }
             if (mNodeFromOriginalWindow != null) {
                 replaceActionsOnInfoLocked(mNodeFromOriginalWindow);
             }
+            recycleReplaceActionNodesLocked();
             nodeToReturn = mNodeFromOriginalWindow;
+            mDone = true;
         }
         try {
             mServiceCallback.setFindAccessibilityNodeInfoResult(nodeToReturn, mInteractionId);
@@ -182,7 +168,21 @@
     private void replaceInfosActionsAndCallService() {
         final List<AccessibilityNodeInfo> nodesToReturn;
         synchronized (mLock) {
-            nodesToReturn = replaceActionsLocked(mNodesFromOriginalWindow);
+            if (mDone) {
+                if (DEBUG) {
+                    Slog.e(LOG_TAG, "Extra callback");
+                }
+                return;
+            }
+            if (mNodesFromOriginalWindow != null) {
+                for (int i = 0; i < mNodesFromOriginalWindow.size(); i++) {
+                    replaceActionsOnInfoLocked(mNodesFromOriginalWindow.get(i));
+                }
+            }
+            recycleReplaceActionNodesLocked();
+            nodesToReturn = (mNodesFromOriginalWindow == null)
+                    ? null : new ArrayList<>(mNodesFromOriginalWindow);
+            mDone = true;
         }
         try {
             mServiceCallback.setFindAccessibilityNodeInfosResult(nodesToReturn, mInteractionId);
@@ -193,31 +193,6 @@
         }
     }
 
-    private void replacePrefetchInfosActionsAndCallService() {
-        final List<AccessibilityNodeInfo> nodesToReturn;
-        synchronized (mLock) {
-            nodesToReturn = replaceActionsLocked(mPrefetchedNodesFromOriginalWindow);
-        }
-        try {
-            mServiceCallback.setPrefetchAccessibilityNodeInfoResult(nodesToReturn, mInteractionId);
-        } catch (RemoteException re) {
-            if (DEBUG) {
-                Slog.e(LOG_TAG, "Failed to setFindAccessibilityNodeInfosResult");
-            }
-        }
-    }
-
-    @GuardedBy("mLock")
-    private List<AccessibilityNodeInfo> replaceActionsLocked(List<AccessibilityNodeInfo> infos) {
-        if (infos != null) {
-            for (int i = 0; i < infos.size(); i++) {
-                replaceActionsOnInfoLocked(infos.get(i));
-            }
-        }
-        return (infos == null)
-                ? null : new ArrayList<>(infos);
-    }
-
     @GuardedBy("mLock")
     private void replaceActionsOnInfoLocked(AccessibilityNodeInfo info) {
         info.removeAllActions();
@@ -229,22 +204,40 @@
         info.setDismissable(false);
         // We currently only replace actions for the root node
         if ((info.getSourceNodeId() == AccessibilityNodeInfo.ROOT_NODE_ID)
-                && mNodeWithReplacementActions != null) {
-            List<AccessibilityAction> actions = mNodeWithReplacementActions.getActionList();
-            if (actions != null) {
-                for (int j = 0; j < actions.size(); j++) {
-                    info.addAction(actions.get(j));
+                && mNodesWithReplacementActions != null) {
+            // This list should always contain a single node with the root ID
+            for (int i = 0; i < mNodesWithReplacementActions.size(); i++) {
+                AccessibilityNodeInfo nodeWithReplacementActions =
+                        mNodesWithReplacementActions.get(i);
+                if (nodeWithReplacementActions.getSourceNodeId()
+                        == AccessibilityNodeInfo.ROOT_NODE_ID) {
+                    List<AccessibilityAction> actions = nodeWithReplacementActions.getActionList();
+                    if (actions != null) {
+                        for (int j = 0; j < actions.size(); j++) {
+                            info.addAction(actions.get(j));
+                        }
+                        // The PIP needs to be able to take accessibility focus
+                        info.addAction(AccessibilityAction.ACTION_ACCESSIBILITY_FOCUS);
+                        info.addAction(AccessibilityAction.ACTION_CLEAR_ACCESSIBILITY_FOCUS);
+                    }
+                    info.setClickable(nodeWithReplacementActions.isClickable());
+                    info.setFocusable(nodeWithReplacementActions.isFocusable());
+                    info.setContextClickable(nodeWithReplacementActions.isContextClickable());
+                    info.setScrollable(nodeWithReplacementActions.isScrollable());
+                    info.setLongClickable(nodeWithReplacementActions.isLongClickable());
+                    info.setDismissable(nodeWithReplacementActions.isDismissable());
                 }
-                // The PIP needs to be able to take accessibility focus
-                info.addAction(AccessibilityAction.ACTION_ACCESSIBILITY_FOCUS);
-                info.addAction(AccessibilityAction.ACTION_CLEAR_ACCESSIBILITY_FOCUS);
             }
-            info.setClickable(mNodeWithReplacementActions.isClickable());
-            info.setFocusable(mNodeWithReplacementActions.isFocusable());
-            info.setContextClickable(mNodeWithReplacementActions.isContextClickable());
-            info.setScrollable(mNodeWithReplacementActions.isScrollable());
-            info.setLongClickable(mNodeWithReplacementActions.isLongClickable());
-            info.setDismissable(mNodeWithReplacementActions.isDismissable());
         }
     }
+
+    @GuardedBy("mLock")
+    private void recycleReplaceActionNodesLocked() {
+        if (mNodesWithReplacementActions == null) return;
+        for (int i = mNodesWithReplacementActions.size() - 1; i >= 0; i--) {
+            AccessibilityNodeInfo nodeWithReplacementAction = mNodesWithReplacementActions.get(i);
+            nodeWithReplacementAction.recycle();
+        }
+        mNodesWithReplacementActions = null;
+    }
 }
diff --git a/services/backup/java/com/android/server/backup/utils/BackupEligibilityRules.java b/services/backup/java/com/android/server/backup/utils/BackupEligibilityRules.java
index 2078492..002f6d7 100644
--- a/services/backup/java/com/android/server/backup/utils/BackupEligibilityRules.java
+++ b/services/backup/java/com/android/server/backup/utils/BackupEligibilityRules.java
@@ -183,7 +183,12 @@
                     } catch (PackageManager.NameNotFoundException e) {
                         Slog.w(TAG, "Failed to read allowAdbBackup property for + "
                                 + packageName);
-                        return false;
+
+                        // This temporarily falls back to the legacy allowBackup flag to
+                        // avoid breaking existing users of adb backup. Once they're able to use
+                        // the new ALLOW_ADB_BACKUP property, we'll return false here.
+                        // TODO(b/176088499): Return false here.
+                        return allowBackup;
                     }
                 } else {
                     // All other apps can use adb backup only when running in debuggable mode.
diff --git a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
index f3d0a2e..70b2672 100644
--- a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
+++ b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
@@ -612,20 +612,25 @@
                         + " for " + association
                         + " - profile still present in " + otherAssociationWithDeviceProfile);
             } else {
-                mRoleManager.removeRoleHolderAsUser(
-                        association.getDeviceProfile(),
-                        association.getPackageName(),
-                        RoleManager.MANAGE_HOLDERS_FLAG_DONT_KILL_APP,
-                        UserHandle.of(association.getUserId()),
-                        getContext().getMainExecutor(),
-                        success -> {
-                            if (!success) {
-                                Log.e(LOG_TAG, "Failed to revoke device profile role "
-                                        + association.getDeviceProfile()
-                                        + " to " + association.getPackageName()
-                                        + " for user " + association.getUserId());
-                            }
-                        });
+                long identity = Binder.clearCallingIdentity();
+                try {
+                    mRoleManager.removeRoleHolderAsUser(
+                            association.getDeviceProfile(),
+                            association.getPackageName(),
+                            RoleManager.MANAGE_HOLDERS_FLAG_DONT_KILL_APP,
+                            UserHandle.of(association.getUserId()),
+                            getContext().getMainExecutor(),
+                            success -> {
+                                if (!success) {
+                                    Log.e(LOG_TAG, "Failed to revoke device profile role "
+                                            + association.getDeviceProfile()
+                                            + " to " + association.getPackageName()
+                                            + " for user " + association.getUserId());
+                                }
+                            });
+                } finally {
+                    Binder.restoreCallingIdentity(identity);
+                }
             }
         }
     }
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 9b99199..01ef69b 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -144,6 +144,7 @@
 import android.os.Handler;
 import android.os.HandlerThread;
 import android.os.IBinder;
+import android.os.INetworkActivityListener;
 import android.os.INetworkManagementService;
 import android.os.Looper;
 import android.os.Message;
@@ -1380,8 +1381,11 @@
             return;
         }
         final String action = blocked ? "BLOCKED" : "UNBLOCKED";
+        final NetworkRequest satisfiedRequest = nri.getSatisfiedRequest();
+        final int requestId =  satisfiedRequest != null
+                ? satisfiedRequest.requestId : nri.mRequests.get(0).requestId;
         mNetworkInfoBlockingLogs.log(String.format(
-                "%s %d(%d) on netId %d", action, nri.mUid, nri.request.requestId, net.getNetId()));
+                "%s %d(%d) on netId %d", action, nri.mUid, requestId, net.getNetId()));
     }
 
     /**
@@ -1709,16 +1713,17 @@
             return newNc;
         }
 
-        Binder.withCleanCallingIdentity(
-                () -> {
-                    if (!mLocationPermissionChecker.checkLocationPermission(
-                            callerPkgName, null /* featureId */, callerUid, null /* message */)) {
-                        // Caller does not have the requisite location permissions. Reset the
-                        // owner's UID in the NetworkCapabilities.
-                        newNc.setOwnerUid(INVALID_UID);
-                    }
-                }
-        );
+        final long token = Binder.clearCallingIdentity();
+        try {
+            if (!mLocationPermissionChecker.checkLocationPermission(
+                    callerPkgName, null /* featureId */, callerUid, null /* message */)) {
+                // Caller does not have the requisite location permissions. Reset the
+                // owner's UID in the NetworkCapabilities.
+                newNc.setOwnerUid(INVALID_UID);
+            }
+        } finally {
+            Binder.restoreCallingIdentity(token);
+        }
 
         return newNc;
     }
@@ -1798,7 +1803,8 @@
 
     private INetworkManagementEventObserver mDataActivityObserver = new BaseNetworkObserver() {
         @Override
-        public void interfaceClassDataActivityChanged(String label, boolean active, long tsNanos) {
+        public void interfaceClassDataActivityChanged(String label, boolean active, long tsNanos,
+                int uid) {
             int deviceType = Integer.parseInt(label);
             sendDataActivityBroadcast(deviceType, active, tsNanos);
         }
@@ -2336,6 +2342,31 @@
     }
 
     /**
+     * Start listening for default data network activity state changes.
+     */
+    @Override
+    public void registerNetworkActivityListener(@NonNull INetworkActivityListener l) {
+        // TODO: Replace network activity listener registry in ConnectivityManager from NMS to here
+    }
+
+    /**
+     * Stop listening for default data network activity state changes.
+     */
+    @Override
+    public void unregisterNetworkActivityListener(@NonNull INetworkActivityListener l) {
+        // TODO: Replace network activity listener registry in ConnectivityManager from NMS to here
+    }
+
+    /**
+     * Check whether the default network radio is currently active.
+     */
+    @Override
+    public boolean isDefaultNetworkActive() {
+        // TODO: Replace isNetworkActive() in NMS.
+        return false;
+    }
+
+    /**
      * Setup data activity tracking for the given network.
      *
      * Every {@code setupDataActivityTracking} should be paired with a
@@ -2705,7 +2736,7 @@
      * Return an array of all current NetworkRequest sorted by request id.
      */
     @VisibleForTesting
-    protected NetworkRequestInfo[] requestsSortedById() {
+    NetworkRequestInfo[] requestsSortedById() {
         NetworkRequestInfo[] requests = new NetworkRequestInfo[0];
         requests = mNetworkRequests.values().toArray(requests);
         // Sort the array based off the NRI containing the min requestId in its requests.
@@ -3555,30 +3586,58 @@
             return false;
         }
         for (NetworkRequestInfo nri : mNetworkRequests.values()) {
-            if (reason == UnneededFor.LINGER && nri.request.isBackgroundRequest()) {
+            if (reason == UnneededFor.LINGER
+                    && !nri.isMultilayerRequest()
+                    && nri.mRequests.get(0).isBackgroundRequest()) {
                 // Background requests don't affect lingering.
                 continue;
             }
 
-            // If this Network is already the highest scoring Network for a request, or if
-            // there is hope for it to become one if it validated, then it is needed.
-            if (nri.request.isRequest() && nai.satisfies(nri.request) &&
-                    (nai.isSatisfyingRequest(nri.request.requestId) ||
-                    // Note that this catches two important cases:
-                    // 1. Unvalidated cellular will not be reaped when unvalidated WiFi
-                    //    is currently satisfying the request.  This is desirable when
-                    //    cellular ends up validating but WiFi does not.
-                    // 2. Unvalidated WiFi will not be reaped when validated cellular
-                    //    is currently satisfying the request.  This is desirable when
-                    //    WiFi ends up validating and out scoring cellular.
-                    nri.mSatisfier.getCurrentScore()
-                            < nai.getCurrentScoreAsValidated())) {
+            if (isNetworkPotentialSatisfier(nai, nri)) {
                 return false;
             }
         }
         return true;
     }
 
+    private boolean isNetworkPotentialSatisfier(
+            @NonNull final NetworkAgentInfo candidate, @NonNull final NetworkRequestInfo nri) {
+        // listen requests won't keep up a network satisfying it. If this is not a multilayer
+        // request, we can return immediately. For multilayer requests, we have to check to see if
+        // any of the multilayer requests may have a potential satisfier.
+        if (!nri.isMultilayerRequest() && nri.mRequests.get(0).isListen()) {
+            return false;
+        }
+        for (final NetworkRequest req : nri.mRequests) {
+            // As non-multilayer listen requests have already returned, the below would only happen
+            // for a multilayer request therefore continue to the next request if available.
+            if (req.isListen()) {
+                continue;
+            }
+            // If this Network is already the highest scoring Network for a request, or if
+            // there is hope for it to become one if it validated, then it is needed.
+            if (candidate.satisfies(req)) {
+                // As soon as a network is found that satisfies a request, return. Specifically for
+                // multilayer requests, returning as soon as a NetworkAgentInfo satisfies a request
+                // is important so as to not evaluate lower priority requests further in
+                // nri.mRequests.
+                final boolean isNetworkNeeded = candidate.isSatisfyingRequest(req.requestId)
+                        // Note that this catches two important cases:
+                        // 1. Unvalidated cellular will not be reaped when unvalidated WiFi
+                        //    is currently satisfying the request.  This is desirable when
+                        //    cellular ends up validating but WiFi does not.
+                        // 2. Unvalidated WiFi will not be reaped when validated cellular
+                        //    is currently satisfying the request.  This is desirable when
+                        //    WiFi ends up validating and out scoring cellular.
+                        || nri.mSatisfier.getCurrentScore()
+                        < candidate.getCurrentScoreAsValidated();
+                return isNetworkNeeded;
+            }
+        }
+
+        return false;
+    }
+
     private NetworkRequestInfo getNriForAppRequest(
             NetworkRequest request, int callingUid, String requestedOperation) {
         final NetworkRequestInfo nri = mNetworkRequests.get(request);
@@ -3875,8 +3934,12 @@
                 new CaptivePortal(new CaptivePortalImpl(network).asBinder()));
         appIntent.setFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT | Intent.FLAG_ACTIVITY_NEW_TASK);
 
-        Binder.withCleanCallingIdentity(() ->
-                mContext.startActivityAsUser(appIntent, UserHandle.CURRENT));
+        final long token = Binder.clearCallingIdentity();
+        try {
+            mContext.startActivityAsUser(appIntent, UserHandle.CURRENT);
+        } finally {
+            Binder.restoreCallingIdentity(token);
+        }
     }
 
     private class CaptivePortalImpl extends ICaptivePortal.Stub {
@@ -5464,6 +5527,10 @@
             this(r, null);
         }
 
+        boolean isMultilayerRequest() {
+            return mRequests.size() > 1;
+        }
+
         private List<NetworkRequest> initializeRequests(NetworkRequest r) {
             final ArrayList<NetworkRequest> tempRequests = new ArrayList<>();
             tempRequests.add(new NetworkRequest(r));
@@ -5505,7 +5572,7 @@
         public void binderDied() {
             log("ConnectivityService NetworkRequestInfo binderDied(" +
                     mRequests + ", " + mBinder + ")");
-            releaseNetworkRequest(mRequests);
+            releaseNetworkRequests(mRequests);
         }
 
         @Override
@@ -5538,13 +5605,15 @@
         mAppOpsManager.checkPackage(callerUid, callerPackageName);
     }
 
-    private ArrayList<Integer> getSignalStrengthThresholds(NetworkAgentInfo nai) {
+    private ArrayList<Integer> getSignalStrengthThresholds(@NonNull final NetworkAgentInfo nai) {
         final SortedSet<Integer> thresholds = new TreeSet<>();
         synchronized (nai) {
-            for (NetworkRequestInfo nri : mNetworkRequests.values()) {
-                if (nri.request.networkCapabilities.hasSignalStrength() &&
-                        nai.satisfiesImmutableCapabilitiesOf(nri.request)) {
-                    thresholds.add(nri.request.networkCapabilities.getSignalStrength());
+            for (final NetworkRequestInfo nri : mNetworkRequests.values()) {
+                for (final NetworkRequest req : nri.mRequests) {
+                    if (req.networkCapabilities.hasSignalStrength()
+                            && nai.satisfiesImmutableCapabilitiesOf(req)) {
+                        thresholds.add(req.networkCapabilities.getSignalStrength());
+                    }
                 }
             }
         }
@@ -5831,7 +5900,7 @@
         return mNextNetworkProviderId.getAndIncrement();
     }
 
-    private void releaseNetworkRequest(List<NetworkRequest> networkRequests) {
+    private void releaseNetworkRequests(List<NetworkRequest> networkRequests) {
         for (int i = 0; i < networkRequests.size(); i++) {
             releaseNetworkRequest(networkRequests.get(i));
         }
@@ -7763,10 +7832,13 @@
 
         final int userId = UserHandle.getCallingUserId();
 
-        Binder.withCleanCallingIdentity(() -> {
+        final long token = Binder.clearCallingIdentity();
+        try {
             final IpMemoryStore ipMemoryStore = IpMemoryStore.getMemoryStore(mContext);
             ipMemoryStore.factoryReset();
-        });
+        } finally {
+            Binder.restoreCallingIdentity(token);
+        }
 
         // Turn airplane mode off
         setAirplaneMode(false);
diff --git a/services/core/java/com/android/server/IntentResolver.java b/services/core/java/com/android/server/IntentResolver.java
index dbf179a..ea1ac0c 100644
--- a/services/core/java/com/android/server/IntentResolver.java
+++ b/services/core/java/com/android/server/IntentResolver.java
@@ -839,6 +839,17 @@
         }
     };
 
+    // Make <this> a copy of <orig>.  The presumption is that <this> is empty.
+    protected void doCopy(IntentResolver orig) {
+        mFilters.addAll(orig.mFilters);
+        mTypeToFilter.putAll(orig.mTypeToFilter);
+        mBaseTypeToFilter.putAll(orig.mBaseTypeToFilter);
+        mWildTypeToFilter.putAll(orig.mWildTypeToFilter);
+        mSchemeToFilter.putAll(orig.mSchemeToFilter);
+        mActionToFilter.putAll(orig.mActionToFilter);
+        mTypedActionToFilter.putAll(orig.mTypedActionToFilter);
+    }
+
     /**
      * All filters that have been registered.
      */
diff --git a/services/core/java/com/android/server/NetworkManagementService.java b/services/core/java/com/android/server/NetworkManagementService.java
index 636da6f..d30adf1 100644
--- a/services/core/java/com/android/server/NetworkManagementService.java
+++ b/services/core/java/com/android/server/NetworkManagementService.java
@@ -396,22 +396,12 @@
      * Notify our observers of a change in the data activity state of the interface
      */
     private void notifyInterfaceClassActivity(int type, boolean isActive, long tsNanos,
-            int uid, boolean fromRadio) {
+            int uid) {
         final boolean isMobile = ConnectivityManager.isNetworkTypeMobile(type);
         int powerState = isActive
                 ? DataConnectionRealTimeInfo.DC_POWER_STATE_HIGH
                 : DataConnectionRealTimeInfo.DC_POWER_STATE_LOW;
         if (isMobile) {
-            if (!fromRadio) {
-                if (mMobileActivityFromRadio) {
-                    // If this call is not coming from a report from the radio itself, but we
-                    // have previously received reports from the radio, then we will take the
-                    // power state to just be whatever the radio last reported.
-                    powerState = mLastPowerStateFromRadio;
-                }
-            } else {
-                mMobileActivityFromRadio = true;
-            }
             if (mLastPowerStateFromRadio != powerState) {
                 mLastPowerStateFromRadio = powerState;
                 try {
@@ -431,15 +421,9 @@
             }
         }
 
-        if (!isMobile || fromRadio || !mMobileActivityFromRadio) {
-            // Report the change in data activity.  We don't do this if this is a change
-            // on the mobile network, that is not coming from the radio itself, and we
-            // have previously seen change reports from the radio.  In that case only
-            // the radio is the authority for the current state.
-            final boolean active = isActive;
-            invokeForAllObservers(o -> o.interfaceClassDataActivityChanged(
-                    Integer.toString(type), active, tsNanos));
-        }
+        final boolean active = isActive;
+        invokeForAllObservers(o -> o.interfaceClassDataActivityChanged(
+                Integer.toString(type), active, tsNanos, uid));
 
         boolean report = false;
         synchronized (mIdleTimerLock) {
@@ -671,7 +655,7 @@
                 timestampNanos = timestamp;
             }
             mDaemonHandler.post(() ->
-                    notifyInterfaceClassActivity(label, isActive, timestampNanos, uid, false));
+                    notifyInterfaceClassActivity(label, isActive, timestampNanos, uid));
         }
 
         @Override
@@ -1157,7 +1141,7 @@
                 mNetworkActive = false;
             }
             mDaemonHandler.post(() -> notifyInterfaceClassActivity(type, true,
-                    SystemClock.elapsedRealtimeNanos(), -1, false));
+                    SystemClock.elapsedRealtimeNanos(), -1));
         }
     }
 
@@ -1181,7 +1165,7 @@
             }
             mActiveIdleTimers.remove(iface);
             mDaemonHandler.post(() -> notifyInterfaceClassActivity(params.type, false,
-                    SystemClock.elapsedRealtimeNanos(), -1, false));
+                    SystemClock.elapsedRealtimeNanos(), -1));
         }
     }
 
diff --git a/services/core/java/com/android/server/TestNetworkService.java b/services/core/java/com/android/server/TestNetworkService.java
index 655d8ab..e8687e5 100644
--- a/services/core/java/com/android/server/TestNetworkService.java
+++ b/services/core/java/com/android/server/TestNetworkService.java
@@ -107,23 +107,23 @@
 
         String ifacePrefix = isTun ? TEST_TUN_PREFIX : TEST_TAP_PREFIX;
         String iface = ifacePrefix + sTestTunIndex.getAndIncrement();
-        return Binder.withCleanCallingIdentity(
-                () -> {
-                    try {
-                        ParcelFileDescriptor tunIntf =
-                                ParcelFileDescriptor.adoptFd(jniCreateTunTap(isTun, iface));
-                        for (LinkAddress addr : linkAddrs) {
-                            mNetd.interfaceAddAddress(
-                                    iface,
-                                    addr.getAddress().getHostAddress(),
-                                    addr.getPrefixLength());
-                        }
+        final long token = Binder.clearCallingIdentity();
+        try {
+            ParcelFileDescriptor tunIntf =
+                    ParcelFileDescriptor.adoptFd(jniCreateTunTap(isTun, iface));
+            for (LinkAddress addr : linkAddrs) {
+                mNetd.interfaceAddAddress(
+                        iface,
+                        addr.getAddress().getHostAddress(),
+                        addr.getPrefixLength());
+            }
 
-                        return new TestNetworkInterface(tunIntf, iface);
-                    } catch (RemoteException e) {
-                        throw e.rethrowFromSystemServer();
-                    }
-                });
+            return new TestNetworkInterface(tunIntf, iface);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        } finally {
+            Binder.restoreCallingIdentity(token);
+        }
     }
 
     /**
@@ -317,7 +317,12 @@
 
         try {
             // This requires NETWORK_STACK privileges.
-            Binder.withCleanCallingIdentity(() -> mNMS.setInterfaceUp(iface));
+            final long token = Binder.clearCallingIdentity();
+            try {
+                mNMS.setInterfaceUp(iface);
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
 
             // Synchronize all accesses to mTestNetworkTracker to prevent the case where:
             // 1. TestNetworkAgent successfully binds to death of binder
diff --git a/services/core/java/com/android/server/VcnManagementService.java b/services/core/java/com/android/server/VcnManagementService.java
index 165b6a1..74e3851 100644
--- a/services/core/java/com/android/server/VcnManagementService.java
+++ b/services/core/java/com/android/server/VcnManagementService.java
@@ -25,24 +25,44 @@
 import android.net.NetworkRequest;
 import android.net.vcn.IVcnManagementService;
 import android.net.vcn.VcnConfig;
+import android.os.Binder;
+import android.os.Handler;
 import android.os.HandlerThread;
 import android.os.Looper;
 import android.os.ParcelUuid;
+import android.os.PersistableBundle;
+import android.os.Process;
+import android.os.ServiceSpecificException;
+import android.os.UserHandle;
+import android.telephony.SubscriptionInfo;
+import android.telephony.SubscriptionManager;
+import android.telephony.TelephonyManager;
+import android.util.ArrayMap;
+import android.util.Slog;
 
+import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.annotations.VisibleForTesting.Visibility;
+import com.android.server.vcn.util.PersistableBundleUtils;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
 
 /**
  * VcnManagementService manages Virtual Carrier Network profiles and lifecycles.
  *
  * <pre>The internal structure of the VCN Management subsystem is as follows:
  *
- * +------------------------+ 1:1                                 +--------------------------------+
- * |  VcnManagementService  | ------------ Creates -------------> |  TelephonySubscriptionManager  |
- * |                        |                                     |                                |
- * | Manages configs and    |                                     | Tracks subscriptions, carrier  |
- * | VcnInstance lifecycles | <--- Notifies of subscription & --- | privilege changes, caches maps |
- * +------------------------+      carrier privilege changes      +--------------------------------+
+ * +-------------------------+ 1:1                                +--------------------------------+
+ * |  VcnManagementService   | ------------ Creates ------------> |  TelephonySubscriptionManager  |
+ * |                         |                                    |                                |
+ * |   Manages configs and   |                                    | Tracks subscriptions, carrier  |
+ * | Vcn instance lifecycles | <--- Notifies of subscription & -- | privilege changes, caches maps |
+ * +-------------------------+      carrier privilege changes     +--------------------------------+
  *      | 1:N          ^
  *      |              |
  *      |              +-------------------------------+
@@ -54,19 +74,19 @@
  *                      |                      mode state changes
  *                      v                              |
  * +-----------------------------------------------------------------------+
- * |                              VcnInstance                              |
+ * |                                  Vcn                                  |
  * |                                                                       |
- * |   Manages tunnel lifecycles based on fulfillable NetworkRequest(s)    |
- * |                        and overall safe-mode                          |
+ * |       Manages GatewayConnection lifecycles based on fulfillable       |
+ * |                NetworkRequest(s) and overall safe-mode                |
  * +-----------------------------------------------------------------------+
  *                      | 1:N                          ^
  *              Creates to fulfill                     |
- *           NetworkRequest(s), tears        Notifies of VcnTunnel
+ *           NetworkRequest(s), tears   Notifies of VcnGatewayConnection
  *          down when no longer needed   teardown (e.g. Network reaped)
  *                      |                 and safe-mode timer changes
  *                      v                              |
  * +-----------------------------------------------------------------------+
- * |                               VcnTunnel                               |
+ * |                          VcnGatewayConnection                         |
  * |                                                                       |
  * |       Manages a single (IKEv2) tunnel session and NetworkAgent,       |
  * |  handles mobility events, (IPsec) Tunnel setup and safe-mode timers   |
@@ -92,20 +112,72 @@
 
     public static final boolean VDBG = false; // STOPSHIP: if true
 
+    @VisibleForTesting(visibility = Visibility.PRIVATE)
+    static final String VCN_CONFIG_FILE = "/data/system/vcn/configs.xml";
+
     /* Binder context for this service */
     @NonNull private final Context mContext;
     @NonNull private final Dependencies mDeps;
 
     @NonNull private final Looper mLooper;
+    @NonNull private final Handler mHandler;
     @NonNull private final VcnNetworkProvider mNetworkProvider;
 
+    @GuardedBy("mLock")
+    @NonNull
+    private final Map<ParcelUuid, VcnConfig> mConfigs = new ArrayMap<>();
+
+    @NonNull private final Object mLock = new Object();
+
+    @NonNull private final PersistableBundleUtils.LockingReadWriteHelper mConfigDiskRwHelper;
+
     @VisibleForTesting(visibility = Visibility.PRIVATE)
     VcnManagementService(@NonNull Context context, @NonNull Dependencies deps) {
         mContext = requireNonNull(context, "Missing context");
         mDeps = requireNonNull(deps, "Missing dependencies");
 
         mLooper = mDeps.getLooper();
+        mHandler = new Handler(mLooper);
         mNetworkProvider = new VcnNetworkProvider(mContext, mLooper);
+
+        mConfigDiskRwHelper = mDeps.newPersistableBundleLockingReadWriteHelper(VCN_CONFIG_FILE);
+
+        // Run on handler to ensure I/O does not block system server startup
+        mHandler.post(() -> {
+            PersistableBundle configBundle = null;
+            try {
+                configBundle = mConfigDiskRwHelper.readFromDisk();
+            } catch (IOException e1) {
+                Slog.e(TAG, "Failed to read configs from disk; retrying", e1);
+
+                // Retry immediately. The IOException may have been transient.
+                try {
+                    configBundle = mConfigDiskRwHelper.readFromDisk();
+                } catch (IOException e2) {
+                    Slog.wtf(TAG, "Failed to read configs from disk", e2);
+                    return;
+                }
+            }
+
+            if (configBundle != null) {
+                final Map<ParcelUuid, VcnConfig> configs =
+                        PersistableBundleUtils.toMap(
+                                configBundle,
+                                PersistableBundleUtils::toParcelUuid,
+                                VcnConfig::new);
+
+                synchronized (mLock) {
+                    for (Entry<ParcelUuid, VcnConfig> entry : configs.entrySet()) {
+                        // Ensure no new configs are overwritten; a carrier app may have added a new
+                        // config.
+                        if (!mConfigs.containsKey(entry.getKey())) {
+                            mConfigs.put(entry.getKey(), entry.getValue());
+                        }
+                    }
+                    // TODO: Trigger re-evaluation of active VCNs; start/stop VCNs as needed.
+                }
+            }
+        });
     }
 
     // Package-visibility for SystemServer to create instances.
@@ -130,16 +202,81 @@
             }
             return mHandlerThread.getLooper();
         }
+
+        /**
+         * Retrieves the caller's UID
+         *
+         * <p>This call MUST be made before calling {@link Binder#clearCallingIdentity}, otherwise
+         * this will not work properly.
+         *
+         * @return
+         */
+        public int getBinderCallingUid() {
+            return Binder.getCallingUid();
+        }
+
+        /**
+         * Creates and returns a new {@link PersistableBundle.LockingReadWriteHelper}
+         *
+         * @param path the file path to read/write from/to.
+         * @return the {@link PersistableBundleUtils.LockingReadWriteHelper} instance
+         */
+        public PersistableBundleUtils.LockingReadWriteHelper
+                newPersistableBundleLockingReadWriteHelper(@NonNull String path) {
+            return new PersistableBundleUtils.LockingReadWriteHelper(path);
+        }
     }
 
     /** Notifies the VcnManagementService that external dependencies can be set up. */
     public void systemReady() {
-        // TODO: Retrieve existing profiles from KeyStore
-
         mContext.getSystemService(ConnectivityManager.class)
                 .registerNetworkProvider(mNetworkProvider);
     }
 
+    private void enforcePrimaryUser() {
+        final int uid = mDeps.getBinderCallingUid();
+        if (uid == Process.SYSTEM_UID) {
+            throw new IllegalStateException(
+                    "Calling identity was System Server. Was Binder calling identity cleared?");
+        }
+
+        if (!UserHandle.getUserHandleForUid(uid).isSystem()) {
+            throw new SecurityException(
+                    "VcnManagementService can only be used by callers running as the primary user");
+        }
+    }
+
+    private void enforceCallingUserAndCarrierPrivilege(ParcelUuid subscriptionGroup) {
+        // Only apps running in the primary (system) user are allowed to configure the VCN. This is
+        // in line with Telephony's behavior with regards to binding to a Carrier App provided
+        // CarrierConfigService.
+        enforcePrimaryUser();
+
+        // TODO (b/172619301): Check based on events propagated from CarrierPrivilegesTracker
+        final SubscriptionManager subMgr = mContext.getSystemService(SubscriptionManager.class);
+        final List<SubscriptionInfo> subscriptionInfos = new ArrayList<>();
+        Binder.withCleanCallingIdentity(
+                () -> {
+                    subscriptionInfos.addAll(subMgr.getSubscriptionsInGroup(subscriptionGroup));
+                });
+
+        final TelephonyManager telMgr = mContext.getSystemService(TelephonyManager.class);
+        for (SubscriptionInfo info : subscriptionInfos) {
+            // Check subscription is active first; much cheaper/faster check, and an app (currently)
+            // cannot be carrier privileged for inactive subscriptions.
+            if (subMgr.isValidSlotIndex(info.getSimSlotIndex())
+                    && telMgr.hasCarrierPrivileges(info.getSubscriptionId())) {
+                // TODO (b/173717728): Allow configuration for inactive, but manageable
+                // subscriptions.
+                // TODO (b/173718661): Check for whole subscription groups at a time.
+                return;
+            }
+        }
+
+        throw new SecurityException(
+                "Carrier privilege required for subscription group to set VCN Config");
+    }
+
     /**
      * Sets a VCN config for a given subscription group.
      *
@@ -150,7 +287,17 @@
         requireNonNull(subscriptionGroup, "subscriptionGroup was null");
         requireNonNull(config, "config was null");
 
-        // TODO: Store VCN configuration, trigger startup as necessary
+        enforceCallingUserAndCarrierPrivilege(subscriptionGroup);
+
+        synchronized (mLock) {
+            mConfigs.put(subscriptionGroup, config);
+
+            // Must be done synchronously to ensure that writes do not happen out-of-order.
+            writeConfigsToDiskLocked();
+        }
+
+        // TODO: Clear Binder calling identity
+        // TODO: Trigger startup as necessary
     }
 
     /**
@@ -162,7 +309,40 @@
     public void clearVcnConfig(@NonNull ParcelUuid subscriptionGroup) {
         requireNonNull(subscriptionGroup, "subscriptionGroup was null");
 
-        // TODO: Clear VCN configuration, trigger teardown as necessary
+        enforceCallingUserAndCarrierPrivilege(subscriptionGroup);
+
+        synchronized (mLock) {
+            mConfigs.remove(subscriptionGroup);
+
+            // Must be done synchronously to ensure that writes do not happen out-of-order.
+            writeConfigsToDiskLocked();
+        }
+
+        // TODO: Clear Binder calling identity
+        // TODO: Trigger teardown as necessary
+    }
+
+    @GuardedBy("mLock")
+    private void writeConfigsToDiskLocked() {
+        try {
+            PersistableBundle bundle =
+                    PersistableBundleUtils.fromMap(
+                            mConfigs,
+                            PersistableBundleUtils::fromParcelUuid,
+                            VcnConfig::toPersistableBundle);
+            mConfigDiskRwHelper.writeToDisk(bundle);
+        } catch (IOException e) {
+            Slog.e(TAG, "Failed to save configs to disk", e);
+            throw new ServiceSpecificException(0, "Failed to save configs");
+        }
+    }
+
+    /** Get current configuration list for testing purposes */
+    @VisibleForTesting(visibility = Visibility.PRIVATE)
+    Map<ParcelUuid, VcnConfig> getConfigs() {
+        synchronized (mLock) {
+            return Collections.unmodifiableMap(mConfigs);
+        }
     }
 
     /**
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index a2b6304..5fde046 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -168,6 +168,7 @@
     public static final int FGS_FEATURE_ALLOWED_BY_FGS_BINDING = 17;
     public static final int FGS_FEATURE_ALLOWED_BY_DEVICE_DEMO_MODE = 18;
     public static final int FGS_FEATURE_ALLOWED_BY_PROCESS_RECORD = 19;
+    public static final int FGS_FEATURE_ALLOWED_BY_EXEMPTED_PACKAGES = 20;
 
     @IntDef(flag = true, prefix = { "FGS_FEATURE_" }, value = {
             FGS_FEATURE_DENIED,
@@ -188,7 +189,8 @@
             FGS_FEATURE_ALLOWED_BY_SYSTEM_ALERT_WINDOW_PERMISSION,
             FGS_FEATURE_ALLOWED_BY_FGS_BINDING,
             FGS_FEATURE_ALLOWED_BY_DEVICE_DEMO_MODE,
-            FGS_FEATURE_ALLOWED_BY_PROCESS_RECORD
+            FGS_FEATURE_ALLOWED_BY_PROCESS_RECORD,
+            FGS_FEATURE_ALLOWED_BY_EXEMPTED_PACKAGES,
     })
     @Retention(RetentionPolicy.SOURCE)
     public @interface FgsFeatureRetCode {}
@@ -275,6 +277,13 @@
     static final long FGS_BG_START_RESTRICTION_CHANGE_ID = 170668199L;
 
     /**
+     * If set to false for a package, the system will *not* exempt it from FGS-BG-start,
+     * even if it's in {#code ActiveServices.sFgsBgStartExemptedPackages}.
+     */
+    @ChangeId
+    static final long FGS_BG_START_USE_EXEMPTION_LIST_CHANGE_ID = 175801883;
+
+    /**
      * If a service can not become foreground service due to BG-FGS-launch restriction or other
      * reasons, throws an IllegalStateException.
      */
@@ -282,6 +291,25 @@
     @EnabledSince(targetSdkVersion = android.os.Build.VERSION_CODES.S)
     static final long FGS_START_EXCEPTION_CHANGE_ID = 174041399L;
 
+    /**
+     * Special allowlist that contains packages that are allowed to start FGS even if they target S,
+     * without using START_FOREGROUND_SERVICES_FROM_BACKGROUND.
+     *
+     * Note: we exempt FGS starts if either the "callee" or "caller" match any of the emempted
+     * packages. This means:
+     * - Exempted apps could call Context.startForegroundService() for services owned by any other
+     *   apps.
+     * - Any apps could call Context.startForegroundService() for services owned by any exempted
+     *   apps.
+     * And the call would succeed.
+     */
+    private static final ArraySet<String> sFgsBgStartExemptedPackages = new ArraySet<>();
+
+    static {
+        sFgsBgStartExemptedPackages.add("com.google.pixel.exo.bootstrapping"); //STOPSHIP Remove it.
+        sFgsBgStartExemptedPackages.add("com.android.chrome"); // STOPSHIP Remove it.
+    }
+
     final Runnable mLastAnrDumpClearer = new Runnable() {
         @Override public void run() {
             synchronized (mAm) {
@@ -1672,13 +1700,12 @@
     // TODO: remove as part of fixing b/173627642
     @SuppressWarnings("AndroidFrameworkCompatChange")
     private void postFgsNotificationLocked(ServiceRecord r) {
-        final boolean isLegacyApp = (r.appInfo.targetSdkVersion < Build.VERSION_CODES.S);
         boolean showNow = !mAm.mConstants.mFlagFgsNotificationDeferralEnabled;
         if (!showNow) {
             // Legacy apps' FGS notifications are not deferred unless the relevant
             // DeviceConfig element has been set
             showNow = mAm.mConstants.mFlagFgsNotificationDeferralApiGated
-                    && isLegacyApp;
+                    && r.appInfo.targetSdkVersion < Build.VERSION_CODES.S;
         }
         if (!showNow) {
             // is the notification such that it should show right away?
@@ -1733,11 +1760,6 @@
             Slog.d(TAG_SERVICE, "FGS " + r
                     + " notification in " + (when - now) + " ms");
         }
-        if (isLegacyApp) {
-            Slog.i(TAG_SERVICE, "Deferring FGS notification in legacy app "
-                    + r.appInfo.packageName + "/" + UserHandle.formatUid(r.appInfo.uid)
-                    + " : " + r.foregroundNoti);
-        }
         mAm.mHandler.postAtTime(mPostDeferredFGSNotifications, when);
     }
 
@@ -1761,7 +1783,7 @@
                         // The service might have been stopped or exited foreground state
                         // in the interval, so we lazy check whether we still need to show
                         // the notification.
-                        if (r.isForeground) {
+                        if (r.isForeground && r.app != null) {
                             r.postNotification();
                         } else if (DEBUG_FOREGROUND_SERVICE) {
                             Slog.d(TAG_SERVICE, "  - service no longer running/fg, ignoring");
@@ -5310,6 +5332,14 @@
             }
         }
 
+        // NOTE this should always be the last check.
+        if (ret == FGS_FEATURE_DENIED) {
+            if (isPackageExemptedFromFgsRestriction(r.appInfo.packageName, r.appInfo.uid)
+                    || isPackageExemptedFromFgsRestriction(callingPackage, callingUid)) {
+                ret = FGS_FEATURE_ALLOWED_BY_EXEMPTED_PACKAGES;
+            }
+        }
+
         final String debugInfo =
                 "[callingPackage: " + callingPackage
                         + "; callingUid: " + callingUid
@@ -5327,6 +5357,13 @@
         return ret;
     }
 
+    private boolean isPackageExemptedFromFgsRestriction(String packageName, int uid) {
+        if (!sFgsBgStartExemptedPackages.contains(packageName)) {
+            return false;
+        }
+        return CompatChanges.isChangeEnabled(FGS_BG_START_USE_EXEMPTION_LIST_CHANGE_ID, uid);
+    }
+
     private static String fgsCodeToString(@FgsFeatureRetCode int code) {
         switch (code) {
             case FGS_FEATURE_DENIED:
@@ -5367,6 +5404,8 @@
                 return "ALLOWED_BY_DEVICE_DEMO_MODE";
             case FGS_FEATURE_ALLOWED_BY_PROCESS_RECORD:
                 return "ALLOWED_BY_PROCESS_RECORD";
+            case FGS_FEATURE_ALLOWED_BY_EXEMPTED_PACKAGES:
+                return "FGS_FEATURE_ALLOWED_BY_EXEMPTED_PACKAGES";
             default:
                 return "";
         }
diff --git a/services/core/java/com/android/server/am/ActivityManagerConstants.java b/services/core/java/com/android/server/am/ActivityManagerConstants.java
index 6892ef7..b0f296f 100644
--- a/services/core/java/com/android/server/am/ActivityManagerConstants.java
+++ b/services/core/java/com/android/server/am/ActivityManagerConstants.java
@@ -370,9 +370,9 @@
     volatile boolean mFlagFgsNotificationDeferralEnabled = true;
 
     // Restrict FGS notification deferral policy to only those apps that target
-    // API version S or higher.  Disabled by default; set to "true" to force
-    // legacy app FGS notifications to display immediately in all cases.
-    volatile boolean mFlagFgsNotificationDeferralApiGated = false;
+    // API version S or higher.  Enabled by default; set to "false" to defer FGS
+    // notifications from legacy apps as well.
+    volatile boolean mFlagFgsNotificationDeferralApiGated = true;
 
     // Time in milliseconds to defer FGS notifications after their transition to
     // the foreground state.
@@ -806,7 +806,7 @@
         mFlagFgsNotificationDeferralApiGated = DeviceConfig.getBoolean(
                 DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
                 KEY_DEFERRED_FGS_NOTIFICATIONS_API_GATED,
-                /*default value*/ false);
+                /*default value*/ true);
     }
 
     private void updateFgsNotificationDeferralInterval() {
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 7fb0bda..1841d67 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -11247,6 +11247,10 @@
                 // set on ION VMAs, therefore consider the entire ION heap as used kernel memory
                 kernelUsed += ionHeap;
             }
+            final long gpuUsage = Debug.getGpuTotalUsageKb();
+            if (gpuUsage >= 0) {
+                pw.print("      GPU: "); pw.println(stringifyKBSize(gpuUsage));
+            }
             final long lostRAM = memInfo.getTotalSizeKb()
                     - (ss[INDEX_TOTAL_PSS] - ss[INDEX_TOTAL_SWAP_PSS])
                     - memInfo.getFreeSizeKb() - memInfo.getCachedSizeKb()
@@ -12041,6 +12045,12 @@
             // set on ION VMAs, therefore consider the entire ION heap as used kernel memory
             kernelUsed += ionHeap;
         }
+        final long gpuUsage = Debug.getGpuTotalUsageKb();
+        if (gpuUsage >= 0) {
+            memInfoBuilder.append("       GPU: ");
+            memInfoBuilder.append(stringifyKBSize(gpuUsage));
+            memInfoBuilder.append("\n");
+        }
         memInfoBuilder.append("  Used RAM: ");
         memInfoBuilder.append(stringifyKBSize(
                                   totalPss - cachedPss + kernelUsed));
diff --git a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
index 12fe3ed..fffa814 100644
--- a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
+++ b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
@@ -2928,6 +2928,7 @@
         final PlatformCompat platformCompat = (PlatformCompat)
                 ServiceManager.getService(Context.PLATFORM_COMPAT_SERVICE);
         String toggleValue = getNextArgRequired();
+        boolean killPackage = !"--no-kill".equals(getNextOption());
         boolean toggleAll = false;
         int targetSdkVersion = -1;
         long changeId = -1;
@@ -2979,7 +2980,11 @@
                         CompatibilityChangeConfig overrides =
                                 new CompatibilityChangeConfig(
                                         new Compatibility.ChangeConfig(enabled, disabled));
-                        platformCompat.setOverrides(overrides, packageName);
+                        if (killPackage) {
+                            platformCompat.setOverrides(overrides, packageName);
+                        } else {
+                            platformCompat.setOverridesForTest(overrides, packageName);
+                        }
                         pw.println("Enabled change " + changeId + " for " + packageName + ".");
                     }
                     return 0;
@@ -2998,13 +3003,21 @@
                         CompatibilityChangeConfig overrides =
                                 new CompatibilityChangeConfig(
                                         new Compatibility.ChangeConfig(enabled, disabled));
-                        platformCompat.setOverrides(overrides, packageName);
+                        if (killPackage) {
+                            platformCompat.setOverrides(overrides, packageName);
+                        } else {
+                            platformCompat.setOverridesForTest(overrides, packageName);
+                        }
                         pw.println("Disabled change " + changeId + " for " + packageName + ".");
                     }
                     return 0;
                 case "reset":
                     if (toggleAll) {
-                        platformCompat.clearOverrides(packageName);
+                        if (killPackage) {
+                            platformCompat.clearOverrides(packageName);
+                        } else {
+                            platformCompat.clearOverridesForTest(packageName);
+                        }
                         pw.println("Reset all changes for " + packageName + " to default value.");
                         return 0;
                     }
@@ -3410,15 +3423,18 @@
             pw.println("  write");
             pw.println("      Write all pending state to storage.");
             pw.println("  compat [COMMAND] [...]: sub-commands for toggling app-compat changes.");
-            pw.println("         enable|disable|reset <CHANGE_ID|CHANGE_NAME> <PACKAGE_NAME>");
+            pw.println("         enable|disable [--no-kill] <CHANGE_ID|CHANGE_NAME> <PACKAGE_NAME>");
+            pw.println("            Toggles a change either by id or by name for <PACKAGE_NAME>.");
+            pw.println("            It kills <PACKAGE_NAME> (to allow the toggle to take effect) unless --no-kill is provided.");
+            pw.println("         reset <CHANGE_ID|CHANGE_NAME> <PACKAGE_NAME>");
             pw.println("            Toggles a change either by id or by name for <PACKAGE_NAME>.");
             pw.println("            It kills <PACKAGE_NAME> (to allow the toggle to take effect).");
-            pw.println("         enable-all|disable-all <targetSdkVersion> <PACKAGE_NAME");
+            pw.println("         enable-all|disable-all <targetSdkVersion> <PACKAGE_NAME>");
             pw.println("            Toggles all changes that are gated by <targetSdkVersion>.");
-            pw.println("         reset-all <PACKAGE_NAME>");
+            pw.println("         reset-all [--no-kill] <PACKAGE_NAME>");
             pw.println("            Removes all existing overrides for all changes for ");
             pw.println("            <PACKAGE_NAME> (back to default behaviour).");
-            pw.println("            It kills <PACKAGE_NAME> (to allow the toggle to take effect).");
+            pw.println("            It kills <PACKAGE_NAME> (to allow the toggle to take effect) unless --no-kill is provided.");
             pw.println("  memory-factor [command] [...]: sub-commands for overriding memory pressure factor");
             pw.println("         set <NORMAL|MODERATE|LOW|CRITICAL>");
             pw.println("            Overrides memory pressure factor. May also supply a raw int level");
diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java
index 82e9b46..2f7c523 100644
--- a/services/core/java/com/android/server/am/BatteryStatsService.java
+++ b/services/core/java/com/android/server/am/BatteryStatsService.java
@@ -254,9 +254,7 @@
         mHandler = new Handler(mHandlerThread.getLooper());
 
         // TODO(b/173077356): Replace directly calling the HAL with PowerStatsService queries
-        // Make sure to init Hal Wrapper before creating BatteryStatsImpl.
-        mPowerStatsHALWrapper = new PowerStatsHALWrapper.PowerStatsHALWrapperImpl();
-        mPowerStatsHALWrapper.initialize();
+        mPowerStatsHALWrapper = PowerStatsHALWrapper.getPowerStatsHalImpl();
 
         final MeasuredEnergyArray initialEnergies = getEnergyConsumptionData();
         final boolean[] supportedBuckets = getSupportedEnergyBuckets(initialEnergies);
@@ -267,8 +265,6 @@
         mStats.setRadioScanningTimeoutLocked(mContext.getResources().getInteger(
                 com.android.internal.R.integer.config_radioScanningTimeout) * 1000L);
         mStats.setPowerProfileLocked(new PowerProfile(context));
-        mStats.startTrackingSystemServerCpuTime();
-
         mBatteryUsageStatsProvider = new BatteryUsageStatsProvider(context, mStats);
     }
 
diff --git a/services/core/java/com/android/server/audio/AudioDeviceBroker.java b/services/core/java/com/android/server/audio/AudioDeviceBroker.java
index 3b407f1..26f5c4c 100644
--- a/services/core/java/com/android/server/audio/AudioDeviceBroker.java
+++ b/services/core/java/com/android/server/audio/AudioDeviceBroker.java
@@ -16,6 +16,7 @@
 package com.android.server.audio;
 
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.bluetooth.BluetoothA2dp;
 import android.bluetooth.BluetoothDevice;
 import android.bluetooth.BluetoothHeadset;
@@ -31,14 +32,17 @@
 import android.media.AudioSystem;
 import android.media.IAudioRoutesObserver;
 import android.media.ICapturePresetDevicesRoleDispatcher;
+import android.media.ICommunicationDeviceDispatcher;
 import android.media.IStrategyPreferredDevicesDispatcher;
 import android.media.MediaMetrics;
+import android.media.audiopolicy.AudioProductStrategy;
 import android.os.Binder;
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.Looper;
 import android.os.Message;
 import android.os.PowerManager;
+import android.os.RemoteCallbackList;
 import android.os.RemoteException;
 import android.os.SystemClock;
 import android.os.UserHandle;
@@ -49,6 +53,7 @@
 import com.android.internal.annotations.GuardedBy;
 
 import java.io.PrintWriter;
+import java.util.Arrays;
 import java.util.HashSet;
 import java.util.LinkedList;
 import java.util.List;
@@ -75,7 +80,8 @@
     private final @NonNull Context mContext;
 
     /** Forced device usage for communications sent to AudioSystem */
-    private int mForcedUseForComm;
+    private AudioDeviceAttributes mPreferredDeviceforComm;
+    private int mCommunicationStrategyId = -1;
 
     // Manages all connected devices, only ever accessed on the message loop
     private final AudioDeviceInventory mDeviceInventory;
@@ -131,10 +137,23 @@
         init();
     }
 
+    private void initCommunicationStrategyId() {
+        List<AudioProductStrategy> strategies = AudioProductStrategy.getAudioProductStrategies();
+        for (AudioProductStrategy strategy : strategies) {
+            if (strategy.getAudioAttributesForLegacyStreamType(AudioSystem.STREAM_VOICE_CALL)
+                    != null) {
+                mCommunicationStrategyId = strategy.getId();
+                return;
+            }
+        }
+        mCommunicationStrategyId = -1;
+    }
+
     private void init() {
         setupMessaging(mContext);
 
-        mForcedUseForComm = AudioSystem.FORCE_NONE;
+        mPreferredDeviceforComm = null;
+        initCommunicationStrategyId();
     }
 
     /*package*/ Context getContext() {
@@ -219,8 +238,7 @@
             synchronized (mDeviceStateLock) {
                 AudioDeviceAttributes device = null;
                 if (on) {
-                    device = new AudioDeviceAttributes(AudioDeviceAttributes.ROLE_OUTPUT,
-                            AudioDeviceInfo.TYPE_BUILTIN_SPEAKER, "");
+                    device = new AudioDeviceAttributes(AudioSystem.DEVICE_OUT_SPEAKER, "");
                 } else {
                     CommunicationRouteClient client = getCommunicationRouteClientForPid(pid);
                     if (client == null || !client.requestsSpeakerphone()) {
@@ -233,6 +251,38 @@
         }
     }
 
+    /**
+     * Select device for use for communication use cases.
+     * @param cb Client binder for death detection
+     * @param pid Client pid
+     * @param device Device selected or null to unselect.
+     * @param eventSource for logging purposes
+     */
+    /*package*/ boolean setDeviceForCommunication(
+            IBinder cb, int pid, AudioDeviceInfo device, String eventSource) {
+
+        if (AudioService.DEBUG_COMM_RTE) {
+            Log.v(TAG, "setDeviceForCommunication, device: " + device + ", pid: " + pid);
+        }
+
+        synchronized (mSetModeLock) {
+            synchronized (mDeviceStateLock) {
+                AudioDeviceAttributes deviceAttr = null;
+                if (device != null) {
+                    deviceAttr = new AudioDeviceAttributes(device);
+                } else {
+                    CommunicationRouteClient client = getCommunicationRouteClientForPid(pid);
+                    if (client == null) {
+                        return false;
+                    }
+                }
+                setCommunicationRouteForClient(
+                        cb, pid, deviceAttr, BtHelper.SCO_MODE_UNDEFINED, eventSource);
+            }
+        }
+        return true;
+    }
+
     @GuardedBy("mDeviceStateLock")
     /*package*/ void setCommunicationRouteForClient(
                             IBinder cb, int pid, AudioDeviceAttributes device,
@@ -241,6 +291,10 @@
         if (AudioService.DEBUG_COMM_RTE) {
             Log.v(TAG, "setCommunicationRouteForClient: device: " + device);
         }
+        AudioService.sDeviceLogger.log((new AudioEventLogger.StringEvent(
+                                        "setCommunicationRouteForClient for pid: " + pid
+                                        + " device: " + device
+                                        + " from API: " + eventSource)).printLog(TAG));
 
         final boolean wasBtScoRequested = isBluetoothScoRequested();
         final boolean wasSpeakerphoneRequested = isSpeakerphoneRequested();
@@ -278,6 +332,7 @@
                 } else {
                     removeCommunicationRouteClient(cb, true);
                 }
+                postBroadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
             }
         } else if (!isBtScoRequested && wasBtScoRequested) {
             mBtHelper.stopBluetoothSco(eventSource);
@@ -325,6 +380,20 @@
     }
 
     /**
+     * Returns the device currently requested for communication use case.
+     * @return AudioDeviceInfo the requested device for communication.
+     */
+    AudioDeviceInfo getDeviceForCommunication() {
+        synchronized (mDeviceStateLock) {
+            AudioDeviceAttributes device = requestedCommunicationDevice();
+            if (device == null) {
+                return null;
+            }
+            return AudioManager.getDeviceInfoFromType(device.getType());
+        }
+    }
+
+    /**
      * Helper method on top of requestedCommunicationDevice() indicating if
      * speakerphone ON is currently requested or not.
      * @return true if speakerphone ON requested, false otherwise.
@@ -344,7 +413,11 @@
      * @return true if speakerphone is active, false otherwise.
      */
     /*package*/ boolean isSpeakerphoneOn() {
-        return getForcedUseForComm() == AudioSystem.FORCE_SPEAKER;
+        AudioDeviceAttributes device = getPreferredDeviceForComm();
+        if (device == null) {
+            return false;
+        }
+        return device.getInternalType() == AudioSystem.DEVICE_OUT_SPEAKER;
     }
 
     /**
@@ -511,7 +584,11 @@
      * @return true if Bluetooth SCO is active , false otherwise.
      */
     /*package*/ boolean isBluetoothScoOn() {
-        return getForcedUseForComm() == AudioSystem.FORCE_BT_SCO;
+        AudioDeviceAttributes device = getPreferredDeviceForComm();
+        if (device == null) {
+            return false;
+        }
+        return AudioSystem.DEVICE_OUT_ALL_SCO_SET.contains(device.getInternalType());
     }
 
     /*package*/ AudioRoutesInfo startWatchingRoutes(IAudioRoutesObserver observer) {
@@ -563,14 +640,9 @@
 
         synchronized (mSetModeLock) {
             synchronized (mDeviceStateLock) {
-                AudioDeviceAttributes device = new AudioDeviceAttributes(
-                        AudioDeviceAttributes.ROLE_OUTPUT, AudioDeviceInfo.TYPE_BLUETOOTH_SCO, "");
+                AudioDeviceAttributes device =
+                        new AudioDeviceAttributes(AudioSystem.DEVICE_OUT_BLUETOOTH_SCO, "");
                 setCommunicationRouteForClient(cb, pid, device, scoAudioMode, eventSource);
-                if (!isBluetoothScoRequested()) {
-                    Log.w(TAG, "startBluetoothScoForClient_Sync: rejected for pid: "
-                            + pid + " mode owner pid: " + mModeOwnerPid);
-                    postBroadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
-                }
             }
         }
     }
@@ -599,10 +671,19 @@
         return mDeviceInventory.setPreferredDevicesForStrategySync(strategy, devices);
     }
 
+    /*package*/ void postSetPreferredDevicesForStrategy(int strategy,
+            @NonNull List<AudioDeviceAttributes> devices) {
+        sendILMsgNoDelay(MSG_IL_SET_PREF_DEVICES_FOR_STRATEGY, SENDMSG_REPLACE, strategy, devices);
+    }
+
     /*package*/ int removePreferredDevicesForStrategySync(int strategy) {
         return mDeviceInventory.removePreferredDevicesForStrategySync(strategy);
     }
 
+    /*package*/ void postRemovePreferredDevicesForStrategy(int strategy) {
+        sendIMsgNoDelay(MSG_I_REMOVE_PREF_DEVICES_FOR_STRATEGY, SENDMSG_REPLACE, strategy);
+    }
+
     /*package*/ void registerStrategyPreferredDevicesDispatcher(
             @NonNull IStrategyPreferredDevicesDispatcher dispatcher) {
         mDeviceInventory.registerStrategyPreferredDevicesDispatcher(dispatcher);
@@ -632,6 +713,45 @@
         mDeviceInventory.unregisterCapturePresetDevicesRoleDispatcher(dispatcher);
     }
 
+    /*package*/ void registerCommunicationDeviceDispatcher(
+            @NonNull ICommunicationDeviceDispatcher dispatcher) {
+        mCommDevDispatchers.register(dispatcher);
+    }
+
+    /*package*/ void unregisterCommunicationDeviceDispatcher(
+            @NonNull ICommunicationDeviceDispatcher dispatcher) {
+        mCommDevDispatchers.unregister(dispatcher);
+    }
+
+    // Monitoring of communication device
+    final RemoteCallbackList<ICommunicationDeviceDispatcher> mCommDevDispatchers =
+            new RemoteCallbackList<ICommunicationDeviceDispatcher>();
+
+    // portId of the device currently selected for communication: avoids broadcasting changes
+    // when same communication route is applied
+    @GuardedBy("mDeviceStateLock")
+    int mCurCommunicationPortId = -1;
+
+    @GuardedBy("mDeviceStateLock")
+    private void dispatchCommunicationDevice() {
+        AudioDeviceInfo device = getDeviceForCommunication();
+        int portId = (getDeviceForCommunication() == null) ? 0 : device.getId();
+        if (portId == mCurCommunicationPortId) {
+            return;
+        }
+        mCurCommunicationPortId = portId;
+
+        final int nbDispatchers = mCommDevDispatchers.beginBroadcast();
+        for (int i = 0; i < nbDispatchers; i++) {
+            try {
+                mCommDevDispatchers.getBroadcastItem(i)
+                        .dispatchCommunicationDeviceChanged(portId);
+            } catch (RemoteException e) {
+            }
+        }
+        mCommDevDispatchers.finishBroadcast();
+    }
+
     //---------------------------------------------------------------------
     // Communication with (to) AudioService
     //TODO check whether the AudioService methods are candidates to move here
@@ -888,9 +1008,12 @@
             pw.println("  " + prefix + "pid: " + cl.getPid() + " device: "
                         + cl.getDevice() + " cb: " + cl.getBinder()); });
 
-        pw.println("\n" + prefix + "mForcedUseForComm: "
-                +  AudioSystem.forceUseConfigToString(mForcedUseForComm));
-        pw.println(prefix + "mModeOwnerPid: " + mModeOwnerPid);
+        pw.println("\n" + prefix + "mPreferredDeviceforComm: "
+                +  mPreferredDeviceforComm);
+        pw.println(prefix + "mCommunicationStrategyId: "
+                +  mCommunicationStrategyId);
+
+        pw.println("\n" + prefix + "mModeOwnerPid: " + mModeOwnerPid);
 
         mBtHelper.dump(pw, prefix);
     }
@@ -985,6 +1108,7 @@
                 case MSG_RESTORE_DEVICES:
                     synchronized (mSetModeLock) {
                         synchronized (mDeviceStateLock) {
+                            initCommunicationStrategyId();
                             mDeviceInventory.onRestoreDevices();
                             mBtHelper.onAudioServerDiedRestoreA2dp();
                             onUpdateCommunicationRoute("MSG_RESTORE_DEVICES");
@@ -1194,6 +1318,17 @@
                     final int strategy = msg.arg1;
                     mDeviceInventory.onSaveRemovePreferredDevices(strategy);
                 } break;
+                case MSG_IL_SET_PREF_DEVICES_FOR_STRATEGY: {
+                    final int strategy = msg.arg1;
+                    final List<AudioDeviceAttributes> devices =
+                            (List<AudioDeviceAttributes>) msg.obj;
+                    setPreferredDevicesForStrategySync(strategy, devices);
+
+                } break;
+                case MSG_I_REMOVE_PREF_DEVICES_FOR_STRATEGY: {
+                    final int strategy = msg.arg1;
+                    removePreferredDevicesForStrategySync(strategy);
+                } break;
                 case MSG_CHECK_MUTE_MUSIC:
                     checkMessagesMuteMusic(0);
                     break;
@@ -1286,7 +1421,8 @@
     private static final int MSG_I_SAVE_CLEAR_PREF_DEVICES_FOR_CAPTURE_PRESET = 38;
 
     private static final int MSG_L_UPDATE_COMMUNICATION_ROUTE = 39;
-
+    private static final int MSG_IL_SET_PREF_DEVICES_FOR_STRATEGY = 40;
+    private static final int MSG_I_REMOVE_PREF_DEVICES_FOR_STRATEGY = 41;
 
     private static boolean isMessageHandledUnderWakelock(int msgId) {
         switch(msgId) {
@@ -1526,16 +1662,25 @@
      * @return selected forced usage for communication.
      */
     @GuardedBy("mDeviceStateLock")
-    private int getForcedUseForComm() {
+    @Nullable private AudioDeviceAttributes getPreferredDeviceForComm() {
         boolean btSCoOn = mBluetoothScoOn && mBtHelper.isBluetoothScoOn();
-
         if (btSCoOn) {
-            return AudioSystem.FORCE_BT_SCO;
+            // Use the SCO device known to BtHelper so that it matches exactly
+            // what has been communicated to audio policy manager. The device
+            // returned by requestedCommunicationDevice() can be a dummy SCO device if legacy
+            // APIs are used to start SCO audio.
+            AudioDeviceAttributes device = mBtHelper.getHeadsetAudioDevice();
+            if (device != null) {
+                return device;
+            }
         }
-        if (isSpeakerphoneRequested()) {
-            return AudioSystem.FORCE_SPEAKER;
+        AudioDeviceAttributes device = requestedCommunicationDevice();
+        if (device == null
+                || AudioSystem.DEVICE_OUT_ALL_SCO_SET.contains(device.getInternalType())) {
+            // Do not indicate BT SCO selection if SCO is requested but SCO is not ON
+            return null;
         }
-        return AudioSystem.FORCE_NONE;
+        return device;
     }
 
     /**
@@ -1545,32 +1690,27 @@
     // @GuardedBy("mSetModeLock")
     @GuardedBy("mDeviceStateLock")
     private void onUpdateCommunicationRoute(String eventSource) {
-        mForcedUseForComm = getForcedUseForComm();
-
+        mPreferredDeviceforComm = getPreferredDeviceForComm();
         if (AudioService.DEBUG_COMM_RTE) {
-            Log.v(TAG, "onUpdateCommunicationRoute, mForcedUseForComm: " + mForcedUseForComm
-                    + " eventSource: " + eventSource);
+            Log.v(TAG, "onUpdateCommunicationRoute, mPreferredDeviceforComm: "
+                    + mPreferredDeviceforComm + " eventSource: " + eventSource);
         }
 
-        if (mForcedUseForComm == AudioSystem.FORCE_BT_SCO) {
-            AudioSystem.setParameters("BT_SCO=on");
-            setForceUse_Async(
-                    AudioSystem.FOR_COMMUNICATION, AudioSystem.FORCE_BT_SCO, eventSource);
-            setForceUse_Async(
-                    AudioSystem.FOR_RECORD, AudioSystem.FORCE_BT_SCO, eventSource);
-        } else {
+        if (mPreferredDeviceforComm == null
+                || !AudioSystem.DEVICE_OUT_ALL_SCO_SET.contains(
+                        mPreferredDeviceforComm.getInternalType())) {
             AudioSystem.setParameters("BT_SCO=off");
-            setForceUse_Async(
-                    AudioSystem.FOR_RECORD, AudioSystem.FORCE_NONE, eventSource);
-            if (mForcedUseForComm == AudioSystem.FORCE_SPEAKER) {
-                setForceUse_Async(
-                        AudioSystem.FOR_COMMUNICATION, AudioSystem.FORCE_SPEAKER, eventSource);
-            } else {
-                setForceUse_Async(
-                        AudioSystem.FOR_COMMUNICATION, AudioSystem.FORCE_NONE, eventSource);
-            }
+        } else {
+            AudioSystem.setParameters("BT_SCO=on");
+        }
+        if (mPreferredDeviceforComm == null) {
+            postRemovePreferredDevicesForStrategy(mCommunicationStrategyId);
+        } else {
+            postSetPreferredDevicesForStrategy(
+                    mCommunicationStrategyId, Arrays.asList(mPreferredDeviceforComm));
         }
         mAudioService.postUpdateRingerModeServiceInt();
+        dispatchCommunicationDevice();
     }
 
     private CommunicationRouteClient removeCommunicationRouteClient(
diff --git a/services/core/java/com/android/server/audio/AudioDeviceInventory.java b/services/core/java/com/android/server/audio/AudioDeviceInventory.java
index 33a8a30..82586b8 100644
--- a/services/core/java/com/android/server/audio/AudioDeviceInventory.java
+++ b/services/core/java/com/android/server/audio/AudioDeviceInventory.java
@@ -648,6 +648,10 @@
     /*package*/ int setPreferredDevicesForStrategySync(int strategy,
             @NonNull List<AudioDeviceAttributes> devices) {
         final long identity = Binder.clearCallingIdentity();
+
+        AudioService.sDeviceLogger.log((new AudioEventLogger.StringEvent(
+                                "setPreferredDevicesForStrategySync, strategy: " + strategy
+                                + " devices: " + devices)).printLog(TAG));
         final int status = mAudioSystem.setDevicesRoleForStrategy(
                 strategy, AudioSystem.DEVICE_ROLE_PREFERRED, devices);
         Binder.restoreCallingIdentity(identity);
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index a04184c..ada67b1 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -85,6 +85,7 @@
 import android.media.IAudioServerStateDispatcher;
 import android.media.IAudioService;
 import android.media.ICapturePresetDevicesRoleDispatcher;
+import android.media.ICommunicationDeviceDispatcher;
 import android.media.IPlaybackConfigDispatcher;
 import android.media.IRecordingConfigDispatcher;
 import android.media.IRingtonePlayer;
@@ -4417,6 +4418,115 @@
         restoreDeviceVolumeBehavior();
     }
 
+    private static final int[] VALID_COMMUNICATION_DEVICE_TYPES = {
+        AudioDeviceInfo.TYPE_BUILTIN_SPEAKER,
+        AudioDeviceInfo.TYPE_BLUETOOTH_SCO,
+        AudioDeviceInfo.TYPE_WIRED_HEADSET,
+        AudioDeviceInfo.TYPE_USB_HEADSET,
+        AudioDeviceInfo.TYPE_BUILTIN_EARPIECE,
+        AudioDeviceInfo.TYPE_WIRED_HEADPHONES,
+        AudioDeviceInfo.TYPE_HEARING_AID,
+        AudioDeviceInfo.TYPE_BLE_HEADSET,
+        AudioDeviceInfo.TYPE_USB_DEVICE,
+        AudioDeviceInfo.TYPE_BLE_SPEAKER,
+        AudioDeviceInfo.TYPE_LINE_ANALOG,
+        AudioDeviceInfo.TYPE_HDMI,
+        AudioDeviceInfo.TYPE_AUX_LINE
+    };
+
+    private boolean isValidCommunicationDevice(AudioDeviceInfo device) {
+        for (int type : VALID_COMMUNICATION_DEVICE_TYPES) {
+            if (device.getType() == type) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /** @see AudioManager#setDeviceForCommunication(int) */
+    public boolean setDeviceForCommunication(IBinder cb, int portId) {
+        final int uid = Binder.getCallingUid();
+        final int pid = Binder.getCallingPid();
+
+        AudioDeviceInfo device = null;
+        if (portId != 0) {
+            device = AudioManager.getDeviceForPortId(portId, AudioManager.GET_DEVICES_OUTPUTS);
+            if (device == null) {
+                throw new IllegalArgumentException("invalid portID " + portId);
+            }
+            if (!isValidCommunicationDevice(device)) {
+                throw new IllegalArgumentException("invalid device type " + device.getType());
+            }
+        }
+        final String eventSource = new StringBuilder("setDeviceForCommunication(")
+                .append(") from u/pid:").append(uid).append("/")
+                .append(pid).toString();
+
+        int deviceType = AudioSystem.DEVICE_OUT_DEFAULT;
+        String deviceAddress = null;
+        if (device != null) {
+            deviceType = device.getPort().type();
+            deviceAddress = device.getAddress();
+        } else {
+            AudioDeviceInfo curDevice = mDeviceBroker.getDeviceForCommunication();
+            if (curDevice != null) {
+                deviceType = curDevice.getPort().type();
+                deviceAddress = curDevice.getAddress();
+            }
+        }
+        // do not log metrics if clearing communication device while no communication device
+        // was selected
+        if (deviceType != AudioSystem.DEVICE_OUT_DEFAULT) {
+            new MediaMetrics.Item(MediaMetrics.Name.AUDIO_DEVICE
+                    + MediaMetrics.SEPARATOR + "setDeviceForCommunication")
+                    .set(MediaMetrics.Property.DEVICE,
+                            AudioSystem.getDeviceName(deviceType))
+                    .set(MediaMetrics.Property.ADDRESS, deviceAddress)
+                    .set(MediaMetrics.Property.STATE, device != null
+                            ? MediaMetrics.Value.CONNECTED : MediaMetrics.Value.DISCONNECTED)
+                    .record();
+        }
+
+        final long ident = Binder.clearCallingIdentity();
+        boolean status =
+                mDeviceBroker.setDeviceForCommunication(cb, pid, device, eventSource);
+        Binder.restoreCallingIdentity(ident);
+        return status;
+    }
+
+    /** @see AudioManager#getDeviceForCommunication() */
+    public int getDeviceForCommunication() {
+        final long ident = Binder.clearCallingIdentity();
+        AudioDeviceInfo device = mDeviceBroker.getDeviceForCommunication();
+        Binder.restoreCallingIdentity(ident);
+        if (device == null) {
+            return 0;
+        }
+        return device.getId();
+    }
+
+    /** @see AudioManager#addOnCommunicationDeviceChangedListener(
+     *               Executor, AudioManager.OnCommunicationDeviceChangedListener)
+     */
+    public void registerCommunicationDeviceDispatcher(
+            @Nullable ICommunicationDeviceDispatcher dispatcher) {
+        if (dispatcher == null) {
+            return;
+        }
+        mDeviceBroker.registerCommunicationDeviceDispatcher(dispatcher);
+    }
+
+    /** @see AudioManager#removeOnCommunicationDeviceChangedListener(
+     *               AudioManager.OnCommunicationDeviceChangedListener)
+     */
+    public void unregisterCommunicationDeviceDispatcher(
+            @Nullable ICommunicationDeviceDispatcher dispatcher) {
+        if (dispatcher == null) {
+            return;
+        }
+        mDeviceBroker.unregisterCommunicationDeviceDispatcher(dispatcher);
+    }
+
     /** @see AudioManager#setSpeakerphoneOn(boolean) */
     public void setSpeakerphoneOn(IBinder cb, boolean on) {
         if (!checkAudioSettingsPermission("setSpeakerphoneOn()")) {
@@ -5011,8 +5121,7 @@
         switch (mPlatformType) {
         case AudioSystem.PLATFORM_VOICE:
             if (isInCommunication()) {
-                if (mAudioSystem.getForceUse(AudioSystem.FOR_COMMUNICATION)
-                        == AudioSystem.FORCE_BT_SCO) {
+                if (mDeviceBroker.isBluetoothScoOn()) {
                     // Log.v(TAG, "getActiveStreamType: Forcing STREAM_BLUETOOTH_SCO...");
                     return AudioSystem.STREAM_BLUETOOTH_SCO;
                 } else {
@@ -5048,8 +5157,7 @@
             }
         default:
             if (isInCommunication()) {
-                if (mAudioSystem.getForceUse(AudioSystem.FOR_COMMUNICATION)
-                        == AudioSystem.FORCE_BT_SCO) {
+                if (mDeviceBroker.isBluetoothScoOn()) {
                     if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Forcing STREAM_BLUETOOTH_SCO");
                     return AudioSystem.STREAM_BLUETOOTH_SCO;
                 } else {
@@ -8798,14 +8906,8 @@
         mPlaybackMonitor.playerAttributes(piid, attr, Binder.getCallingUid());
     }
 
-    /**
-     * Update player event
-     * @param piid Player id to update
-     * @param event The new player event
-     * @param deviceId The new player device id
-     */
-    public void playerEvent(int piid, int event, int deviceId) {
-        mPlaybackMonitor.playerEvent(piid, event, deviceId, Binder.getCallingUid());
+    public void playerEvent(int piid, int event) {
+        mPlaybackMonitor.playerEvent(piid, event, Binder.getCallingUid());
     }
 
     public void playerHasOpPlayAudio(int piid, boolean hasOpPlayAudio) {
diff --git a/services/core/java/com/android/server/audio/BtHelper.java b/services/core/java/com/android/server/audio/BtHelper.java
index ae0e805..c57d5af 100644
--- a/services/core/java/com/android/server/audio/BtHelper.java
+++ b/services/core/java/com/android/server/audio/BtHelper.java
@@ -27,6 +27,7 @@
 import android.bluetooth.BluetoothHearingAid;
 import android.bluetooth.BluetoothProfile;
 import android.content.Intent;
+import android.media.AudioDeviceAttributes;
 import android.media.AudioManager;
 import android.media.AudioSystem;
 import android.os.Binder;
@@ -530,46 +531,64 @@
         mDeviceBroker.postBroadcastScoConnectionState(state);
     }
 
-    private boolean handleBtScoActiveDeviceChange(BluetoothDevice btDevice, boolean isActive) {
-        if (btDevice == null) {
-            return true;
+    @Nullable AudioDeviceAttributes getHeadsetAudioDevice() {
+        if (mBluetoothHeadsetDevice == null) {
+            return null;
         }
+        return btHeadsetDeviceToAudioDevice(mBluetoothHeadsetDevice);
+    }
+
+    private AudioDeviceAttributes btHeadsetDeviceToAudioDevice(BluetoothDevice btDevice) {
         String address = btDevice.getAddress();
+        if (!BluetoothAdapter.checkBluetoothAddress(address)) {
+            address = "";
+        }
         BluetoothClass btClass = btDevice.getBluetoothClass();
-        int inDevice = AudioSystem.DEVICE_IN_BLUETOOTH_SCO_HEADSET;
-        int[] outDeviceTypes = {
-                AudioSystem.DEVICE_OUT_BLUETOOTH_SCO,
-                AudioSystem.DEVICE_OUT_BLUETOOTH_SCO_HEADSET,
-                AudioSystem.DEVICE_OUT_BLUETOOTH_SCO_CARKIT
-        };
+        int nativeType = AudioSystem.DEVICE_OUT_BLUETOOTH_SCO;
         if (btClass != null) {
             switch (btClass.getDeviceClass()) {
                 case BluetoothClass.Device.AUDIO_VIDEO_WEARABLE_HEADSET:
                 case BluetoothClass.Device.AUDIO_VIDEO_HANDSFREE:
-                    outDeviceTypes = new int[] { AudioSystem.DEVICE_OUT_BLUETOOTH_SCO_HEADSET };
+                    nativeType = AudioSystem.DEVICE_OUT_BLUETOOTH_SCO_HEADSET;
                     break;
                 case BluetoothClass.Device.AUDIO_VIDEO_CAR_AUDIO:
-                    outDeviceTypes = new int[] { AudioSystem.DEVICE_OUT_BLUETOOTH_SCO_CARKIT };
+                    nativeType = AudioSystem.DEVICE_OUT_BLUETOOTH_SCO_CARKIT;
                     break;
             }
         }
-        if (!BluetoothAdapter.checkBluetoothAddress(address)) {
-            address = "";
+        if (AudioService.DEBUG_DEVICES) {
+            Log.i(TAG, "btHeadsetDeviceToAudioDevice btDevice: " + btDevice
+                    + " btClass: " + (btClass == null ? "Unknown" : btClass)
+                    + " nativeType: " + nativeType + " address: " + address);
         }
+        return new AudioDeviceAttributes(nativeType, address);
+    }
+
+    private boolean handleBtScoActiveDeviceChange(BluetoothDevice btDevice, boolean isActive) {
+        if (btDevice == null) {
+            return true;
+        }
+        int inDevice = AudioSystem.DEVICE_IN_BLUETOOTH_SCO_HEADSET;
+        AudioDeviceAttributes audioDevice =  btHeadsetDeviceToAudioDevice(btDevice);
         String btDeviceName =  getName(btDevice);
         boolean result = false;
         if (isActive) {
-            result |= mDeviceBroker.handleDeviceConnection(
-                    isActive, outDeviceTypes[0], address, btDeviceName);
+            result |= mDeviceBroker.handleDeviceConnection(isActive, audioDevice.getInternalType(),
+                    audioDevice.getAddress(), btDeviceName);
         } else {
+            int[] outDeviceTypes = {
+                    AudioSystem.DEVICE_OUT_BLUETOOTH_SCO,
+                    AudioSystem.DEVICE_OUT_BLUETOOTH_SCO_HEADSET,
+                    AudioSystem.DEVICE_OUT_BLUETOOTH_SCO_CARKIT
+            };
             for (int outDeviceType : outDeviceTypes) {
                 result |= mDeviceBroker.handleDeviceConnection(
-                        isActive, outDeviceType, address, btDeviceName);
+                        isActive, outDeviceType, audioDevice.getAddress(), btDeviceName);
             }
         }
         // handleDeviceConnection() && result to make sure the method get executed
         result = mDeviceBroker.handleDeviceConnection(
-                isActive, inDevice, address, btDeviceName) && result;
+                isActive, inDevice, audioDevice.getAddress(), btDeviceName) && result;
         return result;
     }
 
diff --git a/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java b/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java
index 36c67cd..a577883 100644
--- a/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java
+++ b/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java
@@ -233,25 +233,15 @@
         }
     }
 
-    /**
-     * Update player event
-     * @param piid Player id to update
-     * @param event The new player event
-     * @param deviceId The new player device id
-     * @param binderUid Calling binder uid
-     */
-    public void playerEvent(int piid, int event, int deviceId, int binderUid) {
-        if (DEBUG) {
-            Log.v(TAG, String.format("playerEvent(piid=%d, deviceId=%d, event=%d)",
-                    piid, deviceId, event));
-        }
+    public void playerEvent(int piid, int event, int binderUid) {
+        if (DEBUG) { Log.v(TAG, String.format("playerEvent(piid=%d, event=%d)", piid, event)); }
         final boolean change;
         synchronized(mPlayerLock) {
             final AudioPlaybackConfiguration apc = mPlayers.get(new Integer(piid));
             if (apc == null) {
                 return;
             }
-            sEventLogger.log(new PlayerEvent(piid, event, deviceId));
+            sEventLogger.log(new PlayerEvent(piid, event));
             if (event == AudioPlaybackConfiguration.PLAYER_STATE_STARTED) {
                 for (Integer uidInteger: mBannedUids) {
                     if (checkBanPlayer(apc, uidInteger.intValue())) {
@@ -269,7 +259,7 @@
             if (checkConfigurationCaller(piid, apc, binderUid)) {
                 //TODO add generation counter to only update to the latest state
                 checkVolumeForPrivilegedAlarm(apc, event);
-                change = apc.handleStateEvent(event, deviceId);
+                change = apc.handleStateEvent(event);
             } else {
                 Log.e(TAG, "Error handling event " + event);
                 change = false;
@@ -299,8 +289,7 @@
                 mPlayers.remove(new Integer(piid));
                 mDuckingManager.removeReleased(apc);
                 checkVolumeForPrivilegedAlarm(apc, AudioPlaybackConfiguration.PLAYER_STATE_RELEASED);
-                change = apc.handleStateEvent(AudioPlaybackConfiguration.PLAYER_STATE_RELEASED,
-                        AudioPlaybackConfiguration.PLAYER_DEVICEID_INVALID);
+                change = apc.handleStateEvent(AudioPlaybackConfiguration.PLAYER_STATE_RELEASED);
             }
         }
         if (change) {
@@ -879,19 +868,16 @@
         // only keeping the player interface ID as it uniquely identifies the player in the event
         final int mPlayerIId;
         final int mState;
-        final int mDeviceId;
 
-        PlayerEvent(int piid, int state, int deviceId) {
+        PlayerEvent(int piid, int state) {
             mPlayerIId = piid;
             mState = state;
-            mDeviceId = deviceId;
         }
 
         @Override
         public String eventToString() {
             return new StringBuilder("player piid:").append(mPlayerIId).append(" state:")
-                    .append(AudioPlaybackConfiguration.toLogFriendlyPlayerState(mState))
-                    .append(" DeviceId:").append(mDeviceId).toString();
+                    .append(AudioPlaybackConfiguration.toLogFriendlyPlayerState(mState)).toString();
         }
     }
 
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/FaceUserState.java b/services/core/java/com/android/server/biometrics/sensors/face/FaceUserState.java
index 78e875b..a26662d 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/FaceUserState.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/FaceUserState.java
@@ -133,7 +133,7 @@
             if (tagName.equals(TAG_FACE)) {
                 String name = parser.getAttributeValue(null, ATTR_NAME);
                 int faceId = parser.getAttributeInt(null, ATTR_FACE_ID);
-                int deviceId = parser.getAttributeInt(null, ATTR_DEVICE_ID);
+                long deviceId = parser.getAttributeLong(null, ATTR_DEVICE_ID);
                 mBiometrics.add(new Face(name, faceId, deviceId));
             }
         }
diff --git a/services/core/java/com/android/server/compat/CompatChange.java b/services/core/java/com/android/server/compat/CompatChange.java
index ff31931..a8aa9aa 100644
--- a/services/core/java/com/android/server/compat/CompatChange.java
+++ b/services/core/java/com/android/server/compat/CompatChange.java
@@ -143,6 +143,9 @@
      * @return {@code true} if the change should be enabled for the package.
      */
     boolean isEnabled(ApplicationInfo app) {
+        if (app == null) {
+            return defaultValue();
+        }
         if (mPackageOverrides != null && mPackageOverrides.containsKey(app.packageName)) {
             return mPackageOverrides.get(app.packageName);
         }
@@ -156,6 +159,15 @@
     }
 
     /**
+     * Returns the default value for the change id, assuming there are no overrides.
+     *
+     * @return {@code false} if it's a default disabled change, {@code true} otherwise.
+     */
+    boolean defaultValue() {
+        return !getDisabled();
+    }
+
+    /**
      * Checks whether a change has an override for a package.
      * @param packageName name of the package
      * @return true if there is such override
diff --git a/services/core/java/com/android/server/compat/CompatConfig.java b/services/core/java/com/android/server/compat/CompatConfig.java
index d80c58b..8511118 100644
--- a/services/core/java/com/android/server/compat/CompatConfig.java
+++ b/services/core/java/com/android/server/compat/CompatConfig.java
@@ -392,6 +392,14 @@
         return alreadyKnown;
     }
 
+    boolean defaultChangeIdValue(long changeId) {
+        CompatChange c = mChanges.get(changeId);
+        if (c == null) {
+            return true;
+        }
+        return c.defaultValue();
+    }
+
     @VisibleForTesting
     void clearChanges() {
         synchronized (mChanges) {
diff --git a/services/core/java/com/android/server/compat/PlatformCompat.java b/services/core/java/com/android/server/compat/PlatformCompat.java
index 77d5411..aa85f7f 100644
--- a/services/core/java/com/android/server/compat/PlatformCompat.java
+++ b/services/core/java/com/android/server/compat/PlatformCompat.java
@@ -60,7 +60,6 @@
     private final CompatConfig mCompatConfig;
 
     private static int sMinTargetSdk = Build.VERSION_CODES.Q;
-    private static int sMaxTargetSdk = Build.VERSION_CODES.R;
 
     public PlatformCompat(Context context) {
         mContext = context;
@@ -120,10 +119,12 @@
      * permission check.
      */
     public boolean isChangeEnabledInternal(long changeId, ApplicationInfo appInfo) {
-        boolean value = isChangeEnabledInternalNoLogging(changeId, appInfo);
-        reportChange(changeId, appInfo.uid,
-                value ? ChangeReporter.STATE_ENABLED : ChangeReporter.STATE_DISABLED);
-        return value;
+        boolean enabled = isChangeEnabledInternalNoLogging(changeId, appInfo);
+        if (appInfo != null) {
+            reportChange(changeId, appInfo.uid,
+                    enabled ? ChangeReporter.STATE_ENABLED : ChangeReporter.STATE_DISABLED);
+        }
+        return enabled;
     }
 
     @Override
@@ -131,9 +132,6 @@
             @UserIdInt int userId) {
         checkCompatChangeReadAndLogPermission();
         ApplicationInfo appInfo = getApplicationInfo(packageName, userId);
-        if (appInfo == null) {
-            return true;
-        }
         return isChangeEnabled(changeId, appInfo);
     }
 
@@ -142,7 +140,7 @@
         checkCompatChangeReadAndLogPermission();
         String[] packages = mContext.getPackageManager().getPackagesForUid(uid);
         if (packages == null || packages.length == 0) {
-            return true;
+            return mCompatConfig.defaultChangeIdValue(changeId);
         }
         boolean enabled = true;
         for (String packageName : packages) {
@@ -385,8 +383,7 @@
             return false;
         }
         if (change.getEnableSinceTargetSdk() > 0) {
-            if (change.getEnableSinceTargetSdk() < sMinTargetSdk
-                    || change.getEnableSinceTargetSdk() > sMaxTargetSdk) {
+            if (change.getEnableSinceTargetSdk() < sMinTargetSdk) {
                 return false;
             }
         }
diff --git a/services/core/java/com/android/server/display/AmbientBrightnessStatsTracker.java b/services/core/java/com/android/server/display/AmbientBrightnessStatsTracker.java
index 0f1e666..d74c702 100644
--- a/services/core/java/com/android/server/display/AmbientBrightnessStatsTracker.java
+++ b/services/core/java/com/android/server/display/AmbientBrightnessStatsTracker.java
@@ -217,7 +217,6 @@
                 }
 
                 final LocalDate cutOffDate = mInjector.getLocalDate().minusDays(MAX_DAYS_TO_TRACK);
-                parser.next();
                 int outerDepth = parser.getDepth();
                 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
                         && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
diff --git a/services/core/java/com/android/server/display/BrightnessTracker.java b/services/core/java/com/android/server/display/BrightnessTracker.java
index 7a8ba9f..2375f74 100644
--- a/services/core/java/com/android/server/display/BrightnessTracker.java
+++ b/services/core/java/com/android/server/display/BrightnessTracker.java
@@ -622,7 +622,6 @@
 
             final long timeCutOff = mInjector.currentTimeMillis() - MAX_EVENT_AGE;
 
-            parser.next();
             int outerDepth = parser.getDepth();
             while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
                     && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
diff --git a/services/core/java/com/android/server/display/color/ColorDisplayService.java b/services/core/java/com/android/server/display/color/ColorDisplayService.java
index 92a3ccf..727944d 100644
--- a/services/core/java/com/android/server/display/color/ColorDisplayService.java
+++ b/services/core/java/com/android/server/display/color/ColorDisplayService.java
@@ -77,7 +77,6 @@
 import com.android.server.DisplayThread;
 import com.android.server.LocalServices;
 import com.android.server.SystemService;
-import com.android.server.SystemService.TargetUser;
 import com.android.server.twilight.TwilightListener;
 import com.android.server.twilight.TwilightManager;
 import com.android.server.twilight.TwilightState;
@@ -119,6 +118,7 @@
     private static final int MSG_APPLY_NIGHT_DISPLAY_ANIMATED = 3;
     private static final int MSG_APPLY_GLOBAL_SATURATION = 4;
     private static final int MSG_APPLY_DISPLAY_WHITE_BALANCE = 5;
+    private static final int MSG_APPLY_REDUCE_BRIGHT_COLORS = 6;
 
     /**
      * Return value if a setting has not been set.
@@ -129,17 +129,6 @@
      * Evaluator used to animate color matrix transitions.
      */
     private static final ColorMatrixEvaluator COLOR_MATRIX_EVALUATOR = new ColorMatrixEvaluator();
-
-    private final NightDisplayTintController mNightDisplayTintController =
-            new NightDisplayTintController();
-
-    @VisibleForTesting
-    final DisplayWhiteBalanceTintController mDisplayWhiteBalanceTintController =
-            new DisplayWhiteBalanceTintController();
-
-    private final TintController mGlobalSaturationTintController =
-            new GlobalSaturationTintController();
-
     /**
      * Matrix and offset used for converting color to grayscale.
      */
@@ -163,6 +152,16 @@
             1f, 1f, 1f, 1f
     };
 
+    @VisibleForTesting
+    final DisplayWhiteBalanceTintController mDisplayWhiteBalanceTintController =
+            new DisplayWhiteBalanceTintController();
+    private final NightDisplayTintController mNightDisplayTintController =
+            new NightDisplayTintController();
+    private final TintController mGlobalSaturationTintController =
+            new GlobalSaturationTintController();
+    private final ReduceBrightColorsTintController mReduceBrightColorsTintController =
+            new ReduceBrightColorsTintController();
+
     private final Handler mHandler;
 
     private final AppSaturationController mAppSaturationController = new AppSaturationController();
@@ -354,6 +353,14 @@
                             case Secure.DISPLAY_WHITE_BALANCE_ENABLED:
                                 updateDisplayWhiteBalanceStatus();
                                 break;
+                            case Secure.REDUCE_BRIGHT_COLORS_ACTIVATED:
+                                onReduceBrightColorsActivationChanged();
+                                mHandler.sendEmptyMessage(MSG_APPLY_REDUCE_BRIGHT_COLORS);
+                                break;
+                            case Secure.REDUCE_BRIGHT_COLORS_LEVEL:
+                                onReduceBrightColorsStrengthLevelChanged();
+                                mHandler.sendEmptyMessage(MSG_APPLY_REDUCE_BRIGHT_COLORS);
+                                break;
                         }
                     }
                 }
@@ -372,17 +379,19 @@
                 false /* notifyForDescendants */, mContentObserver, mCurrentUser);
         cr.registerContentObserver(System.getUriFor(System.DISPLAY_COLOR_MODE),
                 false /* notifyForDescendants */, mContentObserver, mCurrentUser);
-        cr.registerContentObserver(
-                Secure.getUriFor(Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED),
+        cr.registerContentObserver(Secure.getUriFor(Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED),
                 false /* notifyForDescendants */, mContentObserver, mCurrentUser);
         cr.registerContentObserver(
                 Secure.getUriFor(Secure.ACCESSIBILITY_DISPLAY_DALTONIZER_ENABLED),
                 false /* notifyForDescendants */, mContentObserver, mCurrentUser);
-        cr.registerContentObserver(
-                Secure.getUriFor(Secure.ACCESSIBILITY_DISPLAY_DALTONIZER),
+        cr.registerContentObserver(Secure.getUriFor(Secure.ACCESSIBILITY_DISPLAY_DALTONIZER),
                 false /* notifyForDescendants */, mContentObserver, mCurrentUser);
         cr.registerContentObserver(Secure.getUriFor(Secure.DISPLAY_WHITE_BALANCE_ENABLED),
                 false /* notifyForDescendants */, mContentObserver, mCurrentUser);
+        cr.registerContentObserver(Secure.getUriFor(Secure.REDUCE_BRIGHT_COLORS_ACTIVATED),
+                false /* notifyForDescendants */, mContentObserver, mCurrentUser);
+        cr.registerContentObserver(Secure.getUriFor(Secure.REDUCE_BRIGHT_COLORS_LEVEL),
+                false /* notifyForDescendants */, mContentObserver, mCurrentUser);
 
         // Apply the accessibility settings first, since they override most other settings.
         onAccessibilityInversionChanged();
@@ -420,6 +429,17 @@
 
             updateDisplayWhiteBalanceStatus();
         }
+
+        if (mReduceBrightColorsTintController.isAvailable(getContext())) {
+            mReduceBrightColorsTintController
+                    .setUp(getContext(), DisplayTransformManager.needsLinearColorMatrix());
+            onReduceBrightColorsStrengthLevelChanged();
+            final boolean reset = resetReduceBrightColors();
+            if (!reset) {
+                onReduceBrightColorsActivationChanged();
+                mHandler.sendEmptyMessage(MSG_APPLY_REDUCE_BRIGHT_COLORS);
+            }
+        }
     }
 
     private void tearDown() {
@@ -444,6 +464,27 @@
         if (mGlobalSaturationTintController.isAvailable(getContext())) {
             mGlobalSaturationTintController.setActivated(null);
         }
+
+        if (mReduceBrightColorsTintController.isAvailable(getContext())) {
+            mReduceBrightColorsTintController.setActivated(null);
+        }
+    }
+
+    private boolean resetReduceBrightColors() {
+        if (mCurrentUser == UserHandle.USER_NULL) {
+            return false;
+        }
+
+        final boolean isSettingActivated = Secure.getIntForUser(getContext().getContentResolver(),
+                Secure.REDUCE_BRIGHT_COLORS_ACTIVATED, 0, mCurrentUser) == 1;
+        final boolean shouldResetOnReboot = Secure.getIntForUser(getContext().getContentResolver(),
+                Secure.REDUCE_BRIGHT_COLORS_PERSIST_ACROSS_REBOOTS, 0, mCurrentUser) == 0;
+        if (isSettingActivated && mReduceBrightColorsTintController.isActivatedStateNotSet()
+                && shouldResetOnReboot) {
+            return Secure.putIntForUser(getContext().getContentResolver(),
+                    Secure.REDUCE_BRIGHT_COLORS_ACTIVATED, 0, mCurrentUser);
+        }
+        return false;
     }
 
     private void onNightDisplayAutoModeChanged(int autoMode) {
@@ -572,6 +613,24 @@
                 isAccessiblityInversionEnabled() ? MATRIX_INVERT_COLOR : null);
     }
 
+    private void onReduceBrightColorsActivationChanged() {
+        if (mCurrentUser == UserHandle.USER_NULL) {
+            return;
+        }
+        mReduceBrightColorsTintController.setActivated(
+                Secure.getIntForUser(getContext().getContentResolver(),
+                        Secure.REDUCE_BRIGHT_COLORS_ACTIVATED, 0, mCurrentUser) == 1);
+    }
+
+    private void onReduceBrightColorsStrengthLevelChanged() {
+        if (mCurrentUser == UserHandle.USER_NULL) {
+            return;
+        }
+        mReduceBrightColorsTintController.setMatrix(
+                Secure.getIntForUser(getContext().getContentResolver(),
+                        Secure.REDUCE_BRIGHT_COLORS_LEVEL, 0, mCurrentUser));
+    }
+
     /**
      * Applies current color temperature matrix, or removes it if deactivated.
      *
@@ -937,6 +996,14 @@
             pw.println("    Not available");
         }
 
+        pw.println("Reduce bright colors:");
+        if (mReduceBrightColorsTintController.isAvailable(getContext())) {
+            pw.println("    Activated: " + mReduceBrightColorsTintController.isActivated());
+            mReduceBrightColorsTintController.dump(pw);
+        } else {
+            pw.println("    Not available");
+        }
+
         pw.println("Color mode: " + getColorModeInternal());
     }
 
@@ -1438,6 +1505,9 @@
                     mGlobalSaturationTintController.setMatrix(msg.arg1);
                     applyTint(mGlobalSaturationTintController, false);
                     break;
+                case MSG_APPLY_REDUCE_BRIGHT_COLORS:
+                    applyTint(mReduceBrightColorsTintController, true);
+                    break;
                 case MSG_APPLY_NIGHT_DISPLAY_IMMEDIATE:
                     applyTint(mNightDisplayTintController, true);
                     break;
diff --git a/services/core/java/com/android/server/display/color/DisplayTransformManager.java b/services/core/java/com/android/server/display/color/DisplayTransformManager.java
index 3b0069c..5c68c51 100644
--- a/services/core/java/com/android/server/display/color/DisplayTransformManager.java
+++ b/services/core/java/com/android/server/display/color/DisplayTransformManager.java
@@ -59,6 +59,10 @@
      */
     public static final int LEVEL_COLOR_MATRIX_GRAYSCALE = 200;
     /**
+     * Color transform level used by A11y services to reduce bright colors.
+     */
+    public static final int LEVEL_COLOR_MATRIX_REDUCE_BRIGHT_COLORS = 250;
+    /**
      * Color transform level used by A11y services to invert the display colors.
      */
     public static final int LEVEL_COLOR_MATRIX_INVERT_COLOR = 300;
@@ -97,7 +101,7 @@
      * Map of level -> color transformation matrix.
      */
     @GuardedBy("mColorMatrix")
-    private final SparseArray<float[]> mColorMatrix = new SparseArray<>(5);
+    private final SparseArray<float[]> mColorMatrix = new SparseArray<>(6);
     /**
      * Temporary matrix used internally by {@link #computeColorMatrixLocked()}.
      */
diff --git a/services/core/java/com/android/server/display/color/ReduceBrightColorsTintController.java b/services/core/java/com/android/server/display/color/ReduceBrightColorsTintController.java
new file mode 100644
index 0000000..7e120c9
--- /dev/null
+++ b/services/core/java/com/android/server/display/color/ReduceBrightColorsTintController.java
@@ -0,0 +1,113 @@
+/*
+ * 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.server.display.color;
+
+import static com.android.server.display.color.DisplayTransformManager.LEVEL_COLOR_MATRIX_REDUCE_BRIGHT_COLORS;
+
+import android.content.Context;
+import android.hardware.display.ColorDisplayManager;
+import android.opengl.Matrix;
+import android.util.Slog;
+
+import com.android.internal.R;
+
+import java.io.PrintWriter;
+import java.util.Arrays;
+
+/**
+ * Control the color transform for bright color reduction.
+ */
+public class ReduceBrightColorsTintController extends TintController {
+
+    private final float[] mMatrix = new float[16];
+    private final float[] mCoefficients = new float[9];
+
+    private int mStrength;
+
+    @Override
+    public void setUp(Context context, boolean needsLinear) {
+        final String[] coefficients = context.getResources().getStringArray(
+                needsLinear ? R.array.config_reduceBrightColorsCoefficients
+                        : R.array.config_reduceBrightColorsCoefficientsNative);
+        for (int i = 0; i < 9 && i < coefficients.length; i++) {
+            mCoefficients[i] = Float.parseFloat(coefficients[i]);
+        }
+    }
+
+    @Override
+    public float[] getMatrix() {
+        return isActivated() ? Arrays.copyOf(mMatrix, mMatrix.length)
+                : ColorDisplayService.MATRIX_IDENTITY;
+    }
+
+    @Override
+    public void setMatrix(int strengthLevel) {
+        // Clamp to valid range.
+        if (strengthLevel < 0) {
+            strengthLevel = 0;
+        } else if (strengthLevel > 100) {
+            strengthLevel = 100;
+        }
+        Slog.d(ColorDisplayService.TAG, "Setting bright color reduction level: " + strengthLevel);
+        mStrength = strengthLevel;
+
+        Matrix.setIdentityM(mMatrix, 0);
+
+        final float percentageStrength = strengthLevel / 100f;
+        final float squaredPercentageStrength = percentageStrength * percentageStrength;
+        final float red =
+                squaredPercentageStrength * mCoefficients[0] + percentageStrength * mCoefficients[1]
+                        + mCoefficients[2];
+        final float green =
+                squaredPercentageStrength * mCoefficients[3] + percentageStrength * mCoefficients[4]
+                        + mCoefficients[5];
+        final float blue =
+                squaredPercentageStrength * mCoefficients[6] + percentageStrength * mCoefficients[7]
+                        + mCoefficients[8];
+        mMatrix[0] = clamp(red);
+        mMatrix[5] = clamp(green);
+        mMatrix[10] = clamp(blue);
+    }
+
+    private float clamp(float value) {
+        if (value > 1f) {
+            return 1f;
+        } else if (value < 0f) {
+            return 0f;
+        }
+        return value;
+    }
+
+    @Override
+    public void dump(PrintWriter pw) {
+        pw.println("    mStrength = " + mStrength);
+    }
+
+    @Override
+    public int getLevel() {
+        return LEVEL_COLOR_MATRIX_REDUCE_BRIGHT_COLORS;
+    }
+
+    @Override
+    public boolean isAvailable(Context context) {
+        return ColorDisplayManager.isColorTransformAccelerated(context);
+    }
+
+    public int getStrength() {
+        return mStrength;
+    }
+}
diff --git a/services/core/java/com/android/server/hdmi/HdmiControlService.java b/services/core/java/com/android/server/hdmi/HdmiControlService.java
index 8a753c5..c15fdca 100644
--- a/services/core/java/com/android/server/hdmi/HdmiControlService.java
+++ b/services/core/java/com/android/server/hdmi/HdmiControlService.java
@@ -1655,6 +1655,12 @@
         }
 
         @Override
+        public boolean shouldHandleTvPowerKey() {
+            enforceAccessPermission();
+            return HdmiControlService.this.shouldHandleTvPowerKey();
+        }
+
+        @Override
         public void queryDisplayStatus(final IHdmiControlCallback callback) {
             enforceAccessPermission();
             runOnServiceThread(new Runnable() {
@@ -2346,6 +2352,24 @@
         source.toggleAndFollowTvPower();
     }
 
+    @VisibleForTesting
+    protected boolean shouldHandleTvPowerKey() {
+        if (isTvDevice()) {
+            return false;
+        }
+        String powerControlMode = getHdmiCecConfig().getStringValue(
+                HdmiControlManager.CEC_SETTING_NAME_POWER_CONTROL_MODE);
+        if (powerControlMode.equals(HdmiControlManager.POWER_CONTROL_MODE_NONE)) {
+            return false;
+        }
+        int hdmiCecEnabled = getHdmiCecConfig().getIntValue(
+                HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_ENABLED);
+        if (hdmiCecEnabled != HdmiControlManager.HDMI_CEC_CONTROL_ENABLED) {
+            return false;
+        }
+        return true;
+    }
+
     @ServiceThreadOnly
     protected void queryDisplayStatus(final IHdmiControlCallback callback) {
         assertRunOnServiceThread();
diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java
index bfc751f..bff81e6 100644
--- a/services/core/java/com/android/server/input/InputManagerService.java
+++ b/services/core/java/com/android/server/input/InputManagerService.java
@@ -41,11 +41,13 @@
 import android.hardware.display.DisplayViewport;
 import android.hardware.input.IInputDevicesChangedListener;
 import android.hardware.input.IInputManager;
+import android.hardware.input.IInputSensorEventListener;
 import android.hardware.input.ITabletModeChangedListener;
 import android.hardware.input.InputDeviceIdentifier;
 import android.hardware.input.InputManager;
 import android.hardware.input.InputManagerInternal;
 import android.hardware.input.InputManagerInternal.LidSwitchCallback;
+import android.hardware.input.InputSensorInfo;
 import android.hardware.input.KeyboardLayout;
 import android.hardware.input.TouchCalibration;
 import android.media.AudioManager;
@@ -117,6 +119,7 @@
 import java.io.InputStreamReader;
 import java.io.PrintWriter;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashSet;
@@ -158,9 +161,6 @@
             "com.snapchat.android" // b/173297887
     };
 
-    /** TODO(b/169067926): Remove this. */
-    private static final boolean UNTRUSTED_TOUCHES_TOAST = false;
-
     // Pointer to native input manager service object.
     private final long mPtr;
 
@@ -184,12 +184,24 @@
     private final List<TabletModeChangedListenerRecord> mTempTabletModeChangedListenersToNotify =
             new ArrayList<>();
 
+    private final Object mSensorEventLock = new Object();
+    // List of currently registered sensor event listeners by process id
+    @GuardedBy("mSensorEventLock")
+    private final SparseArray<SensorEventListenerRecord> mSensorEventListeners =
+            new SparseArray<>();
+    private final List<SensorEventListenerRecord> mSensorEventListenersToNotify =
+            new ArrayList<>();
+    private final List<SensorEventListenerRecord> mSensorAccuracyListenersToNotify =
+            new ArrayList<>();
+
     // Persistent data store.  Must be locked each time during use.
     private final PersistentDataStore mDataStore = new PersistentDataStore();
 
     // List of currently registered input devices changed listeners by process id.
     private Object mInputDevicesLock = new Object();
+    @GuardedBy("mInputDevicesLock")
     private boolean mInputDevicesChangedPending; // guarded by mInputDevicesLock
+    @GuardedBy("mInputDevicesLock")
     private InputDevice[] mInputDevices = new InputDevice[0];
     private final SparseArray<InputDevicesChangedListenerRecord> mInputDevicesChangedListeners =
             new SparseArray<InputDevicesChangedListenerRecord>(); // guarded by mInputDevicesLock
@@ -247,7 +259,7 @@
             int deviceId, int sourceMask, int[] keyCodes, boolean[] keyExists);
     private static native InputChannel nativeCreateInputChannel(long ptr, String name);
     private static native InputChannel nativeCreateInputMonitor(long ptr, int displayId,
-            boolean isGestureMonitor, String name);
+            boolean isGestureMonitor, String name, int pid);
     private static native void nativeRemoveInputChannel(long ptr, IBinder connectionToken);
     private static native void nativePilferPointers(long ptr, IBinder token);
     private static native void nativeSetInputFilterEnabled(long ptr, boolean enable);
@@ -293,6 +305,11 @@
     private static native boolean nativeCanDispatchToDisplay(long ptr, int deviceId, int displayId);
     private static native void nativeNotifyPortAssociationsChanged(long ptr);
     private static native void nativeSetMotionClassifierEnabled(long ptr, boolean enabled);
+    private static native InputSensorInfo[] nativeGetSensorList(long ptr, int deviceId);
+    private static native boolean nativeFlushSensor(long ptr, int deviceId, int sensorType);
+    private static native boolean nativeEnableSensor(long ptr, int deviceId, int sensorType,
+            int samplingPeriodUs, int maxBatchReportLatencyUs);
+    private static native void nativeDisableSensor(long ptr, int deviceId, int sensorType);
 
     // Maximum number of milliseconds to wait for input event injection.
     private static final int INJECTION_TIMEOUT_MILLIS = 30 * 1000;
@@ -590,7 +607,7 @@
         }
 
         return nativeCreateInputMonitor(mPtr, displayId, false /* isGestureMonitor */,
-                inputChannelName);
+                inputChannelName, Binder.getCallingPid());
     }
 
     /**
@@ -618,7 +635,7 @@
         final long ident = Binder.clearCallingIdentity();
         try {
             InputChannel inputChannel = nativeCreateInputMonitor(
-                    mPtr, displayId, true /*isGestureMonitor*/, inputChannelName);
+                    mPtr, displayId, true /*isGestureMonitor*/, inputChannelName, pid);
             InputMonitorHost host = new InputMonitorHost(inputChannel.getToken());
             synchronized (mGestureMonitorPidsLock) {
                 mGestureMonitorPidsByToken.put(inputChannel.getToken(), pid);
@@ -2047,6 +2064,97 @@
         nativeNotifyPortAssociationsChanged(mPtr);
     }
 
+    @Override // Binder call
+    public InputSensorInfo[] getSensorList(int deviceId) {
+        InputSensorInfo[] sensors = nativeGetSensorList(mPtr, deviceId);
+        return sensors;
+    }
+
+    @Override // Binder call
+    public boolean registerSensorListener(IInputSensorEventListener listener) {
+        if (DEBUG) {
+            Slog.d(TAG, "registerSensorListener: listener=" + listener + " callingPid="
+                    + Binder.getCallingPid());
+        }
+        if (listener == null) {
+            Slog.e(TAG, "listener must not be null");
+            return false;
+        }
+
+        synchronized (mInputDevicesLock) {
+            int callingPid = Binder.getCallingPid();
+            if (mSensorEventListeners.get(callingPid) != null) {
+                Slog.e(TAG, "The calling process " + callingPid + " has already "
+                        + "registered an InputSensorEventListener.");
+                return false;
+            }
+
+            SensorEventListenerRecord record =
+                    new SensorEventListenerRecord(callingPid, listener);
+            try {
+                IBinder binder = listener.asBinder();
+                binder.linkToDeath(record, 0);
+            } catch (RemoteException ex) {
+                // give up
+                throw new RuntimeException(ex);
+            }
+
+            mSensorEventListeners.put(callingPid, record);
+        }
+        return true;
+    }
+
+    @Override // Binder call
+    public void unregisterSensorListener(IInputSensorEventListener listener) {
+        if (DEBUG) {
+            Slog.d(TAG, "unregisterSensorListener: listener=" + listener + " callingPid="
+                    + Binder.getCallingPid());
+        }
+
+        if (listener == null) {
+            throw new IllegalArgumentException("listener must not be null");
+        }
+
+        synchronized (mInputDevicesLock) {
+            int callingPid = Binder.getCallingPid();
+            if (mSensorEventListeners.get(callingPid) != null) {
+                SensorEventListenerRecord record = mSensorEventListeners.get(callingPid);
+                if (record.getListener().asBinder() != listener.asBinder()) {
+                    throw new IllegalArgumentException("listener is not registered");
+                }
+                mSensorEventListeners.remove(callingPid);
+            }
+        }
+    }
+
+    @Override // Binder call
+    public boolean flushSensor(int deviceId, int sensorType) {
+        synchronized (mInputDevicesLock) {
+            int callingPid = Binder.getCallingPid();
+            SensorEventListenerRecord listener = mSensorEventListeners.get(callingPid);
+            if (listener != null) {
+                return nativeFlushSensor(mPtr, deviceId, sensorType);
+            }
+            return false;
+        }
+    }
+
+    @Override // Binder call
+    public boolean enableSensor(int deviceId, int sensorType, int samplingPeriodUs,
+            int maxBatchReportLatencyUs) {
+        synchronized (mInputDevicesLock) {
+            return nativeEnableSensor(mPtr, deviceId, sensorType, samplingPeriodUs,
+                    maxBatchReportLatencyUs);
+        }
+    }
+
+    @Override // Binder call
+    public void disableSensor(int deviceId, int sensorType) {
+        synchronized (mInputDevicesLock) {
+            nativeDisableSensor(mPtr, deviceId, sensorType);
+        }
+    }
+
     @Override
     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
         if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
@@ -2199,8 +2307,7 @@
     // Native callback
     private void notifyUntrustedTouch(String packageName) {
         // TODO(b/169067926): Remove toast after gathering feedback on dogfood.
-        if (!UNTRUSTED_TOUCHES_TOAST || ArrayUtils.contains(
-                PACKAGE_BLOCKLIST_FOR_UNTRUSTED_TOUCHES_TOAST, packageName)) {
+        if (ArrayUtils.contains(PACKAGE_BLOCKLIST_FOR_UNTRUSTED_TOUCHES_TOAST, packageName)) {
             Log.i(TAG, "Suppressing untrusted touch toast for " + packageName);
             return;
         }
@@ -2245,6 +2352,46 @@
     }
 
     // Native callback.
+    private void notifySensorEvent(int deviceId, int sensorType, int accuracy, long timestamp,
+            float[] values) {
+        if (DEBUG) {
+            Slog.d(TAG, "notifySensorEvent: deviceId=" + deviceId + " sensorType="
+                    + sensorType + " values=" + Arrays.toString(values));
+        }
+        mSensorEventListenersToNotify.clear();
+        final int numListeners;
+        synchronized (mSensorEventLock) {
+            numListeners = mSensorEventListeners.size();
+            for (int i = 0; i < numListeners; i++) {
+                mSensorEventListenersToNotify.add(
+                        mSensorEventListeners.valueAt(i));
+            }
+        }
+        for (int i = 0; i < numListeners; i++) {
+            mSensorEventListenersToNotify.get(i).notifySensorEvent(deviceId, sensorType,
+                    accuracy, timestamp, values);
+        }
+        mSensorEventListenersToNotify.clear();
+    }
+
+    // Native callback.
+    private void notifySensorAccuracy(int deviceId, int sensorType, int accuracy) {
+        mSensorAccuracyListenersToNotify.clear();
+        final int numListeners;
+        synchronized (mSensorEventLock) {
+            numListeners = mSensorEventListeners.size();
+            for (int i = 0; i < numListeners; i++) {
+                mSensorAccuracyListenersToNotify.add(mSensorEventListeners.valueAt(i));
+            }
+        }
+        for (int i = 0; i < numListeners; i++) {
+            mSensorAccuracyListenersToNotify.get(i).notifySensorAccuracy(
+                    deviceId, sensorType, accuracy);
+        }
+        mSensorAccuracyListenersToNotify.clear();
+    }
+
+    // Native callback.
     final boolean filterInputEvent(InputEvent event, int policyFlags) {
         synchronized (mInputFilterLock) {
             if (mInputFilter != null) {
@@ -2592,17 +2739,8 @@
 
         /**
          * Called when the focused window has changed.
-         *
-         * @return true if we want to request a configuration refresh.
          */
-        boolean notifyFocusChanged(IBinder oldToken, IBinder newToken);
-
-        /**
-         * Called by the client to request pointer capture.
-         *
-         * @return true if we want to request a configuration refresh.
-         */
-        boolean requestPointerCapture(IBinder windowToken, boolean enabled);
+        void notifyFocusChanged(IBinder oldToken, IBinder newToken);
     }
 
     /**
@@ -2785,6 +2923,56 @@
         }
     }
 
+    private void onSensorEventListenerDied(int pid) {
+        synchronized (mSensorEventLock) {
+            mSensorEventListeners.remove(pid);
+        }
+    }
+
+    private final class SensorEventListenerRecord implements DeathRecipient {
+        private final int mPid;
+        private final IInputSensorEventListener mListener;
+
+        SensorEventListenerRecord(int pid, IInputSensorEventListener listener) {
+            mPid = pid;
+            mListener = listener;
+        }
+
+        @Override
+        public void binderDied() {
+            if (DEBUG) {
+                Slog.d(TAG, "Sensor event listener for pid " + mPid + " died.");
+            }
+            onSensorEventListenerDied(mPid);
+        }
+
+        public IInputSensorEventListener getListener() {
+            return mListener;
+        }
+
+        public void notifySensorEvent(int deviceId, int sensorType, int accuracy, long timestamp,
+                float[] values) {
+            try {
+                mListener.onInputSensorChanged(deviceId, sensorType, accuracy, timestamp,
+                        values);
+            } catch (RemoteException ex) {
+                Slog.w(TAG, "Failed to notify process " + mPid
+                        + " that sensor event notified, assuming it died.", ex);
+                binderDied();
+            }
+        }
+
+        public void notifySensorAccuracy(int deviceId, int sensorType, int accuracy) {
+            try {
+                mListener.onInputSensorAccuracyChanged(deviceId, sensorType, accuracy);
+            } catch (RemoteException ex) {
+                Slog.w(TAG, "Failed to notify process " + mPid
+                        + " that sensor accuracy notified, assuming it died.", ex);
+                binderDied();
+            }
+        }
+    }
+
     private final class VibratorToken implements DeathRecipient {
         public final int mDeviceId;
         public final IBinder mToken;
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index 90edd77..ab7e3b0 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -162,7 +162,11 @@
 import com.android.internal.inputmethod.IBooleanResultCallback;
 import com.android.internal.inputmethod.IInputBindResultResultCallback;
 import com.android.internal.inputmethod.IInputContentUriToken;
+import com.android.internal.inputmethod.IInputMethodInfoListResultCallback;
 import com.android.internal.inputmethod.IInputMethodPrivilegedOperations;
+import com.android.internal.inputmethod.IInputMethodSubtypeListResultCallback;
+import com.android.internal.inputmethod.IInputMethodSubtypeResultCallback;
+import com.android.internal.inputmethod.IIntResultCallback;
 import com.android.internal.inputmethod.InputMethodDebug;
 import com.android.internal.inputmethod.SoftInputShowHideReason;
 import com.android.internal.inputmethod.StartInputFlags;
@@ -1970,43 +1974,51 @@
     }
 
     @Override
-    public List<InputMethodInfo> getInputMethodList(@UserIdInt int userId) {
-        if (UserHandle.getCallingUserId() != userId) {
-            mContext.enforceCallingPermission(Manifest.permission.INTERACT_ACROSS_USERS_FULL, null);
-        }
-        synchronized (mMethodMap) {
-            final int[] resolvedUserIds = InputMethodUtils.resolveUserId(userId,
-                    mSettings.getCurrentUserId(), null);
-            if (resolvedUserIds.length != 1) {
-                return Collections.emptyList();
+    public void getInputMethodList(@UserIdInt int userId,
+            IInputMethodInfoListResultCallback resultCallback) {
+        CallbackUtils.onResult(resultCallback, () -> {
+            if (UserHandle.getCallingUserId() != userId) {
+                mContext.enforceCallingPermission(
+                        Manifest.permission.INTERACT_ACROSS_USERS_FULL, null);
             }
-            final long ident = Binder.clearCallingIdentity();
-            try {
-                return getInputMethodListLocked(resolvedUserIds[0]);
-            } finally {
-                Binder.restoreCallingIdentity(ident);
+            synchronized (mMethodMap) {
+                final int[] resolvedUserIds = InputMethodUtils.resolveUserId(userId,
+                        mSettings.getCurrentUserId(), null);
+                if (resolvedUserIds.length != 1) {
+                    return Collections.emptyList();
+                }
+                final long ident = Binder.clearCallingIdentity();
+                try {
+                    return getInputMethodListLocked(resolvedUserIds[0]);
+                } finally {
+                    Binder.restoreCallingIdentity(ident);
+                }
             }
-        }
+        });
     }
 
     @Override
-    public List<InputMethodInfo> getEnabledInputMethodList(@UserIdInt int userId) {
-        if (UserHandle.getCallingUserId() != userId) {
-            mContext.enforceCallingPermission(Manifest.permission.INTERACT_ACROSS_USERS_FULL, null);
-        }
-        synchronized (mMethodMap) {
-            final int[] resolvedUserIds = InputMethodUtils.resolveUserId(userId,
-                    mSettings.getCurrentUserId(), null);
-            if (resolvedUserIds.length != 1) {
-                return Collections.emptyList();
+    public void getEnabledInputMethodList(@UserIdInt int userId,
+            IInputMethodInfoListResultCallback resultCallback) {
+        CallbackUtils.onResult(resultCallback, () -> {
+            if (UserHandle.getCallingUserId() != userId) {
+                mContext.enforceCallingPermission(
+                        Manifest.permission.INTERACT_ACROSS_USERS_FULL, null);
             }
-            final long ident = Binder.clearCallingIdentity();
-            try {
-                return getEnabledInputMethodListLocked(resolvedUserIds[0]);
-            } finally {
-                Binder.restoreCallingIdentity(ident);
+            synchronized (mMethodMap) {
+                final int[] resolvedUserIds = InputMethodUtils.resolveUserId(userId,
+                        mSettings.getCurrentUserId(), null);
+                if (resolvedUserIds.length != 1) {
+                    return Collections.emptyList();
+                }
+                final long ident = Binder.clearCallingIdentity();
+                try {
+                    return getEnabledInputMethodListLocked(resolvedUserIds[0]);
+                } finally {
+                    Binder.restoreCallingIdentity(ident);
+                }
             }
-        }
+        });
     }
 
     @GuardedBy("mMethodMap")
@@ -2159,27 +2171,34 @@
     }
 
     /**
-     * @param imiId if null, returns enabled subtypes for the current imi
-     * @return enabled subtypes of the specified imi
+     * Gets enabled subtypes of the specified {@link InputMethodInfo}.
+     *
+     * @param imiId if null, returns enabled subtypes for the current {@link InputMethodInfo}.
+     * @param allowsImplicitlySelectedSubtypes {@code true} to return the implicitly selected
+     *                                         subtypes.
+     * @param resultCallback to callback the result.
      */
     @Override
-    public List<InputMethodSubtype> getEnabledInputMethodSubtypeList(String imiId,
-            boolean allowsImplicitlySelectedSubtypes) {
-        final int callingUserId = UserHandle.getCallingUserId();
-        synchronized (mMethodMap) {
-            final int[] resolvedUserIds = InputMethodUtils.resolveUserId(callingUserId,
-                    mSettings.getCurrentUserId(), null);
-            if (resolvedUserIds.length != 1) {
-                return Collections.emptyList();
+    public void getEnabledInputMethodSubtypeList(String imiId,
+            boolean allowsImplicitlySelectedSubtypes,
+            IInputMethodSubtypeListResultCallback resultCallback) {
+        CallbackUtils.onResult(resultCallback, () -> {
+            final int callingUserId = UserHandle.getCallingUserId();
+            synchronized (mMethodMap) {
+                final int[] resolvedUserIds = InputMethodUtils.resolveUserId(callingUserId,
+                        mSettings.getCurrentUserId(), null);
+                if (resolvedUserIds.length != 1) {
+                    return Collections.emptyList();
+                }
+                final long ident = Binder.clearCallingIdentity();
+                try {
+                    return getEnabledInputMethodSubtypeListLocked(imiId,
+                            allowsImplicitlySelectedSubtypes, resolvedUserIds[0]);
+                } finally {
+                    Binder.restoreCallingIdentity(ident);
+                }
             }
-            final long ident = Binder.clearCallingIdentity();
-            try {
-                return getEnabledInputMethodSubtypeListLocked(imiId,
-                        allowsImplicitlySelectedSubtypes, resolvedUserIds[0]);
-            } finally {
-                Binder.restoreCallingIdentity(ident);
-            }
-        }
+        });
     }
 
     @GuardedBy("mMethodMap")
@@ -3892,29 +3911,31 @@
     }
 
     @Override
-    public InputMethodSubtype getLastInputMethodSubtype() {
-        synchronized (mMethodMap) {
-            if (!calledFromValidUserLocked()) {
-                return null;
-            }
-            final Pair<String, String> lastIme = mSettings.getLastInputMethodAndSubtypeLocked();
-            // TODO: Handle the case of the last IME with no subtypes
-            if (lastIme == null || TextUtils.isEmpty(lastIme.first)
-                    || TextUtils.isEmpty(lastIme.second)) return null;
-            final InputMethodInfo lastImi = mMethodMap.get(lastIme.first);
-            if (lastImi == null) return null;
-            try {
-                final int lastSubtypeHash = Integer.parseInt(lastIme.second);
-                final int lastSubtypeId =
-                        InputMethodUtils.getSubtypeIdFromHashCode(lastImi, lastSubtypeHash);
-                if (lastSubtypeId < 0 || lastSubtypeId >= lastImi.getSubtypeCount()) {
+    public void getLastInputMethodSubtype(IInputMethodSubtypeResultCallback resultCallback) {
+        CallbackUtils.onResult(resultCallback, () -> {
+            synchronized (mMethodMap) {
+                if (!calledFromValidUserLocked()) {
                     return null;
                 }
-                return lastImi.getSubtypeAt(lastSubtypeId);
-            } catch (NumberFormatException e) {
-                return null;
+                final Pair<String, String> lastIme = mSettings.getLastInputMethodAndSubtypeLocked();
+                // TODO: Handle the case of the last IME with no subtypes
+                if (lastIme == null || TextUtils.isEmpty(lastIme.first)
+                        || TextUtils.isEmpty(lastIme.second)) return null;
+                final InputMethodInfo lastImi = mMethodMap.get(lastIme.first);
+                if (lastImi == null) return null;
+                try {
+                    final int lastSubtypeHash = Integer.parseInt(lastIme.second);
+                    final int lastSubtypeId =
+                            InputMethodUtils.getSubtypeIdFromHashCode(lastImi, lastSubtypeHash);
+                    if (lastSubtypeId < 0 || lastSubtypeId >= lastImi.getSubtypeCount()) {
+                        return null;
+                    }
+                    return lastImi.getSubtypeAt(lastSubtypeId);
+                } catch (NumberFormatException e) {
+                    return null;
+                }
             }
-        }
+        });
     }
 
     @Override
@@ -3981,9 +4002,11 @@
      * @return {@link WindowManagerInternal#getInputMethodWindowVisibleHeight(int)}
      */
     @Override
-    public int getInputMethodWindowVisibleHeight() {
-        // TODO(yukawa): Should we verify the display ID?
-        return mWindowManagerInternal.getInputMethodWindowVisibleHeight(mCurTokenDisplayId);
+    public void getInputMethodWindowVisibleHeight(IIntResultCallback resultCallback) {
+        CallbackUtils.onResult(resultCallback, () -> {
+            // TODO(yukawa): Should we verify the display ID?
+            return mWindowManagerInternal.getInputMethodWindowVisibleHeight(mCurTokenDisplayId);
+        });
     }
 
     @Override
@@ -4950,17 +4973,21 @@
     }
 
     /**
-     * @return Return the current subtype of this input method.
+     * Gets the current subtype of this input method.
+     *
+     * @param resultCallback to callback the result.
      */
     @Override
-    public InputMethodSubtype getCurrentInputMethodSubtype() {
-        synchronized (mMethodMap) {
-            // TODO: Make this work even for non-current users?
-            if (!calledFromValidUserLocked()) {
-                return null;
+    public void getCurrentInputMethodSubtype(IInputMethodSubtypeResultCallback resultCallback) {
+        CallbackUtils.onResult(resultCallback, () -> {
+            synchronized (mMethodMap) {
+                // TODO: Make this work even for non-current users?
+                if (!calledFromValidUserLocked()) {
+                    return null;
+                }
+                return getCurrentInputMethodSubtypeLocked();
             }
-            return getCurrentInputMethodSubtypeLocked();
-        }
+        });
     }
 
     InputMethodSubtype getCurrentInputMethodSubtypeLocked() {
diff --git a/services/core/java/com/android/server/inputmethod/MultiClientInputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/MultiClientInputMethodManagerService.java
index ccb78a4..3485881 100644
--- a/services/core/java/com/android/server/inputmethod/MultiClientInputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/MultiClientInputMethodManagerService.java
@@ -75,6 +75,10 @@
 import com.android.internal.inputmethod.CallbackUtils;
 import com.android.internal.inputmethod.IBooleanResultCallback;
 import com.android.internal.inputmethod.IInputBindResultResultCallback;
+import com.android.internal.inputmethod.IInputMethodInfoListResultCallback;
+import com.android.internal.inputmethod.IInputMethodSubtypeListResultCallback;
+import com.android.internal.inputmethod.IInputMethodSubtypeResultCallback;
+import com.android.internal.inputmethod.IIntResultCallback;
 import com.android.internal.inputmethod.IMultiClientInputMethod;
 import com.android.internal.inputmethod.IMultiClientInputMethodPrivilegedOperations;
 import com.android.internal.inputmethod.IMultiClientInputMethodSession;
@@ -1457,35 +1461,42 @@
 
         @BinderThread
         @Override
-        public List<InputMethodInfo> getInputMethodList(@UserIdInt int userId) {
-            if (UserHandle.getCallingUserId() != userId) {
-                mContext.enforceCallingPermission(INTERACT_ACROSS_USERS_FULL, null);
-            }
-            return mInputMethodInfoMap.getAsList(userId);
+        public void getInputMethodList(@UserIdInt int userId,
+                IInputMethodInfoListResultCallback resultCallback) {
+            CallbackUtils.onResult(resultCallback, () -> {
+                if (UserHandle.getCallingUserId() != userId) {
+                    mContext.enforceCallingPermission(INTERACT_ACROSS_USERS_FULL, null);
+                }
+                return mInputMethodInfoMap.getAsList(userId);
+            });
         }
 
         @BinderThread
         @Override
-        public List<InputMethodInfo> getEnabledInputMethodList(@UserIdInt int userId) {
-            if (UserHandle.getCallingUserId() != userId) {
-                mContext.enforceCallingPermission(INTERACT_ACROSS_USERS_FULL, null);
-            }
-            return mInputMethodInfoMap.getAsList(userId);
+        public void getEnabledInputMethodList(@UserIdInt int userId,
+                IInputMethodInfoListResultCallback resultCallback) {
+            CallbackUtils.onResult(resultCallback, () -> {
+                if (UserHandle.getCallingUserId() != userId) {
+                    mContext.enforceCallingPermission(INTERACT_ACROSS_USERS_FULL, null);
+                }
+                return mInputMethodInfoMap.getAsList(userId);
+            });
         }
 
         @BinderThread
         @Override
-        public List<InputMethodSubtype> getEnabledInputMethodSubtypeList(String imiId,
-                boolean allowsImplicitlySelectedSubtypes) {
+        public void getEnabledInputMethodSubtypeList(String imiId,
+                boolean allowsImplicitlySelectedSubtypes,
+                IInputMethodSubtypeListResultCallback resultCallback) {
             reportNotSupported();
-            return Collections.emptyList();
+            CallbackUtils.onResult(resultCallback, Collections::emptyList);
         }
 
         @BinderThread
         @Override
-        public InputMethodSubtype getLastInputMethodSubtype() {
+        public void getLastInputMethodSubtype(IInputMethodSubtypeResultCallback resultCallback) {
             reportNotSupported();
-            return null;
+            CallbackUtils.onResult(resultCallback, () -> null);
         }
 
         @BinderThread
@@ -1793,9 +1804,9 @@
 
         @BinderThread
         @Override
-        public InputMethodSubtype getCurrentInputMethodSubtype() {
+        public void getCurrentInputMethodSubtype(IInputMethodSubtypeResultCallback resultCallback) {
             reportNotSupported();
-            return null;
+            CallbackUtils.onResult(resultCallback, () -> null);
         }
 
         @BinderThread
@@ -1806,9 +1817,9 @@
 
         @BinderThread
         @Override
-        public int getInputMethodWindowVisibleHeight() {
+        public void getInputMethodWindowVisibleHeight(IIntResultCallback resultCallback) {
             reportNotSupported();
-            return 0;
+            CallbackUtils.onResult(resultCallback, () -> 0);
         }
 
         @BinderThread
diff --git a/services/core/java/com/android/server/location/LocationManagerService.java b/services/core/java/com/android/server/location/LocationManagerService.java
index 324332f..9068287 100644
--- a/services/core/java/com/android/server/location/LocationManagerService.java
+++ b/services/core/java/com/android/server/location/LocationManagerService.java
@@ -47,7 +47,7 @@
 import android.location.Geofence;
 import android.location.GnssCapabilities;
 import android.location.GnssMeasurementCorrections;
-import android.location.GnssRequest;
+import android.location.GnssMeasurementRequest;
 import android.location.IGeocodeListener;
 import android.location.IGnssAntennaInfoListener;
 import android.location.IGnssMeasurementsListener;
@@ -859,7 +859,7 @@
     }
 
     @Override
-    public void addGnssMeasurementsListener(@Nullable GnssRequest request,
+    public void addGnssMeasurementsListener(@Nullable GnssMeasurementRequest request,
             IGnssMeasurementsListener listener, String packageName, String attributionTag) {
         if (mGnssManagerService != null) {
             mGnssManagerService.addGnssMeasurementsListener(request, listener, packageName,
diff --git a/services/core/java/com/android/server/location/contexthub/ContextHubClientBroker.java b/services/core/java/com/android/server/location/contexthub/ContextHubClientBroker.java
index 20458b4..cc510fb 100644
--- a/services/core/java/com/android/server/location/contexthub/ContextHubClientBroker.java
+++ b/services/core/java/com/android/server/location/contexthub/ContextHubClientBroker.java
@@ -39,6 +39,10 @@
 
 import com.android.server.location.ClientBrokerProto;
 
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.function.Supplier;
 
@@ -119,6 +123,13 @@
     private final boolean mHasAccessContextHubPermission;
 
     /*
+     * The set of nanoapp IDs that represent the group of nanoapps this client has a messaging
+     * channel with, i.e. has sent or received messages from this particular nanoapp.
+     */
+    private final Set<Long> mMessageChannelNanoappIdSet =
+            Collections.newSetFromMap(new ConcurrentHashMap<Long, Boolean>());
+
+    /*
      * Helper class to manage registered PendingIntent requests from the client.
      */
     private class PendingIntentRequest {
@@ -134,7 +145,8 @@
 
         private boolean mValid = false;
 
-        PendingIntentRequest() {}
+        PendingIntentRequest() {
+        }
 
         PendingIntentRequest(PendingIntent pendingIntent, long nanoAppId) {
             mPendingIntent = pendingIntent;
@@ -177,7 +189,7 @@
         mPackage = mContext.getPackageManager().getNameForUid(Binder.getCallingUid());
 
         mHasAccessContextHubPermission = context.checkCallingPermission(
-            Manifest.permission.ACCESS_CONTEXT_HUB) == PERMISSION_GRANTED;
+                Manifest.permission.ACCESS_CONTEXT_HUB) == PERMISSION_GRANTED;
     }
 
     /* package */ ContextHubClientBroker(
@@ -193,7 +205,7 @@
         mPackage = pendingIntent.getCreatorPackage();
 
         mHasAccessContextHubPermission = context.checkCallingPermission(
-            Manifest.permission.ACCESS_CONTEXT_HUB) == PERMISSION_GRANTED;
+                Manifest.permission.ACCESS_CONTEXT_HUB) == PERMISSION_GRANTED;
     }
 
     /**
@@ -209,6 +221,7 @@
 
         int result;
         if (isRegistered()) {
+            mMessageChannelNanoappIdSet.add(message.getNanoAppId());
             ContextHubMsg messageToNanoApp =
                     ContextHubServiceUtil.createHidlContextHubMessage(mHostEndPointId, message);
 
@@ -269,6 +282,7 @@
      * @param message the message that came from a nanoapp
      */
     /* package */ void sendMessageToClient(NanoAppMessage message) {
+        mMessageChannelNanoappIdSet.add(message.getNanoAppId());
         invokeCallback(callback -> callback.onMessageFromNanoApp(message));
 
         Supplier<Intent> supplier =
@@ -413,7 +427,7 @@
     /**
      * Sends an intent to any existing PendingIntent
      *
-     * @param supplier method to create the extra Intent
+     * @param supplier  method to create the extra Intent
      * @param nanoAppId the ID of the nanoapp which this event is for
      */
     private synchronized void sendPendingIntent(Supplier<Intent> supplier, long nanoAppId) {
@@ -427,7 +441,7 @@
      * Sends a PendingIntent with extra Intent data
      *
      * @param pendingIntent the PendingIntent
-     * @param intent the extra Intent data
+     * @param intent        the extra Intent data
      */
     private void doSendPendingIntent(PendingIntent pendingIntent, Intent intent) {
         try {
@@ -500,6 +514,17 @@
         } else {
             out += "package: " + mPackage;
         }
+        if (mMessageChannelNanoappIdSet.size() > 0) {
+            out += " messageChannelNanoappSet: (";
+            Iterator<Long> it = mMessageChannelNanoappIdSet.iterator();
+            while (it.hasNext()) {
+                out += "0x" + Long.toHexString(it.next());
+                if (it.hasNext()) {
+                    out += ",";
+                }
+            }
+            out += ")";
+        }
         out += "]";
 
         return out;
diff --git a/services/core/java/com/android/server/location/gnss/GnssManagerService.java b/services/core/java/com/android/server/location/gnss/GnssManagerService.java
index 326265f..fa137aa 100644
--- a/services/core/java/com/android/server/location/gnss/GnssManagerService.java
+++ b/services/core/java/com/android/server/location/gnss/GnssManagerService.java
@@ -21,9 +21,9 @@
 import android.content.Context;
 import android.location.GnssAntennaInfo;
 import android.location.GnssMeasurementCorrections;
+import android.location.GnssMeasurementRequest;
 import android.location.GnssMeasurementsEvent;
 import android.location.GnssNavigationMessage;
-import android.location.GnssRequest;
 import android.location.IGnssAntennaInfoListener;
 import android.location.IGnssMeasurementsListener;
 import android.location.IGnssNavigationMessageListener;
@@ -176,12 +176,10 @@
     /**
      * Adds a GNSS measurements listener.
      */
-    public void addGnssMeasurementsListener(GnssRequest request, IGnssMeasurementsListener listener,
-            String packageName, @Nullable String attributionTag) {
+    public void addGnssMeasurementsListener(GnssMeasurementRequest request,
+            IGnssMeasurementsListener listener, String packageName,
+            @Nullable String attributionTag) {
         mContext.enforceCallingOrSelfPermission(Manifest.permission.ACCESS_FINE_LOCATION, null);
-        if (request.isFullTracking()) {
-            mContext.enforceCallingOrSelfPermission(Manifest.permission.LOCATION_HARDWARE, null);
-        }
 
         CallerIdentity identity = CallerIdentity.fromBinder(mContext, packageName, attributionTag);
         mGnssMeasurementsProvider.addListener(request, identity, listener);
diff --git a/services/core/java/com/android/server/location/gnss/GnssMeasurementsProvider.java b/services/core/java/com/android/server/location/gnss/GnssMeasurementsProvider.java
index 59a533c..fa8e2a6 100644
--- a/services/core/java/com/android/server/location/gnss/GnssMeasurementsProvider.java
+++ b/services/core/java/com/android/server/location/gnss/GnssMeasurementsProvider.java
@@ -21,8 +21,8 @@
 
 import android.annotation.Nullable;
 import android.app.AppOpsManager;
+import android.location.GnssMeasurementRequest;
 import android.location.GnssMeasurementsEvent;
-import android.location.GnssRequest;
 import android.location.IGnssMeasurementsListener;
 import android.location.util.identity.CallerIdentity;
 import android.os.IBinder;
@@ -47,18 +47,18 @@
  * @hide
  */
 public final class GnssMeasurementsProvider extends
-        GnssListenerMultiplexer<GnssRequest, IGnssMeasurementsListener, Boolean> implements
-        SettingsHelper.GlobalSettingChangedListener {
+        GnssListenerMultiplexer<GnssMeasurementRequest, IGnssMeasurementsListener, Boolean>
+        implements SettingsHelper.GlobalSettingChangedListener {
 
     private class GnssMeasurementListenerRegistration extends GnssListenerRegistration {
 
         private static final String GNSS_MEASUREMENTS_BUCKET = "gnss_measurement";
 
         protected GnssMeasurementListenerRegistration(
-                @Nullable GnssRequest gnssRequest,
+                @Nullable GnssMeasurementRequest request,
                 CallerIdentity callerIdentity,
                 IGnssMeasurementsListener iGnssMeasurementsListener) {
-            super(gnssRequest, callerIdentity, iGnssMeasurementsListener);
+            super(request, callerIdentity, iGnssMeasurementsListener);
         }
 
         @Nullable
@@ -100,13 +100,13 @@
     }
 
     @Override
-    public void addListener(GnssRequest request, CallerIdentity identity,
+    public void addListener(GnssMeasurementRequest request, CallerIdentity identity,
             IGnssMeasurementsListener listener) {
         super.addListener(request, identity, listener);
     }
 
     @Override
-    protected GnssListenerRegistration createRegistration(GnssRequest request,
+    protected GnssListenerRegistration createRegistration(GnssMeasurementRequest request,
             CallerIdentity callerIdentity, IGnssMeasurementsListener listener) {
         return new GnssMeasurementListenerRegistration(request, callerIdentity, listener);
     }
diff --git a/services/core/java/com/android/server/media/BluetoothRouteProvider.java b/services/core/java/com/android/server/media/BluetoothRouteProvider.java
index 7afa81a..8a13969 100644
--- a/services/core/java/com/android/server/media/BluetoothRouteProvider.java
+++ b/services/core/java/com/android/server/media/BluetoothRouteProvider.java
@@ -439,6 +439,7 @@
             }
         }
     }
+
     private class BluetoothBroadcastReceiver extends BroadcastReceiver {
         @Override
         public void onReceive(Context context, Intent intent) {
diff --git a/services/core/java/com/android/server/media/MediaSessionService.java b/services/core/java/com/android/server/media/MediaSessionService.java
index 4be7689..17ceb15 100644
--- a/services/core/java/com/android/server/media/MediaSessionService.java
+++ b/services/core/java/com/android/server/media/MediaSessionService.java
@@ -16,6 +16,7 @@
 
 package com.android.server.media;
 
+import static android.Manifest.permission.INTERACT_ACROSS_USERS_FULL;
 import static android.os.UserHandle.ALL;
 import static android.os.UserHandle.CURRENT;
 
@@ -1115,8 +1116,7 @@
             final long token = Binder.clearCallingIdentity();
             try {
                 enforcePackageName(packageName, uid);
-                int resolvedUserId = ActivityManager.handleIncomingUser(pid, uid, userId,
-                        false /* allowAll */, true /* requireFull */, "createSession", packageName);
+                int resolvedUserId = handleIncomingUser(pid, uid, userId, packageName);
                 if (cb == null) {
                     throw new IllegalArgumentException("Controller callback cannot be null");
                 }
@@ -1191,11 +1191,8 @@
             final long token = Binder.clearCallingIdentity();
 
             try {
-                // Check that they can make calls on behalf of the user and
-                // get the final user id
-                int resolvedUserId = ActivityManager.handleIncomingUser(pid, uid, userId,
-                        true /* allowAll */, true /* requireFull */, "getSession2Tokens",
-                        null /* optional packageName */);
+                // Check that they can make calls on behalf of the user and get the final user id
+                int resolvedUserId = handleIncomingUser(pid, uid, userId, null);
                 List<Session2Token> result;
                 synchronized (mLock) {
                     FullUserRecord user = getFullUserRecordLocked(userId);
@@ -1262,9 +1259,7 @@
 
             try {
                 // Check that they can make calls on behalf of the user and get the final user id.
-                int resolvedUserId = ActivityManager.handleIncomingUser(pid, uid, userId,
-                        true /* allowAll */, true /* requireFull */, "addSession2TokensListener",
-                        null /* optional packageName */);
+                int resolvedUserId = handleIncomingUser(pid, uid, userId, null);
                 synchronized (mLock) {
                     int index = findIndexOfSession2TokensListenerLocked(listener);
                     if (index >= 0) {
@@ -1981,16 +1976,40 @@
                 packageName = componentName.getPackageName();
                 enforcePackageName(packageName, uid);
             }
-            // Check that they can make calls on behalf of the user and
-            // get the final user id
-            int resolvedUserId = ActivityManager.handleIncomingUser(pid, uid, userId,
-                    true /* allowAll */, true /* requireFull */, "getSessions", packageName);
-            // Check if they have the permissions or their component is
-            // enabled for the user they're calling from.
+            // Check that they can make calls on behalf of the user and get the final user id
+            int resolvedUserId = handleIncomingUser(pid, uid, userId, packageName);
+            // Check if they have the permissions or their component is enabled for the user
+            // they're calling from.
             enforceMediaPermissions(componentName, pid, uid, resolvedUserId);
             return resolvedUserId;
         }
 
+        // Handles incoming user by checking whether the caller has permission to access the
+        // given user id's information or not. Permission is not necessary if the given user id is
+        // equal to the caller's user id, but if not, the caller needs to have the
+        // INTERACT_ACROSS_USERS_FULL permission. Otherwise, a security exception will be thrown.
+        // The return value will be the given user id, unless the given user id is
+        // UserHandle.CURRENT, which will return the ActivityManager.getCurrentUser() value instead.
+        private int handleIncomingUser(int pid, int uid, int userId, String packageName) {
+            int callingUserId = UserHandle.getUserHandleForUid(uid).getIdentifier();
+            if (userId == callingUserId) {
+                return userId;
+            }
+
+            boolean canInteractAcrossUsersFull = mContext.checkPermission(
+                    INTERACT_ACROSS_USERS_FULL, pid, uid) == PackageManager.PERMISSION_GRANTED;
+            if (canInteractAcrossUsersFull) {
+                if (userId == CURRENT.getIdentifier()) {
+                    return ActivityManager.getCurrentUser();
+                }
+                return userId;
+            }
+
+            throw new SecurityException("Permission denied while calling from " + packageName
+                    + " with user id: " + userId + "; Need to run as either the calling user id ("
+                    + callingUserId + "), or with " + INTERACT_ACROSS_USERS_FULL + " permission");
+        }
+
         private boolean hasEnabledNotificationListener(int callingUserId,
                 String controllerPackageName, int controllerUid) {
             int controllerUserId = UserHandle.getUserHandleForUid(controllerUid).getIdentifier();
diff --git a/services/core/java/com/android/server/net/NetworkStatsCollection.java b/services/core/java/com/android/server/net/NetworkStatsCollection.java
index 342a11b..c4beddd4 100644
--- a/services/core/java/com/android/server/net/NetworkStatsCollection.java
+++ b/services/core/java/com/android/server/net/NetworkStatsCollection.java
@@ -28,9 +28,9 @@
 import static android.net.NetworkStats.TAG_NONE;
 import static android.net.NetworkStats.UID_ALL;
 import static android.net.TrafficStats.UID_REMOVED;
-import static android.net.NetworkUtils.multiplySafeByRational;
 import static android.text.format.DateUtils.WEEK_IN_MILLIS;
 
+import static com.android.internal.net.NetworkUtilsInternal.multiplySafeByRational;
 import static com.android.server.net.NetworkStatsService.TAG;
 
 import android.net.NetworkIdentity;
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index d3d998a..c9ed518 100755
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -6363,6 +6363,7 @@
         private final int mRank;
         private final int mCount;
         private final ManagedServiceInfo mListener;
+        private final long mWhen;
 
         CancelNotificationRunnable(final int callingUid, final int callingPid,
                 final String pkg, final String tag, final int id,
@@ -6382,6 +6383,7 @@
             this.mRank = rank;
             this.mCount = count;
             this.mListener = listener;
+            this.mWhen = System.currentTimeMillis();
         }
 
         @Override
@@ -6393,8 +6395,33 @@
             }
 
             synchronized (mNotificationLock) {
-                // Look for the notification, searching both the posted and enqueued lists.
-                NotificationRecord r = findNotificationLocked(mPkg, mTag, mId, mUserId);
+                // Check to see if there is a notification in the enqueued list that hasn't had a
+                // chance to post yet.
+                List<NotificationRecord> enqueued = findEnqueuedNotificationsForCriteria(
+                        mPkg, mTag, mId, mUserId);
+                boolean repost = false;
+                if (enqueued.size() > 0) {
+                    // Found something, let's see what it was
+                    repost = true;
+                    // If all enqueues happened before this cancel then wait for them to happen,
+                    // otherwise we should let this cancel through so the next enqueue happens
+                    for (NotificationRecord r : enqueued) {
+                        if (r.mUpdateTimeMs > mWhen) {
+                            // At least one enqueue was posted after the cancel, so we're invalid
+                            Slog.i(TAG, "notification cancel ignored due to newer enqueued entry"
+                                    + "key=" + r.getSbn().getKey());
+                            return;
+                        }
+                    }
+                }
+                if (repost) {
+                    mHandler.post(this);
+                    return;
+                }
+
+                // Look for the notification in the posted list, since we already checked enqueued.
+                NotificationRecord r =
+                        findNotificationByListLocked(mNotificationList, mPkg, mTag, mId, mUserId);
                 if (r != null) {
                     // The notification was found, check if it should be removed.
 
@@ -6417,6 +6444,10 @@
                     if ((r.getNotification().flags & mMustNotHaveFlags) != 0) {
                         return;
                     }
+                    if (r.getUpdateTimeMs() > mWhen) {
+                        // In this case, a post must have slipped by when this runnable reposted
+                        return;
+                    }
 
                     // Bubbled children get to stick around if the summary was manually cancelled
                     // (user removed) from systemui.
diff --git a/services/core/java/com/android/server/pm/AppsFilter.java b/services/core/java/com/android/server/pm/AppsFilter.java
index b131aff..094be06 100644
--- a/services/core/java/com/android/server/pm/AppsFilter.java
+++ b/services/core/java/com/android/server/pm/AppsFilter.java
@@ -55,6 +55,12 @@
 import com.android.server.compat.CompatChange;
 import com.android.server.om.OverlayReferenceMapper;
 import com.android.server.pm.parsing.pkg.AndroidPackage;
+import com.android.server.utils.Snappable;
+import com.android.server.utils.Snapshots;
+import com.android.server.utils.Watchable;
+import com.android.server.utils.WatchableImpl;
+import com.android.server.utils.WatchedArrayMap;
+import com.android.server.utils.Watcher;
 
 import java.io.PrintWriter;
 import java.util.Arrays;
@@ -69,7 +75,7 @@
  * manifests.
  */
 @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
-public class AppsFilter {
+public class AppsFilter implements Watchable, Snappable {
 
     private static final String TAG = "AppsFilter";
 
@@ -145,6 +151,55 @@
     @GuardedBy("mCacheLock")
     private volatile SparseArray<SparseBooleanArray> mShouldFilterCache;
 
+    /**
+     * A cached snapshot.
+     */
+    private volatile AppsFilter mSnapshot = null;
+
+    /**
+     * Watchable machinery
+     */
+    private final WatchableImpl mWatchable = new WatchableImpl();
+
+    /**
+     * Ensures an observer is in the list, exactly once. The observer cannot be null.  The
+     * function quietly returns if the observer is already in the list.
+     *
+     * @param observer The {@link Watcher} to be notified when the {@link Watchable} changes.
+     */
+    public void registerObserver(@NonNull Watcher observer) {
+        mWatchable.registerObserver(observer);
+    }
+
+    /**
+     * Ensures an observer is not in the list. The observer must not be null.  The function
+     * quietly returns if the objserver is not in the list.
+     *
+     * @param observer The {@link Watcher} that should not be in the notification list.
+     */
+    public void unregisterObserver(@NonNull Watcher observer) {
+        mWatchable.unregisterObserver(observer);
+    }
+
+    /**
+     * Invokes {@link Watcher#onChange} on each registered observer.  The method can be called
+     * with the {@link Watchable} that generated the event.  In a tree of {@link Watchable}s, this
+     * is generally the first (deepest) {@link Watchable} to detect a change.
+     *
+     * @param what The {@link Watchable} that generated the event.
+     */
+    public void dispatchChange(@Nullable Watchable what) {
+        mSnapshot = null;
+        mWatchable.dispatchChange(what);
+    }
+
+    /**
+     * Report a change to observers.
+     */
+    private void onChanged() {
+        dispatchChange(this);
+    }
+
     @VisibleForTesting(visibility = PRIVATE)
     AppsFilter(StateProvider stateProvider,
             FeatureConfig featureConfig,
@@ -162,6 +217,44 @@
     }
 
     /**
+     * The copy constructor is used by PackageManagerService to construct a snapshot.
+     * Attributes are not deep-copied since these are supposed to be immutable.
+     * TODO: deep-copy the attributes, if necessary.
+     */
+    private AppsFilter(AppsFilter orig) {
+        Snapshots.copy(mImplicitlyQueryable, orig.mImplicitlyQueryable);
+        Snapshots.copy(mQueriesViaPackage, orig.mQueriesViaPackage);
+        Snapshots.copy(mQueriesViaComponent, orig.mQueriesViaComponent);
+        mQueriesViaComponentRequireRecompute = orig.mQueriesViaComponentRequireRecompute;
+        mForceQueryable.addAll(orig.mForceQueryable);
+        mForceQueryableByDevicePackageNames = orig.mForceQueryableByDevicePackageNames;
+        mSystemAppsQueryable = orig.mSystemAppsQueryable;
+        mFeatureConfig = orig.mFeatureConfig;
+        mOverlayReferenceMapper = orig.mOverlayReferenceMapper;
+        mStateProvider = orig.mStateProvider;
+        mSystemSigningDetails = orig.mSystemSigningDetails;
+        mProtectedBroadcasts = orig.mProtectedBroadcasts;
+        mShouldFilterCache = orig.mShouldFilterCache;
+
+        mBackgroundExecutor = null;
+    }
+
+    /**
+     * Return a snapshot.  If the cached snapshot is null, build a new one.  The logic in
+     * the function ensures that this function returns a valid snapshot even if a race
+     * condition causes the cached snapshot to be cleared asynchronously to this method.
+     */
+    public AppsFilter snapshot() {
+        AppsFilter s = mSnapshot;
+        if (s == null) {
+            s = new AppsFilter(this);
+            s.mWatchable.seal();
+            mSnapshot = s;
+        }
+        return s;
+    }
+
+    /**
      * Provides system state to AppsFilter via {@link CurrentStateCallback} after properly guarding
      * the data with the package lock.
      */
@@ -311,6 +404,9 @@
             } else {
                 mDisabledPackages.add(pkg.getPackageName());
             }
+            if (mAppsFilter != null) {
+                mAppsFilter.onChanged();
+            }
         }
 
         @Override
@@ -347,7 +443,7 @@
         }
         final StateProvider stateProvider = command -> {
             synchronized (injector.getLock()) {
-                command.currentState(injector.getSettings().getPackagesLocked(),
+                command.currentState(injector.getSettings().getPackagesLocked().untrackedMap(),
                         injector.getUserManagerInternal().getUserInfos());
             }
         };
@@ -482,7 +578,8 @@
      */
     public void grantImplicitAccess(int recipientUid, int visibleUid) {
         if (recipientUid != visibleUid) {
-            if (mImplicitlyQueryable.add(recipientUid, visibleUid) && DEBUG_LOGGING) {
+            final boolean changed = mImplicitlyQueryable.add(recipientUid, visibleUid);
+            if (changed && DEBUG_LOGGING) {
                 Slog.i(TAG, "implicit access granted: " + recipientUid + " -> " + visibleUid);
             }
             synchronized (mCacheLock) {
@@ -497,6 +594,9 @@
                     visibleUids.put(visibleUid, false);
                 }
             }
+            if (changed) {
+                onChanged();
+            }
         }
     }
 
@@ -505,6 +605,7 @@
         mFeatureConfig.onSystemReady();
 
         updateEntireShouldFilterCacheAsync();
+        onChanged();
     }
 
     /**
@@ -530,6 +631,7 @@
                 }
             });
         } finally {
+            onChanged();
             Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
         }
     }
@@ -712,6 +814,7 @@
         synchronized (mCacheLock) {
             if (mShouldFilterCache != null) {
                 updateEntireShouldFilterCache();
+                onChanged();
             }
         }
     }
@@ -870,6 +973,16 @@
     }
 
     /**
+     * This api does type conversion on the <existingSettings> parameter.
+     */
+    @VisibleForTesting(visibility = PRIVATE)
+    @Nullable
+    SparseArray<int[]> getVisibilityAllowList(PackageSetting setting, int[] users,
+            WatchedArrayMap<String, PackageSetting> existingSettings) {
+        return getVisibilityAllowList(setting, users, existingSettings.untrackedMap());
+    }
+
+    /**
      * Equivalent to calling {@link #addPackage(PackageSetting, boolean)} with {@code isReplace}
      * equal to {@code false}.
      * @see AppsFilter#addPackage(PackageSetting, boolean)
@@ -946,6 +1059,7 @@
                                 siblingSetting, settings, users, settings.size());
                     }
                 }
+                onChanged();
             }
         });
     }
diff --git a/services/core/java/com/android/server/pm/CrossProfileIntentResolver.java b/services/core/java/com/android/server/pm/CrossProfileIntentResolver.java
index 8e6b89a..bf7f466 100644
--- a/services/core/java/com/android/server/pm/CrossProfileIntentResolver.java
+++ b/services/core/java/com/android/server/pm/CrossProfileIntentResolver.java
@@ -14,21 +14,22 @@
  * limitations under the License.
  */
 
-
 package com.android.server.pm;
 
-
 import android.annotation.NonNull;
 import android.content.IntentFilter;
 
-import com.android.server.IntentResolver;
+import com.android.server.utils.Snappable;
+import com.android.server.utils.WatchableIntentResolver;
+
 import java.util.List;
 
 /**
  * Used to find a list of {@link CrossProfileIntentFilter}s that match an intent.
  */
 class CrossProfileIntentResolver
-        extends IntentResolver<CrossProfileIntentFilter, CrossProfileIntentFilter> {
+        extends WatchableIntentResolver<CrossProfileIntentFilter, CrossProfileIntentFilter>
+        implements Snappable {
     @Override
     protected CrossProfileIntentFilter[] newArray(int size) {
         return new CrossProfileIntentFilter[size];
@@ -48,4 +49,15 @@
     protected IntentFilter getIntentFilter(@NonNull CrossProfileIntentFilter input) {
         return input;
     }
+
+    /**
+     * Return a snapshot of the current object.  The snapshot is a read-only copy suitable
+     * for read-only methods.
+     * @return A snapshot of the current object.
+     */
+    public CrossProfileIntentResolver snapshot() {
+        CrossProfileIntentResolver result = new CrossProfileIntentResolver();
+        result.doCopy(this);
+        return result;
+    }
 }
diff --git a/services/core/java/com/android/server/pm/InstantAppRegistry.java b/services/core/java/com/android/server/pm/InstantAppRegistry.java
index a09640d..69d3e5c 100644
--- a/services/core/java/com/android/server/pm/InstantAppRegistry.java
+++ b/services/core/java/com/android/server/pm/InstantAppRegistry.java
@@ -24,6 +24,7 @@
 import android.content.pm.InstantAppInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageParser;
+import android.content.pm.PermissionInfo;
 import android.graphics.Bitmap;
 import android.graphics.BitmapFactory;
 import android.graphics.Canvas;
@@ -36,13 +37,13 @@
 import android.os.Message;
 import android.os.UserHandle;
 import android.os.storage.StorageManager;
+import android.permission.PermissionManager;
 import android.provider.Settings;
 import android.util.ArrayMap;
 import android.util.AtomicFile;
 import android.util.PackageUtils;
 import android.util.Slog;
 import android.util.SparseArray;
-import android.util.SparseBooleanArray;
 import android.util.TypedXmlPullParser;
 import android.util.TypedXmlSerializer;
 import android.util.Xml;
@@ -55,20 +56,23 @@
 import com.android.server.pm.parsing.PackageInfoUtils;
 import com.android.server.pm.parsing.pkg.AndroidPackage;
 import com.android.server.pm.permission.PermissionManagerServiceInternal;
+import com.android.server.utils.Snappable;
+import com.android.server.utils.Watchable;
+import com.android.server.utils.WatchableImpl;
+import com.android.server.utils.WatchedSparseArray;
+import com.android.server.utils.WatchedSparseBooleanArray;
+import com.android.server.utils.Watcher;
 
 import libcore.io.IoUtils;
 import libcore.util.HexEncoding;
 
-import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
-import org.xmlpull.v1.XmlSerializer;
 
 import java.io.File;
 import java.io.FileInputStream;
 import java.io.FileNotFoundException;
 import java.io.FileOutputStream;
 import java.io.IOException;
-import java.nio.charset.StandardCharsets;
 import java.security.SecureRandom;
 import java.util.ArrayList;
 import java.util.List;
@@ -82,7 +86,7 @@
  * pruning installed instant apps and meta-data for uninstalled instant apps
  * when free space is needed.
  */
-class InstantAppRegistry {
+class InstantAppRegistry implements Watchable, Snappable {
     private static final boolean DEBUG = false;
 
     private static final String LOG_TAG = "InstantAppRegistry";
@@ -120,7 +124,7 @@
 
     /** State for uninstalled instant apps */
     @GuardedBy("mService.mLock")
-    private SparseArray<List<UninstalledInstantAppState>> mUninstalledInstantApps;
+    private final WatchedSparseArray<List<UninstalledInstantAppState>> mUninstalledInstantApps;
 
     /**
      * Automatic grants for access to instant app metadata.
@@ -129,17 +133,90 @@
      * UserID -> TargetAppId -> InstantAppId
      */
     @GuardedBy("mService.mLock")
-    private SparseArray<SparseArray<SparseBooleanArray>> mInstantGrants;
+    private final WatchedSparseArray<WatchedSparseArray<WatchedSparseBooleanArray>> mInstantGrants;
 
     /** The set of all installed instant apps. UserID -> AppID */
     @GuardedBy("mService.mLock")
-    private SparseArray<SparseBooleanArray> mInstalledInstantAppUids;
+    private final WatchedSparseArray<WatchedSparseBooleanArray> mInstalledInstantAppUids;
+
+    /**
+     * The cached snapshot
+     */
+    private volatile InstantAppRegistry mSnapshot = null;
+
+    /**
+     * Watchable machinery
+     */
+    private final WatchableImpl mWatchable = new WatchableImpl();
+    public void registerObserver(@NonNull Watcher observer) {
+        mWatchable.registerObserver(observer);
+    }
+    public void unregisterObserver(@NonNull Watcher observer) {
+        mWatchable.unregisterObserver(observer);
+    }
+    public void dispatchChange(@Nullable Watchable what) {
+        mSnapshot = null;
+        mWatchable.dispatchChange(what);
+    }
+    /**
+     * Notify listeners that this object has changed.
+     */
+    private void onChanged() {
+        dispatchChange(this);
+    }
+
+    /** The list of observers */
+    private final Watcher mObserver = new Watcher() {
+            @Override
+            public void onChange(@Nullable Watchable what) {
+                InstantAppRegistry.this.onChanged();
+            }
+        };
 
     public InstantAppRegistry(PackageManagerService service,
             PermissionManagerServiceInternal permissionManager) {
         mService = service;
         mPermissionManager = permissionManager;
         mCookiePersistence = new CookiePersistence(BackgroundThread.getHandler().getLooper());
+
+        mUninstalledInstantApps = new WatchedSparseArray<List<UninstalledInstantAppState>>();
+        mInstantGrants = new WatchedSparseArray<WatchedSparseArray<WatchedSparseBooleanArray>>();
+        mInstalledInstantAppUids = new WatchedSparseArray<WatchedSparseBooleanArray>();
+
+        mUninstalledInstantApps.registerObserver(mObserver);
+        mInstantGrants.registerObserver(mObserver);
+        mInstalledInstantAppUids.registerObserver(mObserver);
+    }
+
+    /**
+     * The copy constructor is used by PackageManagerService to construct a snapshot.
+     */
+    private InstantAppRegistry(InstantAppRegistry r) {
+        mService = r.mService;
+        mPermissionManager = r.mPermissionManager;
+        mCookiePersistence = null;
+
+        mUninstalledInstantApps = new WatchedSparseArray<List<UninstalledInstantAppState>>(
+            r.mUninstalledInstantApps);
+        mInstantGrants = new WatchedSparseArray<WatchedSparseArray<WatchedSparseBooleanArray>>(
+            r.mInstantGrants);
+        mInstalledInstantAppUids = new WatchedSparseArray<WatchedSparseBooleanArray>(
+            r.mInstalledInstantAppUids);
+
+        // Do not register any observers.  This is a clone
+    }
+
+    /**
+     * Return a snapshot: the value is the cached snapshot if available.
+     */
+    public InstantAppRegistry snapshot() {
+        InstantAppRegistry s = mSnapshot;
+        if (s == null) {
+            s = new InstantAppRegistry(this);
+            s.mWatchable.seal();
+            mSnapshot = s;
+        }
+        return s;
     }
 
     @GuardedBy("mService.mLock")
@@ -370,37 +447,20 @@
 
     @GuardedBy("mService.mLock")
     public void onUserRemovedLPw(int userId) {
-        if (mUninstalledInstantApps != null) {
-            mUninstalledInstantApps.remove(userId);
-            if (mUninstalledInstantApps.size() <= 0) {
-                mUninstalledInstantApps = null;
-            }
-        }
-        if (mInstalledInstantAppUids != null) {
-            mInstalledInstantAppUids.remove(userId);
-            if (mInstalledInstantAppUids.size() <= 0) {
-                mInstalledInstantAppUids = null;
-            }
-        }
-        if (mInstantGrants != null) {
-            mInstantGrants.remove(userId);
-            if (mInstantGrants.size() <= 0) {
-                mInstantGrants = null;
-            }
-        }
+        mUninstalledInstantApps.remove(userId);
+        mInstalledInstantAppUids.remove(userId);
+        mInstantGrants.remove(userId);
         deleteDir(getInstantApplicationsDir(userId));
     }
 
     public boolean isInstantAccessGranted(@UserIdInt int userId, int targetAppId,
             int instantAppId) {
-        if (mInstantGrants == null) {
-            return false;
-        }
-        final SparseArray<SparseBooleanArray> targetAppList = mInstantGrants.get(userId);
+        final WatchedSparseArray<WatchedSparseBooleanArray> targetAppList =
+                mInstantGrants.get(userId);
         if (targetAppList == null) {
             return false;
         }
-        final SparseBooleanArray instantGrantList = targetAppList.get(targetAppId);
+        final WatchedSparseBooleanArray instantGrantList = targetAppList.get(targetAppId);
         if (instantGrantList == null) {
             return false;
         }
@@ -413,7 +473,7 @@
         if (mInstalledInstantAppUids == null) {
             return;     // no instant apps installed; no need to grant
         }
-        SparseBooleanArray instantAppList = mInstalledInstantAppUids.get(userId);
+        WatchedSparseBooleanArray instantAppList = mInstalledInstantAppUids.get(userId);
         if (instantAppList == null || !instantAppList.get(instantAppId)) {
             return;     // instant app id isn't installed; no need to grant
         }
@@ -426,17 +486,14 @@
                 return;  // launched via VIEW/BROWSABLE intent; no need to grant
             }
         }
-        if (mInstantGrants == null) {
-            mInstantGrants = new SparseArray<>();
-        }
-        SparseArray<SparseBooleanArray> targetAppList = mInstantGrants.get(userId);
+        WatchedSparseArray<WatchedSparseBooleanArray> targetAppList = mInstantGrants.get(userId);
         if (targetAppList == null) {
-            targetAppList = new SparseArray<>();
+            targetAppList = new WatchedSparseArray<>();
             mInstantGrants.put(userId, targetAppList);
         }
-        SparseBooleanArray instantGrantList = targetAppList.get(recipientUid);
+        WatchedSparseBooleanArray instantGrantList = targetAppList.get(recipientUid);
         if (instantGrantList == null) {
-            instantGrantList = new SparseBooleanArray();
+            instantGrantList = new WatchedSparseBooleanArray();
             targetAppList.put(recipientUid, instantGrantList);
         }
         instantGrantList.put(instantAppId, true /*granted*/);
@@ -444,15 +501,13 @@
 
     @GuardedBy("mService.mLock")
     public void addInstantAppLPw(@UserIdInt int userId, int instantAppId) {
-        if (mInstalledInstantAppUids == null) {
-            mInstalledInstantAppUids = new SparseArray<>();
-        }
-        SparseBooleanArray instantAppList = mInstalledInstantAppUids.get(userId);
+        WatchedSparseBooleanArray instantAppList = mInstalledInstantAppUids.get(userId);
         if (instantAppList == null) {
-            instantAppList = new SparseBooleanArray();
+            instantAppList = new WatchedSparseBooleanArray();
             mInstalledInstantAppUids.put(userId, instantAppList);
         }
         instantAppList.put(instantAppId, true /*installed*/);
+        onChanged();
     }
 
     @GuardedBy("mService.mLock")
@@ -461,23 +516,28 @@
         if (mInstalledInstantAppUids == null) {
             return; // no instant apps on the system
         }
-        final SparseBooleanArray instantAppList = mInstalledInstantAppUids.get(userId);
+        final WatchedSparseBooleanArray instantAppList = mInstalledInstantAppUids.get(userId);
         if (instantAppList == null) {
             return;
         }
 
-        instantAppList.delete(instantAppId);
+        try {
+            instantAppList.delete(instantAppId);
 
-        // remove any grants
-        if (mInstantGrants == null) {
-            return; // no grants on the system
-        }
-        final SparseArray<SparseBooleanArray> targetAppList = mInstantGrants.get(userId);
-        if (targetAppList == null) {
-            return; // no grants for this user
-        }
-        for (int i = targetAppList.size() - 1; i >= 0; --i) {
-            targetAppList.valueAt(i).delete(instantAppId);
+            // remove any grants
+            if (mInstantGrants == null) {
+                return; // no grants on the system
+            }
+            final WatchedSparseArray<WatchedSparseBooleanArray> targetAppList =
+                    mInstantGrants.get(userId);
+            if (targetAppList == null) {
+                return; // no grants for this user
+            }
+            for (int i = targetAppList.size() - 1; i >= 0; --i) {
+                targetAppList.valueAt(i).delete(instantAppId);
+            }
+        } finally {
+            onChanged();
         }
     }
 
@@ -487,11 +547,13 @@
         if (mInstantGrants == null) {
             return; // no grants on the system
         }
-        final SparseArray<SparseBooleanArray> targetAppList = mInstantGrants.get(userId);
+        final WatchedSparseArray<WatchedSparseBooleanArray> targetAppList =
+                mInstantGrants.get(userId);
         if (targetAppList == null) {
             return; // no grants for this user
         }
         targetAppList.delete(targetAppId);
+        onChanged();
     }
 
     @GuardedBy("mService.mLock")
@@ -502,9 +564,6 @@
         if (uninstalledApp == null) {
             return;
         }
-        if (mUninstalledInstantApps == null) {
-            mUninstalledInstantApps = new SparseArray<>();
-        }
         List<UninstalledInstantAppState> uninstalledAppStates =
                 mUninstalledInstantApps.get(userId);
         if (uninstalledAppStates == null) {
@@ -593,9 +652,7 @@
             uninstalledAppStates.remove(i);
             if (uninstalledAppStates.isEmpty()) {
                 mUninstalledInstantApps.remove(userId);
-                if (mUninstalledInstantApps.size() <= 0) {
-                    mUninstalledInstantApps = null;
-                }
+                onChanged();
                 return;
             }
         }
@@ -919,8 +976,7 @@
         final long identity = Binder.clearCallingIdentity();
         try {
             for (String grantedPermission : appInfo.getGrantedPermissions()) {
-                final boolean propagatePermission =
-                        mPermissionManager.canPropagatePermissionToInstantApp(grantedPermission);
+                final boolean propagatePermission = canPropagatePermission(grantedPermission);
                 if (propagatePermission && pkg.getRequestedPermissions().contains(
                         grantedPermission)) {
                     mService.grantRuntimePermission(pkg.getPackageName(), grantedPermission,
@@ -932,6 +988,19 @@
         }
     }
 
+    private boolean canPropagatePermission(@NonNull String permissionName) {
+        final PermissionManager permissionManager = mService.mContext.getSystemService(
+                PermissionManager.class);
+        final PermissionInfo permissionInfo = permissionManager.getPermissionInfo(permissionName,
+                0);
+        return permissionInfo != null
+                && (permissionInfo.getProtection() == PermissionInfo.PROTECTION_DANGEROUS
+                        || (permissionInfo.getProtectionFlags()
+                                & PermissionInfo.PROTECTION_FLAG_DEVELOPMENT) != 0)
+                && (permissionInfo.getProtectionFlags() & PermissionInfo.PROTECTION_FLAG_INSTANT)
+                        != 0;
+    }
+
     private @NonNull
     InstantAppInfo peekOrParseUninstalledInstantAppInfo(
             @NonNull String packageName, @UserIdInt int userId) {
@@ -994,12 +1063,7 @@
             }
         }
 
-        if (uninstalledAppStates != null) {
-            if (mUninstalledInstantApps == null) {
-                mUninstalledInstantApps = new SparseArray<>();
-            }
-            mUninstalledInstantApps.put(userId, uninstalledAppStates);
-        }
+        mUninstalledInstantApps.put(userId, uninstalledAppStates);
 
         return uninstalledAppStates;
     }
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 4cf9933..22f4a92 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -394,6 +394,7 @@
 import com.android.server.storage.DeviceStorageMonitorInternal;
 import com.android.server.uri.UriGrantsManagerInternal;
 import com.android.server.utils.TimingsTraceAndSlog;
+import com.android.server.utils.WatchedArrayMap;
 import com.android.server.wm.ActivityTaskManagerInternal;
 
 import dalvik.system.CloseGuard;
@@ -1002,7 +1003,7 @@
                 Producer<PackageParser2> scanningPackageParserProducer,
                 Producer<PackageParser2> preparingPackageParserProducer,
                 Producer<PackageInstallerService> packageInstallerServiceProducer,
-                ProducerWithArgument<InstantAppResolverConnection, ComponentName> 
+                ProducerWithArgument<InstantAppResolverConnection, ComponentName>
                         instantAppResolverConnectionProducer,
                 Producer<ModuleInfoProvider> moduleInfoProviderProducer,
                 Producer<LegacyPermissionManagerInternal> legacyPermissionManagerInternalProducer,
@@ -3302,7 +3303,8 @@
 
             // Clean up orphaned packages for which the code path doesn't exist
             // and they are an update to a system app - caused by bug/32321269
-            final ArrayMap<String, PackageSetting> packageSettings = mSettings.getPackagesLocked();
+            final WatchedArrayMap<String, PackageSetting> packageSettings =
+                mSettings.getPackagesLocked();
             final int packageSettingCount = packageSettings.size();
             for (int i = packageSettingCount - 1; i >= 0; i--) {
                 PackageSetting ps = packageSettings.valueAt(i);
@@ -4806,6 +4808,12 @@
         enforceCrossUserPermission(Binder.getCallingUid(), userId,
                 false /* requireFullPermission */, false /* checkShell */, "get package info");
 
+        return getPackageInfoInternalBody(packageName, versionCode, flags, filterCallingUid,
+                userId);
+    }
+
+    private PackageInfo getPackageInfoInternalBody(String packageName, long versionCode,
+            int flags, int filterCallingUid, int userId) {
         // reader
         synchronized (mLock) {
             // Normalize package name to handle renamed packages and static libs
@@ -5227,6 +5235,11 @@
                     "get application info");
         }
 
+        return getApplicationInfoInternalBody(packageName, flags, filterCallingUid, userId);
+    }
+
+    private ApplicationInfo getApplicationInfoInternalBody(String packageName, int flags,
+            int filterCallingUid, int userId) {
         // writer
         synchronized (mLock) {
             // Normalize package name to handle renamed packages and static libs
@@ -5659,6 +5672,11 @@
                     false /* requireFullPermission */, false /* checkShell */, "get activity info");
         }
 
+        return getActivityInfoInternalBody(component, flags, filterCallingUid, userId);
+    }
+
+    private ActivityInfo getActivityInfoInternalBody(ComponentName component, int flags,
+            int filterCallingUid, int userId) {
         synchronized (mLock) {
             ParsedActivity a = mComponentResolver.getActivity(component);
 
@@ -5965,6 +5983,11 @@
         flags = updateFlagsForComponent(flags, userId);
         enforceCrossUserOrProfilePermission(callingUid, userId, false /* requireFullPermission */,
                 false /* checkShell */, "get service info");
+        return getServiceInfoBody(component, flags, userId, callingUid);
+    }
+
+    private ServiceInfo getServiceInfoBody(ComponentName component, int flags, int userId,
+                                             int callingUid) {
         synchronized (mLock) {
             ParsedService s = mComponentResolver.getService(component);
             if (DEBUG_PACKAGE_INFO) Log.v(
@@ -6537,6 +6560,11 @@
         final boolean isCallerInstantApp = getInstantAppPackageName(callingUid) != null;
         final int userId = UserHandle.getUserId(uid);
         final int appId = UserHandle.getAppId(uid);
+        return getPackagesForUidInternalBody(callingUid, userId, appId, isCallerInstantApp);
+    }
+
+    private String[] getPackagesForUidInternalBody(int callingUid, int userId, int appId,
+                                                     boolean isCallerInstantApp) {
         // reader
         synchronized (mLock) {
             final Object obj = mSettings.getSettingLPr(appId);
@@ -6888,6 +6916,15 @@
         }
         // Deny ephemeral apps if the user chose _ALWAYS or _ALWAYS_ASK for intent resolution.
         // Or if there's already an ephemeral app installed that handles the action
+        return isInstantAppResolutionAllowedBody(intent, resolvedActivities, userId,
+                                                   skipPackageCheck);
+    }
+
+    // Deny ephemeral apps if the user chose _ALWAYS or _ALWAYS_ASK for intent resolution.
+    // Or if there's already an ephemeral app installed that handles the action
+    private boolean isInstantAppResolutionAllowedBody(
+            Intent intent, List<ResolveInfo> resolvedActivities, int userId,
+            boolean skipPackageCheck) {
         synchronized (mLock) {
             final int count = (resolvedActivities == null ? 0 : resolvedActivities.size());
             for (int n = 0; n < count; n++) {
@@ -7457,6 +7494,23 @@
                 userId, false /*resolveForStart*/, true /*allowDynamicSplits*/);
     }
 
+    // Collect the results of queryIntentActivitiesInternalBody into a single class
+    private static class QueryIntentActivitiesResult {
+        public boolean sortResult = false;
+        public boolean addInstant = false;
+        public List<ResolveInfo> result = null;
+        public List<ResolveInfo> answer = null;
+
+        QueryIntentActivitiesResult(List<ResolveInfo> l) {
+            answer = l;
+        }
+        QueryIntentActivitiesResult(boolean s, boolean a, List<ResolveInfo> l) {
+            sortResult = s;
+            addInstant = a;
+            result = l;
+        }
+    }
+
     private @NonNull List<ResolveInfo> queryIntentActivitiesInternal(Intent intent,
             String resolvedType, int flags, @PrivateResolveFlags int privateResolveFlags,
             int filterCallingUid, int userId, boolean resolveForStart, boolean allowDynamicSplits) {
@@ -7530,11 +7584,37 @@
             return result;
         }
 
+        QueryIntentActivitiesResult lockedResult =
+                queryIntentActivitiesInternalBody(
+                    intent, resolvedType, flags, filterCallingUid, userId, resolveForStart,
+                    allowDynamicSplits, pkgName, instantAppPkgName);
+        if (lockedResult.answer != null) {
+            return lockedResult.answer;
+        }
+
+        if (lockedResult.addInstant) {
+            String callingPkgName = getInstantAppPackageName(filterCallingUid);
+            boolean isRequesterInstantApp = isInstantApp(callingPkgName, userId);
+            lockedResult.result = maybeAddInstantAppInstaller(lockedResult.result, intent,
+                    resolvedType, flags, userId, resolveForStart, isRequesterInstantApp);
+        }
+        if (lockedResult.sortResult) {
+            Collections.sort(lockedResult.result, RESOLVE_PRIORITY_SORTER);
+        }
+        return applyPostResolutionFilter(
+                lockedResult.result, instantAppPkgName, allowDynamicSplits, filterCallingUid,
+                resolveForStart, userId, intent);
+    }
+
+    private @NonNull QueryIntentActivitiesResult queryIntentActivitiesInternalBody(
+            Intent intent, String resolvedType, int flags, int filterCallingUid, int userId,
+            boolean resolveForStart, boolean allowDynamicSplits, String pkgName,
+            String instantAppPkgName) {
         // reader
-        boolean sortResult = false;
-        boolean addInstant = false;
-        List<ResolveInfo> result;
         synchronized (mLock) {
+            boolean sortResult = false;
+            boolean addInstant = false;
+            List<ResolveInfo> result = null;
             if (pkgName == null) {
                 List<CrossProfileIntentFilter> matchingFilters =
                         getMatchingCrossProfileIntentFilters(intent, resolvedType, userId);
@@ -7544,9 +7624,11 @@
                 if (xpResolveInfo != null) {
                     List<ResolveInfo> xpResult = new ArrayList<>(1);
                     xpResult.add(xpResolveInfo);
-                    return applyPostResolutionFilter(
-                            filterIfNotSystemUser(xpResult, userId), instantAppPkgName,
-                            allowDynamicSplits, filterCallingUid, resolveForStart, userId, intent);
+                    return new QueryIntentActivitiesResult(
+                            applyPostResolutionFilter(
+                                    filterIfNotSystemUser(xpResult, userId), instantAppPkgName,
+                                    allowDynamicSplits, filterCallingUid, resolveForStart, userId,
+                                    intent));
                 }
 
                 // Check for results in the current profile.
@@ -7585,17 +7667,19 @@
                             // And we are not going to add emphemeral app, so we can return the
                             // result straight away.
                             result.add(xpDomainInfo.resolveInfo);
-                            return applyPostResolutionFilter(result, instantAppPkgName,
-                                    allowDynamicSplits, filterCallingUid, resolveForStart, userId,
-                                    intent);
+                            return new QueryIntentActivitiesResult(
+                                    applyPostResolutionFilter(result, instantAppPkgName,
+                                            allowDynamicSplits, filterCallingUid, resolveForStart,
+                                            userId, intent));
                         }
                     } else if (result.size() <= 1 && !addInstant) {
                         // No result in parent user and <= 1 result in current profile, and we
                         // are not going to add emphemeral app, so we can return the result without
                         // further processing.
-                        return applyPostResolutionFilter(result, instantAppPkgName,
+                        return new QueryIntentActivitiesResult(
+                                applyPostResolutionFilter(result, instantAppPkgName,
                                 allowDynamicSplits, filterCallingUid, resolveForStart, userId,
-                                intent);
+                                intent));
                     }
                     // We have more than one candidate (combining results from current and parent
                     // profile), so we need filtering and sorting.
@@ -7623,19 +7707,8 @@
                     }
                 }
             }
+            return new QueryIntentActivitiesResult(sortResult, addInstant, result);
         }
-        if (addInstant) {
-            String callingPkgName = getInstantAppPackageName(filterCallingUid);
-            boolean isRequesterInstantApp = isInstantApp(callingPkgName, userId);
-            result = maybeAddInstantAppInstaller(result, intent, resolvedType, flags, userId,
-                    resolveForStart, isRequesterInstantApp);
-        }
-        if (sortResult) {
-            Collections.sort(result, RESOLVE_PRIORITY_SORTER);
-        }
-        return applyPostResolutionFilter(
-                result, instantAppPkgName, allowDynamicSplits, filterCallingUid, resolveForStart,
-                userId, intent);
     }
 
     private List<ResolveInfo> maybeAddInstantAppInstaller(List<ResolveInfo> result, Intent intent,
@@ -7982,14 +8055,30 @@
                     candidates.size());
         }
 
-        final ArrayList<ResolveInfo> result = new ArrayList<>();
-        final ArrayList<ResolveInfo> alwaysList = new ArrayList<>();
-        final ArrayList<ResolveInfo> undefinedList = new ArrayList<>();
-        final ArrayList<ResolveInfo> alwaysAskList = new ArrayList<>();
-        final ArrayList<ResolveInfo> neverList = new ArrayList<>();
-        final ArrayList<ResolveInfo> matchAllList = new ArrayList<>();
+        final ArrayList<ResolveInfo> result =
+                filterCandidatesWithDomainPreferredActivitiesLPrBody(
+                    intent, matchFlags, candidates, xpDomainInfo, userId, debug);
 
+        if (DEBUG_PREFERRED || DEBUG_DOMAIN_VERIFICATION) {
+            Slog.v(TAG, "Filtered results with preferred activities. New candidates count: "
+                    + result.size());
+            for (ResolveInfo info : result) {
+                Slog.v(TAG, "  + " + info.activityInfo);
+            }
+        }
+        return result;
+    }
+
+    private ArrayList<ResolveInfo> filterCandidatesWithDomainPreferredActivitiesLPrBody(
+            Intent intent, int matchFlags, List<ResolveInfo> candidates,
+            CrossProfileDomainInfo xpDomainInfo, int userId, boolean debug) {
         synchronized (mLock) {
+            final ArrayList<ResolveInfo> result = new ArrayList<>();
+            final ArrayList<ResolveInfo> alwaysList = new ArrayList<>();
+            final ArrayList<ResolveInfo> undefinedList = new ArrayList<>();
+            final ArrayList<ResolveInfo> alwaysAskList = new ArrayList<>();
+            final ArrayList<ResolveInfo> neverList = new ArrayList<>();
+            final ArrayList<ResolveInfo> matchAllList = new ArrayList<>();
             final int count = candidates.size();
             // First, try to use linked apps. Partition the candidates into four lists:
             // one for the final results, one for the "do not use ever", one for "undefined status"
@@ -8125,15 +8214,8 @@
                     result.removeAll(neverList);
                 }
             }
+            return result;
         }
-        if (DEBUG_PREFERRED || DEBUG_DOMAIN_VERIFICATION) {
-            Slog.v(TAG, "Filtered results with preferred activities. New candidates count: " +
-                    result.size());
-            for (ResolveInfo info : result) {
-                Slog.v(TAG, "  + " + info.activityInfo);
-            }
-        }
-        return result;
     }
 
     // Returns a packed value as a long:
@@ -8632,6 +8714,13 @@
             return list;
         }
 
+        return queryIntentServicesInternalBody(intent, resolvedType, flags,
+                userId, callingUid, instantAppPkgName);
+    }
+
+    private @NonNull List<ResolveInfo> queryIntentServicesInternalBody(Intent intent,
+            String resolvedType, int flags, int userId, int callingUid,
+            String instantAppPkgName) {
         // reader
         synchronized (mLock) {
             String pkgName = intent.getPackage();
@@ -8857,15 +8946,21 @@
         }
         if (!mUserManager.exists(userId)) return ParceledListSlice.emptyList();
         flags = updateFlagsForPackage(flags, userId);
-        final boolean listUninstalled = (flags & MATCH_KNOWN_PACKAGES) != 0;
-        final boolean listApex = (flags & MATCH_APEX) != 0;
-        final boolean listFactory = (flags & MATCH_FACTORY_ONLY) != 0;
 
         enforceCrossUserPermission(callingUid, userId, false /* requireFullPermission */,
                 false /* checkShell */, "get installed packages");
 
+        return getInstalledPackagesBody(flags, userId, callingUid);
+    }
+
+    private ParceledListSlice<PackageInfo> getInstalledPackagesBody(int flags, int userId,
+                                                                      int callingUid) {
         // writer
         synchronized (mLock) {
+            final boolean listUninstalled = (flags & MATCH_KNOWN_PACKAGES) != 0;
+            final boolean listApex = (flags & MATCH_APEX) != 0;
+            final boolean listFactory = (flags & MATCH_FACTORY_ONLY) != 0;
+
             ArrayList<PackageInfo> list;
             if (listUninstalled) {
                 list = new ArrayList<>(mSettings.getPackagesLocked().size());
@@ -9115,6 +9210,11 @@
         if (HIDE_EPHEMERAL_APIS) {
             return false;
         }
+        return isInstantAppInternalBody(packageName, userId, callingUid);
+    }
+
+    private boolean isInstantAppInternalBody(String packageName, @UserIdInt int userId,
+            int callingUid) {
         synchronized (mLock) {
             if (Process.isIsolated(callingUid)) {
                 callingUid = mIsolatedOwners.get(callingUid);
@@ -20813,8 +20913,12 @@
                 mSettings.applyDefaultPreferredAppsLPw(userId);
                 clearIntentFilterVerificationsLPw(userId);
                 primeDomainVerificationsLPw(userId);
+                final int numPackages = mPackages.size();
+                for (int i = 0; i < numPackages; i++) {
+                    final AndroidPackage pkg = mPackages.valueAt(i);
+                    mPermissionManager.resetRuntimePermissions(pkg, userId);
+                }
             }
-            mPermissionManager.resetAllRuntimePermissions(userId);
             updateDefaultHomeNotLocked(userId);
             // TODO: We have to reset the default SMS and Phone. This requires
             // significant refactoring to keep all default apps in the package
@@ -22312,7 +22416,7 @@
         mUserManager.reconcileUsers(StorageManager.UUID_PRIVATE_INTERNAL);
         reconcileApps(StorageManager.UUID_PRIVATE_INTERNAL);
 
-        mPermissionManager.systemReady();
+        mPermissionManager.onSystemReady();
 
         int[] grantPermissionsUserIds = EMPTY_INT_ARRAY;
         for (int userId : UserManagerService.getInstance().getUserIds()) {
diff --git a/services/core/java/com/android/server/pm/PackageSettingBase.java b/services/core/java/com/android/server/pm/PackageSettingBase.java
index ac76cf7..67bd82b4 100644
--- a/services/core/java/com/android/server/pm/PackageSettingBase.java
+++ b/services/core/java/com/android/server/pm/PackageSettingBase.java
@@ -175,22 +175,27 @@
 
     public void setInstallerPackageName(String packageName) {
         installSource = installSource.setInstallerPackage(packageName);
+        onChanged();
     }
 
     public void setInstallSource(InstallSource installSource) {
         this.installSource = Objects.requireNonNull(installSource);
+        onChanged();
     }
 
     void removeInstallerPackage(String packageName) {
         installSource = installSource.removeInstallerPackage(packageName);
+        onChanged();
     }
 
     public void setIsOrphaned(boolean isOrphaned) {
         installSource = installSource.setIsOrphaned(isOrphaned);
+        onChanged();
     }
 
     public void setVolumeUuid(String volumeUuid) {
         this.volumeUuid = volumeUuid;
+        onChanged();
     }
 
     public String getVolumeUuid() {
@@ -199,10 +204,12 @@
 
     public void setTimeStamp(long newStamp) {
         timeStamp = newStamp;
+        onChanged();
     }
 
     public void setUpdateAvailable(boolean updateAvailable) {
         this.updateAvailable = updateAvailable;
+        onChanged();
     }
 
     public boolean isUpdateAvailable() {
@@ -272,6 +279,7 @@
         if (state == null) {
             state = new PackageUserState();
             mUserState.put(userId, state);
+            onChanged();
         }
         return state;
     }
@@ -289,6 +297,7 @@
         PackageUserState st = modifyUserState(userId);
         st.enabled = state;
         st.lastDisableAppCaller = callingPackage;
+        onChanged();
     }
 
     int getEnabled(int userId) {
@@ -434,6 +443,7 @@
         }
         existingUserState.suspendParams.put(suspendingPackage, newSuspendParams);
         existingUserState.suspended = true;
+        onChanged();
     }
 
     void removeSuspension(String suspendingPackage, int userId) {
@@ -445,6 +455,7 @@
             }
         }
         existingUserState.suspended = (existingUserState.suspendParams != null);
+        onChanged();
     }
 
     void removeSuspension(Predicate<String> suspendingPackagePredicate, int userId) {
@@ -461,6 +472,7 @@
             }
         }
         existingUserState.suspended = (existingUserState.suspendParams != null);
+        onChanged();
     }
 
     public boolean getInstantApp(int userId) {
@@ -506,6 +518,7 @@
         state.instantApp = instantApp;
         state.virtualPreload = virtualPreload;
         state.harmfulAppWarning = harmfulAppWarning;
+        onChanged();
     }
 
     void setUserState(int userId, PackageUserState otherState) {
@@ -547,11 +560,17 @@
 
     PackageUserState modifyUserStateComponents(int userId, boolean disabled, boolean enabled) {
         PackageUserState state = modifyUserState(userId);
+        boolean changed = false;
         if (disabled && state.disabledComponents == null) {
             state.disabledComponents = new ArraySet<String>(1);
+            changed = true;
         }
         if (enabled && state.enabledComponents == null) {
             state.enabledComponents = new ArraySet<String>(1);
+            changed = true;
+        }
+        if (changed) {
+            onChanged();
         }
         return state;
     }
@@ -603,6 +622,7 @@
 
     void removeUser(int userId) {
         mUserState.delete(userId);
+        onChanged();
     }
 
     public int[] getNotInstalledUserIds() {
@@ -630,6 +650,7 @@
 
     void setIntentFilterVerificationInfo(IntentFilterVerificationInfo info) {
         verificationInfo = info;
+        onChanged();
     }
 
     // Returns a packed value as a long:
@@ -648,6 +669,7 @@
         state.domainVerificationStatus = status;
         if (status == PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS) {
             state.appLinkGeneration = generation;
+            onChanged();
         }
     }
 
@@ -694,6 +716,7 @@
     void setHarmfulAppWarning(int userId, String harmfulAppWarning) {
         PackageUserState userState = modifyUserState(userId);
         userState.harmfulAppWarning = harmfulAppWarning;
+        onChanged();
     }
 
     String getHarmfulAppWarning(int userId) {
@@ -838,6 +861,7 @@
         for (int i = 0; i < other.mUserState.size(); i++) {
             mUserState.put(other.mUserState.keyAt(i), other.mUserState.valueAt(i));
         }
+        onChanged();
         return this;
     }
 }
diff --git a/services/core/java/com/android/server/pm/PersistentPreferredIntentResolver.java b/services/core/java/com/android/server/pm/PersistentPreferredIntentResolver.java
index 08a87d8..d0f9787 100644
--- a/services/core/java/com/android/server/pm/PersistentPreferredIntentResolver.java
+++ b/services/core/java/com/android/server/pm/PersistentPreferredIntentResolver.java
@@ -19,10 +19,12 @@
 import android.annotation.NonNull;
 import android.content.IntentFilter;
 
-import com.android.server.IntentResolver;
+import com.android.server.utils.Snappable;
+import com.android.server.utils.WatchableIntentResolver;
 
 public class PersistentPreferredIntentResolver
-        extends IntentResolver<PersistentPreferredActivity, PersistentPreferredActivity> {
+        extends WatchableIntentResolver<PersistentPreferredActivity, PersistentPreferredActivity>
+        implements Snappable {
     @Override
     protected PersistentPreferredActivity[] newArray(int size) {
         return new PersistentPreferredActivity[size];
@@ -37,4 +39,15 @@
     protected boolean isPackageForFilter(String packageName, PersistentPreferredActivity filter) {
         return packageName.equals(filter.mComponent.getPackageName());
     }
+
+    /**
+     * Return a snapshot of the current object.  The snapshot is a read-only copy suitable
+     * for read-only methods.
+     * @return A snapshot of the current object.
+     */
+    public PersistentPreferredIntentResolver snapshot() {
+        PersistentPreferredIntentResolver result = new PersistentPreferredIntentResolver();
+        result.doCopy(this);
+        return result;
+    }
 }
diff --git a/services/core/java/com/android/server/pm/PreferredIntentResolver.java b/services/core/java/com/android/server/pm/PreferredIntentResolver.java
index ff3df13..b62421e 100644
--- a/services/core/java/com/android/server/pm/PreferredIntentResolver.java
+++ b/services/core/java/com/android/server/pm/PreferredIntentResolver.java
@@ -19,13 +19,15 @@
 import android.annotation.NonNull;
 import android.content.IntentFilter;
 
-import java.io.PrintWriter;
+import com.android.server.utils.Snappable;
+import com.android.server.utils.WatchableIntentResolver;
 
-import com.android.server.IntentResolver;
+import java.io.PrintWriter;
 import java.util.ArrayList;
 
 public class PreferredIntentResolver
-        extends IntentResolver<PreferredActivity, PreferredActivity> {
+        extends WatchableIntentResolver<PreferredActivity, PreferredActivity>
+        implements Snappable {
     @Override
     protected PreferredActivity[] newArray(int size) {
         return new PreferredActivity[size];
@@ -66,4 +68,15 @@
         }
         return true;
     }
+
+    /**
+     * Return a snapshot of the current object.  The snapshot is a read-only copy suitable
+     * for read-only methods.
+     * @return A snapshot of the current object.
+     */
+    public PreferredIntentResolver snapshot() {
+        PreferredIntentResolver result = new PreferredIntentResolver();
+        result.doCopy(this);
+        return result;
+    }
 }
diff --git a/services/core/java/com/android/server/pm/SettingBase.java b/services/core/java/com/android/server/pm/SettingBase.java
index 968c4b5..7924d5d 100644
--- a/services/core/java/com/android/server/pm/SettingBase.java
+++ b/services/core/java/com/android/server/pm/SettingBase.java
@@ -16,17 +16,71 @@
 
 package com.android.server.pm;
 
+import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.content.pm.ApplicationInfo;
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.server.pm.permission.LegacyPermissionState;
+import com.android.server.utils.Watchable;
+import com.android.server.utils.WatchableImpl;
+import com.android.server.utils.Watcher;
 
 @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
-public abstract class SettingBase {
+public abstract class SettingBase implements Watchable {
+    // TODO: make this variable protected, or even private with a getter and setter.
+    // Simply making it protected or private requires that the name be changed to conformm
+    // to the Android naming convention, and that touches quite a few files.
     int pkgFlags;
+
+    // TODO: make this variable protected, or even private with a getter and setter.
+    // Simply making it protected or private requires that the name be changed to conformm
+    // to the Android naming convention, and that touches quite a few files.
     int pkgPrivateFlags;
 
     /**
+     * Watchable machinery
+     */
+    private final Watchable mWatchable = new WatchableImpl();
+
+    /**
+     * Ensures an observer is in the list, exactly once. The observer cannot be null.  The
+     * function quietly returns if the observer is already in the list.
+     *
+     * @param observer The {@link Watcher} to be notified when the {@link Watchable} changes.
+     */
+    public void registerObserver(@NonNull Watcher observer) {
+        mWatchable.registerObserver(observer);
+    }
+
+    /**
+     * Ensures an observer is not in the list. The observer must not be null.  The function
+     * quietly returns if the objserver is not in the list.
+     *
+     * @param observer The {@link Watcher} that should not be in the notification list.
+     */
+    public void unregisterObserver(@NonNull Watcher observer) {
+        mWatchable.unregisterObserver(observer);
+    }
+
+    /**
+     * Invokes {@link Watcher#onChange} on each registered observer.  The method can be called
+     * with the {@link Watchable} that generated the event.  In a tree of {@link Watchable}s, this
+     * is generally the first (deepest) {@link Watchable} to detect a change.
+     *
+     * @param what The {@link Watchable} that generated the event.
+     */
+    public void dispatchChange(@Nullable Watchable what) {
+        mWatchable.dispatchChange(what);
+    }
+    /**
+     * Notify listeners that this object has changed.
+     */
+    protected void onChanged() {
+        dispatchChange(this);
+    }
+
+    /**
      * The legacy permission state that is read from package settings persistence for migration.
      * This state here can not reflect the current permission state and should not be used for
      * purposes other than migration.
@@ -53,6 +107,7 @@
         pkgFlags = orig.pkgFlags;
         pkgPrivateFlags = orig.pkgPrivateFlags;
         mLegacyPermissionsState.copyFrom(orig.mLegacyPermissionsState);
+        onChanged();
     }
 
     @Deprecated
@@ -64,6 +119,7 @@
         this.pkgFlags = pkgFlags
                 & (ApplicationInfo.FLAG_SYSTEM
                         | ApplicationInfo.FLAG_EXTERNAL_STORAGE);
+        onChanged();
     }
 
     void setPrivateFlags(int pkgPrivateFlags) {
@@ -75,5 +131,6 @@
                 | ApplicationInfo.PRIVATE_FLAG_SYSTEM_EXT
                 | ApplicationInfo.PRIVATE_FLAG_REQUIRED_FOR_SYSTEM_USER
                 | ApplicationInfo.PRIVATE_FLAG_ODM);
+        onChanged();
     }
 }
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index 7482ef45..7c4dade 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -114,7 +114,14 @@
 import com.android.server.pm.permission.LegacyPermissionSettings;
 import com.android.server.pm.permission.LegacyPermissionState;
 import com.android.server.pm.permission.LegacyPermissionState.PermissionState;
+import com.android.server.utils.Snappable;
+import com.android.server.utils.Snapshots;
 import com.android.server.utils.TimingsTraceAndSlog;
+import com.android.server.utils.Watchable;
+import com.android.server.utils.WatchableImpl;
+import com.android.server.utils.WatchedArrayMap;
+import com.android.server.utils.WatchedSparseArray;
+import com.android.server.utils.Watcher;
 
 import libcore.io.IoUtils;
 
@@ -148,10 +155,58 @@
 /**
  * Holds information about dynamic settings.
  */
-public final class Settings {
+public final class Settings implements Watchable, Snappable {
     private static final String TAG = "PackageSettings";
 
     /**
+     * Cached snapshot
+     */
+    private volatile Settings mSnapshot = null;
+
+    /**
+     * Watchable machinery
+     */
+    private final WatchableImpl mWatchable = new WatchableImpl();
+
+    /**
+     * Ensures an observer is in the list, exactly once. The observer cannot be null.  The
+     * function quietly returns if the observer is already in the list.
+     *
+     * @param observer The {@link Watcher} to be notified when the {@link Watchable} changes.
+     */
+    public void registerObserver(@NonNull Watcher observer) {
+        mWatchable.registerObserver(observer);
+    }
+
+    /**
+     * Ensures an observer is not in the list. The observer must not be null.  The function
+     * quietly returns if the objserver is not in the list.
+     *
+     * @param observer The {@link Watcher} that should not be in the notification list.
+     */
+    public void unregisterObserver(@NonNull Watcher observer) {
+        mWatchable.unregisterObserver(observer);
+    }
+
+    /**
+     * Invokes {@link Watcher#onChange} on each registered observer.  The method can be called
+     * with the {@link Watchable} that generated the event.  In a tree of {@link Watchable}s, this
+     * is generally the first (deepest) {@link Watchable} to detect a change.
+     *
+     * @param what The {@link Watchable} that generated the event.
+     */
+    public void dispatchChange(@Nullable Watchable what) {
+        mSnapshot = null;
+        mWatchable.dispatchChange(what);
+    }
+    /**
+     * Notify listeners that this object has changed.
+     */
+    protected void onChanged() {
+        dispatchChange(this);
+    }
+
+    /**
      * Current version of the package database. Set it to the latest version in
      * the {@link DatabaseVersion} class below to ensure the database upgrade
      * doesn't happen repeatedly.
@@ -296,7 +351,7 @@
 
     /** Map from package name to settings */
     @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
-    final ArrayMap<String, PackageSetting> mPackages = new ArrayMap<>();
+    final WatchedArrayMap<String, PackageSetting> mPackages = new WatchedArrayMap<>();
 
     /**
      * List of packages that were involved in installing other packages, i.e. are listed
@@ -368,21 +423,21 @@
 
     // The user's preferred activities associated with particular intent
     // filters.
-    private final SparseArray<PreferredIntentResolver> mPreferredActivities =
-            new SparseArray<PreferredIntentResolver>();
+    private final WatchedSparseArray<PreferredIntentResolver>
+            mPreferredActivities = new WatchedSparseArray<>();
 
     // The persistent preferred activities of the user's profile/device owner
     // associated with particular intent filters.
-    private final SparseArray<PersistentPreferredIntentResolver> mPersistentPreferredActivities =
-            new SparseArray<PersistentPreferredIntentResolver>();
+    private final WatchedSparseArray<PersistentPreferredIntentResolver>
+            mPersistentPreferredActivities = new WatchedSparseArray<>();
 
     // For every user, it is used to find to which other users the intent can be forwarded.
-    private final SparseArray<CrossProfileIntentResolver> mCrossProfileIntentResolvers =
-            new SparseArray<CrossProfileIntentResolver>();
+    private final WatchedSparseArray<CrossProfileIntentResolver>
+            mCrossProfileIntentResolvers = new WatchedSparseArray<>();
 
     final ArrayMap<String, SharedUserSetting> mSharedUsers = new ArrayMap<>();
-    private final ArrayList<SettingBase> mAppIds = new ArrayList<>();
-    private final SparseArray<SettingBase> mOtherAppIds = new SparseArray<>();
+    private final ArrayList<SettingBase> mAppIds;
+    private final SparseArray<SettingBase> mOtherAppIds;
 
     // For reading/writing settings file.
     private final ArrayList<Signature> mPastSignatures =
@@ -415,17 +470,30 @@
 
     private final File mSystemDir;
 
-    public final KeySetManagerService mKeySetManagerService = new KeySetManagerService(mPackages);
+    public final KeySetManagerService mKeySetManagerService =
+            new KeySetManagerService(mPackages.untrackedMap());
 
     /** Settings and other information about permissions */
     final LegacyPermissionSettings mPermissions;
 
     private final LegacyPermissionDataProvider mPermissionDataProvider;
 
+    /**
+     * The observer that watches for changes from array members
+     */
+    private final Watcher mObserver = new Watcher() {
+            @Override
+            public void onChange(@Nullable Watchable what) {
+                Settings.this.dispatchChange(what);
+            }
+        };
+
     @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
     public Settings(Map<String, PackageSetting> pkgSettings) {
         mLock = new Object();
         mPackages.putAll(pkgSettings);
+        mAppIds = new ArrayList<>();
+        mOtherAppIds = new SparseArray<>();
         mSystemDir = null;
         mPermissions = null;
         mRuntimePermissionsPersistence = null;
@@ -436,11 +504,17 @@
         mStoppedPackagesFilename = null;
         mBackupStoppedPackagesFilename = null;
         mKernelMappingFilename = null;
+        mPackages.registerObserver(mObserver);
+        mPreferredActivities.registerObserver(mObserver);
+        mPersistentPreferredActivities.registerObserver(mObserver);
+        mCrossProfileIntentResolvers.registerObserver(mObserver);
     }
 
     Settings(File dataDir, RuntimePermissionsPersistence runtimePermissionsPersistence,
             LegacyPermissionDataProvider permissionDataProvider, Object lock) {
         mLock = lock;
+        mAppIds = new ArrayList<>();
+        mOtherAppIds = new SparseArray<>();
         mPermissions = new LegacyPermissionSettings(lock);
         mRuntimePermissionsPersistence = new RuntimePermissionPersistence(
                 runtimePermissionsPersistence);
@@ -463,18 +537,91 @@
         // Deprecated: Needed for migration
         mStoppedPackagesFilename = new File(mSystemDir, "packages-stopped.xml");
         mBackupStoppedPackagesFilename = new File(mSystemDir, "packages-stopped-backup.xml");
+        mPackages.registerObserver(mObserver);
+        mPreferredActivities.registerObserver(mObserver);
+        mPersistentPreferredActivities.registerObserver(mObserver);
+        mCrossProfileIntentResolvers.registerObserver(mObserver);
     }
 
-    private static void invalidatePackageCache() {
+    /**
+     * A copy constructor used in snapshot().  Attributes that are supposed to be
+     * immutable in the PackageManagerService application are referenced.  Attributes that
+     * are changed by PackageManagerService APIs are deep-copied
+     */
+    private Settings(Settings r) {
+        final int mPackagesSize = r.mPackages.size();
+        mPackages.putAll(r.mPackages);
+
+        // The following assignments satisfy Java requirements but are not
+        // needed by the read-only methods.  Note especially that the lock
+        // is not required because this clone is meant to support lock-free
+        // read-only methods.
+        mLock = null;
+        mRuntimePermissionsPersistence = r.mRuntimePermissionsPersistence;
+        mSettingsFilename = null;
+        mBackupSettingsFilename = null;
+        mPackageListFilename = null;
+        mStoppedPackagesFilename = null;
+        mBackupStoppedPackagesFilename = null;
+        mKernelMappingFilename = null;
+
+        mInstallerPackages.addAll(r.mInstallerPackages);
+        mKernelMapping.putAll(r.mKernelMapping);
+        mDisabledSysPackages.putAll(r.mDisabledSysPackages);
+        Snapshots.copy(mBlockUninstallPackages, r.mBlockUninstallPackages);
+        mRestoredIntentFilterVerifications.putAll(r.mRestoredIntentFilterVerifications);
+        mVersion.putAll(r.mVersion);
+        mVerifierDeviceIdentity = r.mVerifierDeviceIdentity;
+        WatchedSparseArray.snapshot(
+                mPreferredActivities, r.mPreferredActivities);
+        WatchedSparseArray.snapshot(
+                mPersistentPreferredActivities, r.mPersistentPreferredActivities);
+        WatchedSparseArray.snapshot(
+                mCrossProfileIntentResolvers, r.mCrossProfileIntentResolvers);
+        mSharedUsers.putAll(r.mSharedUsers);
+        mAppIds = new ArrayList<>(r.mAppIds);
+        mOtherAppIds = r.mOtherAppIds.clone();
+        mPastSignatures.addAll(r.mPastSignatures);
+        mKeySetRefs.putAll(r.mKeySetRefs);
+        mRenamedPackages.putAll(r.mRenamedPackages);
+        Snapshots.copy(mDefaultBrowserApp, r.mDefaultBrowserApp);
+        Snapshots.snapshot(mNextAppLinkGeneration, r.mNextAppLinkGeneration);
+        // mReadMessages
+        mPendingPackages.addAll(r.mPendingPackages);
+        mSystemDir = null;
+        // mKeySetManagerService;
+        mPermissions = r.mPermissions;
+        mPermissionDataProvider = r.mPermissionDataProvider;
+
+        // Do not register any Watchables
+    }
+
+    /**
+     * Return a snapshot.  If the cached snapshot is null, build a new one.  The logic in
+     * the function ensures that this function returns a valid snapshot even if a race
+     * condition causes the cached snapshot to be cleared asynchronously to this method.
+     */
+    public Settings snapshot() {
+        Settings s = mSnapshot;
+        if (s == null) {
+            s = new Settings(this);
+            s.mWatchable.seal();
+            mSnapshot = s;
+        }
+        return s;
+    }
+
+    private void invalidatePackageCache() {
         PackageManagerService.invalidatePackageInfoCache();
         ChangeIdStateCache.invalidate();
+        onChanged();
     }
 
     PackageSetting getPackageLPr(String pkgName) {
         return mPackages.get(pkgName);
     }
 
-    ArrayMap<String, PackageSetting> getPackagesLocked() {
+    WatchedArrayMap<String, PackageSetting> getPackagesLocked() {
         return mPackages;
     }
 
@@ -5558,6 +5705,7 @@
     /** This method takes a specific user id as well as UserHandle.USER_ALL. */
     void clearPackagePreferredActivities(String packageName,
             @NonNull SparseBooleanArray outUserChanged, int userId) {
+        boolean changed = false;
         ArrayList<PreferredActivity> removed = null;
         for (int i = 0; i < mPreferredActivities.size(); i++) {
             final int thisUserId = mPreferredActivities.keyAt(i);
@@ -5585,8 +5733,12 @@
                     pir.removeFilter(pa);
                 }
                 outUserChanged.put(thisUserId, true);
+                changed = true;
             }
         }
+        if (changed) {
+            onChanged();
+        }
     }
 
     boolean clearPackagePersistentPreferredActivities(String packageName, int userId) {
@@ -5617,6 +5769,9 @@
                 changed = true;
             }
         }
+        if (changed) {
+            onChanged();
+        }
         return changed;
     }
 
@@ -5649,6 +5804,7 @@
                 changed.add(mPreferredActivities.keyAt(i));
             }
         }
+        onChanged();
         return changed;
     }
 
diff --git a/services/core/java/com/android/server/pm/SharedUserSetting.java b/services/core/java/com/android/server/pm/SharedUserSetting.java
index 6103f558..9b1c08d 100644
--- a/services/core/java/com/android/server/pm/SharedUserSetting.java
+++ b/services/core/java/com/android/server/pm/SharedUserSetting.java
@@ -93,6 +93,7 @@
                     proc.addStateFrom(newProc);
                 }
             }
+            onChanged();
         }
     }
 
@@ -117,6 +118,7 @@
         }
         // recalculate processes.
         updateProcesses();
+        onChanged();
         return true;
     }
 
@@ -129,6 +131,7 @@
         if (packages.add(packageSetting)) {
             setFlags(this.pkgFlags | packageSetting.pkgFlags);
             setPrivateFlags(this.pkgPrivateFlags | packageSetting.pkgPrivateFlags);
+            onChanged();
         }
         if (packageSetting.pkg != null) {
             addProcesses(packageSetting.pkg.getProcesses());
@@ -169,6 +172,7 @@
             }
             if (ps.pkg.getTargetSdkVersion() < seInfoTargetSdkVersion) {
                 seInfoTargetSdkVersion = ps.pkg.getTargetSdkVersion();
+                onChanged();
             }
         }
 
@@ -179,6 +183,7 @@
             final boolean isPrivileged = isPrivileged() | ps.pkg.isPrivileged();
             ps.getPkgState().setOverrideSeInfo(SELinuxMMAC.getSeInfo(ps.pkg, isPrivileged,
                     seInfoTargetSdkVersion));
+            onChanged();
         }
     }
 
@@ -234,6 +239,7 @@
         } else {
             this.processes = null;
         }
+        onChanged();
         return this;
     }
 }
diff --git a/services/core/java/com/android/server/pm/ShortcutService.java b/services/core/java/com/android/server/pm/ShortcutService.java
index 56fb5e8..95ce140 100644
--- a/services/core/java/com/android/server/pm/ShortcutService.java
+++ b/services/core/java/com/android/server/pm/ShortcutService.java
@@ -2739,7 +2739,8 @@
 
                 // Default launcher from role manager.
                 final long startGetHomeRoleHoldersAsUser = getStatStartTime();
-                final String defaultLauncher = injectGetHomeRoleHolderAsUser(userId);
+                final String defaultLauncher = injectGetHomeRoleHolderAsUser(
+                        getParentOrSelfUserId(userId));
                 logDurationStat(Stats.GET_DEFAULT_HOME, startGetHomeRoleHoldersAsUser);
 
                 if (defaultLauncher != null) {
@@ -4694,7 +4695,7 @@
                 final List<ResolveInfo> allHomeCandidates = new ArrayList<>();
                 // Default launcher from package manager.
                 final ComponentName defaultLauncher = mPackageManagerInternal
-                        .getHomeActivitiesAsUser(allHomeCandidates, mUserId);
+                        .getHomeActivitiesAsUser(allHomeCandidates, getParentOrSelfUserId(mUserId));
                 getOutPrintWriter().println("Launcher: " + defaultLauncher);
             }
         }
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index 225c998..ccbf73c 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -4760,31 +4760,13 @@
                 final boolean hasParent = user.profileGroupId != user.id
                         && user.profileGroupId != UserInfo.NO_PROFILE_GROUP_ID;
                 if (verbose) {
-                    final DevicePolicyManagerInternal dpm = getDevicePolicyManagerInternal();
-                    String deviceOwner = "";
-                    String profileOwner = "";
-                    if (dpm != null) {
-                        final long ident = Binder.clearCallingIdentity();
-                        try {
-                            if (dpm.getDeviceOwnerUserId() == user.id) {
-                                deviceOwner = " (device-owner)";
-                            }
-                            if (dpm.getProfileOwnerAsUser(user.id) != null) {
-                                profileOwner = " (profile-owner)";
-                            }
-                        } finally {
-                            Binder.restoreCallingIdentity(ident);
-                        }
-                    }
-                    pw.printf("%d: id=%d, name=%s, flags=%s%s%s%s%s%s%s%s%s\n", i, user.id,
-                            user.name,
+                    pw.printf("%d: id=%d, name=%s, flags=%s%s%s%s%s%s%s\n", i, user.id, user.name,
                             UserInfo.flagsToString(user.flags),
                             hasParent ? " (parentId=" + user.profileGroupId + ")" : "",
                             running ? " (running)" : "",
                             user.partial ? " (partial)" : "",
                             user.preCreated ? " (pre-created)" : "",
                             user.convertedFromPreCreated ? " (converted)" : "",
-                            deviceOwner, profileOwner,
                             current ? " (current)" : "");
                 } else {
                     // NOTE: the standard "list users" command is used by integration tests and
@@ -4878,21 +4860,6 @@
                     if (userInfo.convertedFromPreCreated) {
                         pw.print(" <converted>");
                     }
-                    final DevicePolicyManagerInternal dpm = getDevicePolicyManagerInternal();
-                    if (dpm != null) {
-                        final long ident = Binder.clearCallingIdentity();
-                        try {
-                            if (dpm.getDeviceOwnerUserId() == userId) {
-                                pw.print(" <device-owner>");
-                            }
-                            if (dpm.getProfileOwnerAsUser(userId) != null) {
-                                pw.print(" <profile-owner>");
-                            }
-                        } finally {
-                            Binder.restoreCallingIdentity(ident);
-                        }
-                    }
-
                     pw.println();
                     pw.print("    Type: "); pw.println(userInfo.userType);
                     pw.print("    Flags: "); pw.print(userInfo.flags); pw.print(" (");
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
index 1dbf839..2107536f 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
@@ -1117,8 +1117,9 @@
         mOnPermissionChangeListeners.removeListener(listener);
     }
 
+    @Nullable
     @Override
-    @Nullable public List<String> getWhitelistedRestrictedPermissions(@NonNull String packageName,
+    public List<String> getAllowlistedRestrictedPermissions(@NonNull String packageName,
             @PermissionWhitelistFlags int flags, @UserIdInt int userId) {
         Objects.requireNonNull(packageName);
         Preconditions.checkFlagsArgument(flags,
@@ -1131,7 +1132,7 @@
         if (UserHandle.getCallingUserId() != userId) {
             mContext.enforceCallingOrSelfPermission(
                     android.Manifest.permission.INTERACT_ACROSS_USERS,
-                    "getWhitelistedRestrictedPermissions for user " + userId);
+                    "getAllowlistedRestrictedPermissions for user " + userId);
         }
 
         final AndroidPackage pkg = mPackageManagerInt.getPackage(packageName);
@@ -1217,7 +1218,7 @@
     }
 
     @Override
-    public boolean addWhitelistedRestrictedPermission(@NonNull String packageName,
+    public boolean addAllowlistedRestrictedPermission(@NonNull String packageName,
             @NonNull String permName, @PermissionWhitelistFlags int flags,
             @UserIdInt int userId) {
         // Other argument checks are done in get/setAllowlistedRestrictedPermissions
@@ -1228,7 +1229,7 @@
         }
 
         List<String> permissions =
-                getWhitelistedRestrictedPermissions(packageName, flags, userId);
+                getAllowlistedRestrictedPermissions(packageName, flags, userId);
         if (permissions == null) {
             permissions = new ArrayList<>(1);
         }
@@ -1255,14 +1256,14 @@
         if (isImmutablyRestrictedPermission && mContext.checkCallingOrSelfPermission(
                 Manifest.permission.WHITELIST_RESTRICTED_PERMISSIONS)
                 != PackageManager.PERMISSION_GRANTED) {
-            throw new SecurityException("Cannot modify whitelisting of an immutably "
+            throw new SecurityException("Cannot modify allowlisting of an immutably "
                     + "restricted permission: " + permName);
         }
         return true;
     }
 
     @Override
-    public boolean removeWhitelistedRestrictedPermission(@NonNull String packageName,
+    public boolean removeAllowlistedRestrictedPermission(@NonNull String packageName,
             @NonNull String permName, @PermissionWhitelistFlags int flags,
             @UserIdInt int userId) {
         // Other argument checks are done in get/setAllowlistedRestrictedPermissions
@@ -1273,7 +1274,7 @@
         }
 
         final List<String> permissions =
-                getWhitelistedRestrictedPermissions(packageName, flags, userId);
+                getAllowlistedRestrictedPermissions(packageName, flags, userId);
         if (permissions != null && permissions.remove(permName)) {
             return setAllowlistedRestrictedPermissions(packageName, permissions,
                     flags, userId);
@@ -1328,20 +1329,20 @@
                         + " being installer on record or "
                         + Manifest.permission.WHITELIST_RESTRICTED_PERMISSIONS);
             }
-            final List<String> whitelistedPermissions =
-                    getWhitelistedRestrictedPermissions(pkg.getPackageName(), flags, userId);
+            final List<String> allowlistedPermissions =
+                    getAllowlistedRestrictedPermissions(pkg.getPackageName(), flags, userId);
             if (permissions == null || permissions.isEmpty()) {
-                if (whitelistedPermissions == null || whitelistedPermissions.isEmpty()) {
+                if (allowlistedPermissions == null || allowlistedPermissions.isEmpty()) {
                     return true;
                 }
             } else {
                 // Only the system can add and remove while the installer can only remove.
                 final int permissionCount = permissions.size();
                 for (int i = 0; i < permissionCount; i++) {
-                    if ((whitelistedPermissions == null
-                            || !whitelistedPermissions.contains(permissions.get(i)))
+                    if ((allowlistedPermissions == null
+                            || !allowlistedPermissions.contains(permissions.get(i)))
                             && !isCallerPrivileged) {
-                        throw new SecurityException("Adding to upgrade whitelist requires"
+                        throw new SecurityException("Adding to upgrade allowlist requires"
                                 + Manifest.permission.WHITELIST_RESTRICTED_PERMISSIONS);
                     }
                 }
@@ -1349,7 +1350,7 @@
 
             if ((flags & PackageManager.FLAG_PERMISSION_WHITELIST_INSTALLER) != 0) {
                 if (!isCallerPrivileged && !isCallerInstallerOnRecord) {
-                    throw new SecurityException("Modifying installer whitelist requires"
+                    throw new SecurityException("Modifying installer allowlist requires"
                             + " being installer on record or "
                             + Manifest.permission.WHITELIST_RESTRICTED_PERMISSIONS);
                 }
@@ -1367,8 +1368,8 @@
     }
 
     @Override
-    public boolean setAutoRevokeWhitelisted(
-            @NonNull String packageName, boolean whitelisted, int userId) {
+    public boolean setAutoRevokeExempted(
+            @NonNull String packageName, boolean exempted, int userId) {
         Objects.requireNonNull(packageName);
 
         final AndroidPackage pkg = mPackageManagerInt.getPackage(packageName);
@@ -1378,7 +1379,7 @@
             return false;
         }
 
-        return setAutoRevokeExemptedInternal(pkg, whitelisted, userId);
+        return setAutoRevokeExemptedInternal(pkg, exempted, userId);
     }
 
     private boolean setAutoRevokeExemptedInternal(@NonNull AndroidPackage pkg, boolean exempted,
@@ -1386,7 +1387,7 @@
         final int packageUid = UserHandle.getUid(userId, pkg.getUid());
         if (mAppOpsManager.checkOpNoThrow(AppOpsManager.OP_AUTO_REVOKE_MANAGED_BY_INSTALLER,
                 packageUid, pkg.getPackageName()) != MODE_ALLOWED) {
-            // Whitelist user set - don't override
+            // Allowlist user set - don't override
             return false;
         }
 
@@ -1420,7 +1421,7 @@
     }
 
     @Override
-    public boolean isAutoRevokeWhitelisted(@NonNull String packageName, int userId) {
+    public boolean isAutoRevokeExempted(@NonNull String packageName, int userId) {
         Objects.requireNonNull(packageName);
 
         final AndroidPackage pkg = mPackageManagerInt.getPackage(packageName);
@@ -2872,7 +2873,7 @@
                         boolean softRestricted = bp.isSoftRestricted();
 
                         // If permission policy is not ready we don't deal with restricted
-                        // permissions as the policy may whitelist some permissions. Once
+                        // permissions as the policy may allowlist some permissions. Once
                         // the policy is initialized we would re-evaluate permissions.
                         final boolean permissionPolicyInitialized =
                                 isPermissionPolicyInitialized.get(userId);
@@ -3576,9 +3577,9 @@
         if (isInSystemConfigPrivAppPermissions(pkg, permissionName)) {
             return true;
         }
-        // Only enforce whitelist this on boot
+        // Only enforce the allowlist on boot
         if (!mSystemReady
-                // Updated system apps do not need to be whitelisted
+                // Updated system apps do not need to be allowlisted
                 && !isUpdatedSystemApp) {
             final ApexManager apexManager = ApexManager.getInstance();
             final String packageName = pkg.getPackageName();
@@ -3587,7 +3588,7 @@
             final boolean isInUpdatedApex = containingApexPackageName != null
                     && !apexManager.isFactory(apexManager.getPackageInfo(containingApexPackageName,
                     MATCH_ACTIVE_PACKAGE));
-            // Apps that are in updated apexs' do not need to be whitelisted
+            // Apps that are in updated apexs' do not need to be allowlisted
             if (!isInUpdatedApex) {
                 // it's only a reportable violation if the permission isn't explicitly
                 // denied
@@ -3596,7 +3597,7 @@
                 }
                 Slog.w(TAG, "Privileged permission " + permissionName + " for package "
                         + packageName + " (" + pkg.getPath()
-                        + ") not in privapp-permissions whitelist");
+                        + ") not in privapp-permissions allowlist");
                 if (RoSystemProperties.CONTROL_PRIVAPP_PERMISSIONS_ENFORCE) {
                     synchronized (mLock) {
                         if (mPrivappPermissionsViolations == null) {
@@ -3775,10 +3776,10 @@
 
             int newFlags = oldFlags;
             int mask = 0;
-            int whitelistFlagsCopy = allowlistFlags;
-            while (whitelistFlagsCopy != 0) {
-                final int flag = 1 << Integer.numberOfTrailingZeros(whitelistFlagsCopy);
-                whitelistFlagsCopy &= ~flag;
+            int allowlistFlagsCopy = allowlistFlags;
+            while (allowlistFlagsCopy != 0) {
+                final int flag = 1 << Integer.numberOfTrailingZeros(allowlistFlagsCopy);
+                allowlistFlagsCopy &= ~flag;
                 switch (flag) {
                     case FLAG_PERMISSION_WHITELIST_SYSTEM: {
                         mask |= FLAG_PERMISSION_RESTRICTION_SYSTEM_EXEMPT;
@@ -3825,26 +3826,26 @@
 
             updatePermissions = true;
 
-            final boolean wasWhitelisted = (oldFlags
+            final boolean wasAllowlisted = (oldFlags
                     & (PackageManager.FLAGS_PERMISSION_RESTRICTION_ANY_EXEMPT)) != 0;
-            final boolean isWhitelisted = (newFlags
+            final boolean isAllowlisted = (newFlags
                     & (PackageManager.FLAGS_PERMISSION_RESTRICTION_ANY_EXEMPT)) != 0;
 
             // If the permission is policy fixed as granted but it is no longer
-            // on any of the whitelists we need to clear the policy fixed flag
-            // as whitelisting trumps policy i.e. policy cannot grant a non
+            // on any of the allowlists we need to clear the policy fixed flag
+            // as allowlisting trumps policy i.e. policy cannot grant a non
             // grantable permission.
             if ((oldFlags & PackageManager.FLAG_PERMISSION_POLICY_FIXED) != 0) {
-                if (!isWhitelisted && isGranted) {
+                if (!isAllowlisted && isGranted) {
                     mask |= PackageManager.FLAG_PERMISSION_POLICY_FIXED;
                     newFlags &= ~PackageManager.FLAG_PERMISSION_POLICY_FIXED;
                 }
             }
 
-            // If we are whitelisting an app that does not support runtime permissions
+            // If we are allowlisting an app that does not support runtime permissions
             // we need to make sure it goes through the permission review UI at launch.
             if (pkg.getTargetSdkVersion() < Build.VERSION_CODES.M
-                    && !wasWhitelisted && isWhitelisted) {
+                    && !wasAllowlisted && isAllowlisted) {
                 mask |= PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED;
                 newFlags |= PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED;
             }
@@ -3854,7 +3855,7 @@
         }
 
         if (updatePermissions) {
-            // Update permission of this app to take into account the new whitelist state.
+            // Update permission of this app to take into account the new allowlist state.
             restorePermissionState(pkg, false, pkg.getPackageName(), mDefaultPermissionCallback);
 
             // If this resulted in losing a permission we need to kill the app.
@@ -4487,7 +4488,7 @@
         synchronized (mLock) {
             if (mPrivappPermissionsViolations != null) {
                 throw new IllegalStateException("Signature|privileged permissions not in "
-                        + "privapp-permissions whitelist: " + mPrivappPermissionsViolations);
+                        + "privapp-permissions allowlist: " + mPrivappPermissionsViolations);
             }
         }
 
@@ -4868,13 +4869,6 @@
         }
     }
 
-    private boolean canPropagatePermissionToInstantApp(@NonNull String permissionName) {
-        synchronized (mLock) {
-            final Permission bp = mRegistry.getPermission(permissionName);
-            return bp != null && (bp.isRuntime() || bp.isDevelopment()) && bp.isInstant();
-        }
-    }
-
     @NonNull
     private List<LegacyPermission> getLegacyPermissions() {
         synchronized (mLock) {
@@ -4954,7 +4948,7 @@
 
     private class PermissionManagerServiceInternalImpl implements PermissionManagerServiceInternal {
         @Override
-        public void systemReady() {
+        public void onSystemReady() {
             PermissionManagerService.this.systemReady();
         }
 
@@ -5012,11 +5006,6 @@
             Preconditions.checkArgumentNonNegative(userId, "userId");
             resetRuntimePermissionsInternal(pkg, userId);
         }
-        @Override
-        public void resetAllRuntimePermissions(@UserIdInt int userId) {
-            Preconditions.checkArgumentNonNegative(userId, "userId");
-            mPackageManagerInt.forEachPackage(pkg -> resetRuntimePermissionsInternal(pkg, userId));
-        }
 
         @Override
         public Permission getPermissionTEMP(String permName) {
@@ -5157,11 +5146,6 @@
             onPackageUninstalledInternal(packageName, appId, pkg, sharedUserPkgs, userId);
         }
 
-        @Override
-        public boolean canPropagatePermissionToInstantApp(@NonNull String permissionName) {
-            return PermissionManagerService.this.canPropagatePermissionToInstantApp(permissionName);
-        }
-
         @NonNull
         @Override
         public List<LegacyPermission> getLegacyPermissions() {
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java
index 0817d4f..1cfae00 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java
@@ -54,8 +54,6 @@
     void removeOnRuntimePermissionStateChangedListener(
             @NonNull OnRuntimePermissionStateChangedListener listener);
 
-    void systemReady();
-
     /**
      * Get whether permission review is required for a package.
      *
@@ -94,14 +92,6 @@
             @UserIdInt int userId);
 
     /**
-     * Reset the runtime permission state changes for all packages.
-     *
-     * @param userId the user ID
-     */
-    //@SystemApi(client = SystemApi.Client.SYSTEM_SERVER)
-    void resetAllRuntimePermissions(@UserIdInt int userId);
-
-    /**
      * Read legacy permission state from package settings.
      *
      * TODO(zhanghai): This is a temporary method because we should not expose
@@ -201,6 +191,12 @@
     void writeLegacyPermissionsTEMP(@NonNull LegacyPermissionSettings legacyPermissionSettings);
 
     /**
+     * Callback when the system is ready.
+     */
+    //@SystemApi(client = SystemApi.Client.SYSTEM_SERVER)
+    void onSystemReady();
+
+    /**
      * Callback when a user has been created.
      *
      * @param userId the created user ID
@@ -265,14 +261,6 @@
             @NonNull List<AndroidPackage> sharedUserPkgs, @UserIdInt int userId);
 
     /**
-     * Check whether a permission can be propagated to instant app.
-     *
-     * @param permissionName the name of the permission
-     * @return whether the permission can be propagated
-     */
-    boolean canPropagatePermissionToInstantApp(@NonNull String permissionName);
-
-    /**
      * Listener for package permission state (permissions or flags) changes.
      */
     interface OnRuntimePermissionStateChangedListener {
diff --git a/services/core/java/com/android/server/powerstats/PowerStatsHALWrapper.java b/services/core/java/com/android/server/powerstats/PowerStatsHALWrapper.java
index 88e5f69..79c0392 100644
--- a/services/core/java/com/android/server/powerstats/PowerStatsHALWrapper.java
+++ b/services/core/java/com/android/server/powerstats/PowerStatsHALWrapper.java
@@ -16,7 +16,11 @@
 
 package com.android.server.powerstats;
 
+import android.hardware.power.stats.ChannelInfo;
+import android.hardware.power.stats.EnergyMeasurement;
 import android.hardware.power.stats.IPowerStats;
+import android.hardware.power.stats.PowerEntityInfo;
+import android.hardware.power.stats.StateResidencyResult;
 import android.os.Binder;
 import android.os.IBinder;
 import android.os.RemoteException;
@@ -32,6 +36,7 @@
  */
 public final class PowerStatsHALWrapper {
     private static final String TAG = PowerStatsHALWrapper.class.getSimpleName();
+    private static final boolean DEBUG = false;
 
     /**
      * IPowerStatsHALWrapper defines the interface to the PowerStatsHAL.
@@ -122,17 +127,30 @@
          *
          * @return true if connection to power stats HAL was correctly established.
          */
-        boolean initialize();
+        boolean isInitialized();
     }
 
     /**
-     * PowerStatsHALWrapperImpl is the implementation of the IPowerStatsHALWrapper
-     * used by the PowerStatsService.  Other implementations will be used by the testing
-     * framework and will be passed into the PowerStatsService through an injector.
+     * PowerStatsHALWrapper20Impl is the implementation of the IPowerStatsHALWrapper
+     * used by the PowerStatsService on devices that support only PowerStats HAL 2.0.
+     * Other implementations will be used by the testing framework and will be passed
+     * into the PowerStatsService through an injector.
      */
-    public static final class PowerStatsHALWrapperImpl implements IPowerStatsHALWrapper {
+    public static final class PowerStatsHAL20WrapperImpl implements IPowerStatsHALWrapper {
         private static Supplier<IPowerStats> sVintfPowerStats;
 
+        public PowerStatsHAL20WrapperImpl() {
+            Supplier<IPowerStats> service = new VintfHalCache();
+            sVintfPowerStats = null;
+
+            if (service.get() == null) {
+                if (DEBUG) Slog.d(TAG, "PowerStats HAL 2.0 not available on this device.");
+                sVintfPowerStats = null;
+            } else {
+                sVintfPowerStats = service;
+            }
+        }
+
         @Override
         public android.hardware.power.stats.PowerEntityInfo[] getPowerEntityInfo() {
             android.hardware.power.stats.PowerEntityInfo[] powerEntityInfoHAL = null;
@@ -141,7 +159,7 @@
                 try {
                     powerEntityInfoHAL = sVintfPowerStats.get().getPowerEntityInfo();
                 } catch (RemoteException e) {
-                    Slog.e(TAG, "Failed to get power entity info from PowerStats HAL");
+                    if (DEBUG) Slog.d(TAG, "Failed to get power entity info from PowerStats HAL");
                 }
             }
 
@@ -158,7 +176,7 @@
                     stateResidencyResultHAL =
                         sVintfPowerStats.get().getStateResidency(powerEntityIds);
                 } catch (RemoteException e) {
-                    Slog.e(TAG, "Failed to get state residency from PowerStats HAL");
+                    if (DEBUG) Slog.d(TAG, "Failed to get state residency from PowerStats HAL");
                 }
             }
 
@@ -173,7 +191,9 @@
                 try {
                     energyConsumerInfoHAL = sVintfPowerStats.get().getEnergyConsumerInfo();
                 } catch (RemoteException e) {
-                    Slog.e(TAG, "Failed to get energy consumer info from PowerStats HAL");
+                    if (DEBUG) {
+                        Slog.d(TAG, "Failed to get energy consumer info from PowerStats HAL");
+                    }
                 }
             }
 
@@ -190,7 +210,9 @@
                     energyConsumedHAL =
                         sVintfPowerStats.get().getEnergyConsumed(energyConsumerIds);
                 } catch (RemoteException e) {
-                    Slog.e(TAG, "Failed to get energy consumer results from PowerStats HAL");
+                    if (DEBUG) {
+                        Slog.d(TAG, "Failed to get energy consumer results from PowerStats HAL");
+                    }
                 }
             }
 
@@ -205,7 +227,7 @@
                 try {
                     energyMeterInfoHAL = sVintfPowerStats.get().getEnergyMeterInfo();
                 } catch (RemoteException e) {
-                    Slog.e(TAG, "Failed to get energy meter info from PowerStats HAL");
+                    if (DEBUG) Slog.d(TAG, "Failed to get energy meter info from PowerStats HAL");
                 }
             }
 
@@ -221,7 +243,7 @@
                     energyMeasurementHAL =
                         sVintfPowerStats.get().readEnergyMeters(channelIds);
                 } catch (RemoteException e) {
-                    Slog.e(TAG, "Failed to get energy measurements from PowerStats HAL");
+                    if (DEBUG) Slog.d(TAG, "Failed to get energy measurements from PowerStats HAL");
                 }
             }
 
@@ -229,17 +251,90 @@
         }
 
         @Override
-        public boolean initialize() {
-            Supplier<IPowerStats> service = new VintfHalCache();
+        public boolean isInitialized() {
+            return (sVintfPowerStats != null);
+        }
+    }
 
-            if (service.get() == null) {
-                sVintfPowerStats = null;
-                return false;
+    /**
+     * PowerStatsHALWrapper10Impl is the implementation of the IPowerStatsHALWrapper
+     * used by the PowerStatsService on devices that support only PowerStats HAL 1.0.
+     * Other implementations will be used by the testing framework and will be passed
+     * into the PowerStatsService through an injector.
+     */
+    public static final class PowerStatsHAL10WrapperImpl implements IPowerStatsHALWrapper {
+        private boolean mIsInitialized;
+
+        // PowerStatsHAL 1.0 native functions exposed by JNI layer.
+        private static native boolean nativeInit();
+        private static native PowerEntityInfo[] nativeGetPowerEntityInfo();
+        private static native StateResidencyResult[] nativeGetStateResidency(int[] powerEntityIds);
+        private static native ChannelInfo[] nativeGetEnergyMeterInfo();
+        private static native EnergyMeasurement[] nativeReadEnergyMeters(int[] channelIds);
+
+        public PowerStatsHAL10WrapperImpl() {
+            if (nativeInit()) {
+                mIsInitialized = true;
             } else {
-                sVintfPowerStats = service;
-                return true;
+                if (DEBUG) Slog.d(TAG, "PowerStats HAL 1.0 not available on this device.");
+                mIsInitialized = false;
             }
         }
+
+        @Override
+        public android.hardware.power.stats.PowerEntityInfo[] getPowerEntityInfo() {
+            return nativeGetPowerEntityInfo();
+        }
+
+        @Override
+        public android.hardware.power.stats.StateResidencyResult[] getStateResidency(
+                int[] powerEntityIds) {
+            return nativeGetStateResidency(powerEntityIds);
+        }
+
+        @Override
+        public int[] getEnergyConsumerInfo() {
+            if (DEBUG) Slog.d(TAG, "Energy consumer info is not supported");
+            return null;
+        }
+
+        @Override
+        public android.hardware.power.stats.EnergyConsumerResult[] getEnergyConsumed(
+                int[] energyConsumerIds) {
+            if (DEBUG) Slog.d(TAG, "Energy consumer results are not supported");
+            return null;
+        }
+
+        @Override
+        public android.hardware.power.stats.ChannelInfo[] getEnergyMeterInfo() {
+            return nativeGetEnergyMeterInfo();
+        }
+
+        @Override
+        public android.hardware.power.stats.EnergyMeasurement[] readEnergyMeters(int[] channelIds) {
+            return nativeReadEnergyMeters(channelIds);
+        }
+
+        @Override
+        public boolean isInitialized() {
+            return mIsInitialized;
+        }
+    }
+
+    /**
+     * Returns an instance of an IPowerStatsHALWrapper.  If PowerStats HAL 2.0 is supported on the
+     * device, return a PowerStatsHAL20WrapperImpl, else return a PowerStatsHAL10WrapperImpl.
+     *
+     * @return an instance of an IPowerStatsHALWrapper where preference is given to PowerStats HAL
+     *         2.0.
+     */
+    public static IPowerStatsHALWrapper getPowerStatsHalImpl() {
+        PowerStatsHAL20WrapperImpl powerStatsHAL20WrapperImpl = new PowerStatsHAL20WrapperImpl();
+        if (powerStatsHAL20WrapperImpl.isInitialized()) {
+            return powerStatsHAL20WrapperImpl;
+        } else {
+            return new PowerStatsHAL10WrapperImpl();
+        }
     }
 
     private static class VintfHalCache implements Supplier<IPowerStats>, IBinder.DeathRecipient {
diff --git a/services/core/java/com/android/server/powerstats/PowerStatsService.java b/services/core/java/com/android/server/powerstats/PowerStatsService.java
index 1150d4b..ce50e583 100644
--- a/services/core/java/com/android/server/powerstats/PowerStatsService.java
+++ b/services/core/java/com/android/server/powerstats/PowerStatsService.java
@@ -29,7 +29,6 @@
 import com.android.internal.util.DumpUtils;
 import com.android.server.SystemService;
 import com.android.server.powerstats.PowerStatsHALWrapper.IPowerStatsHALWrapper;
-import com.android.server.powerstats.PowerStatsHALWrapper.PowerStatsHALWrapperImpl;
 import com.android.server.powerstats.ProtoStreamUtils.ChannelInfoUtils;
 import com.android.server.powerstats.ProtoStreamUtils.EnergyConsumerIdUtils;
 import com.android.server.powerstats.ProtoStreamUtils.PowerEntityInfoUtils;
@@ -78,7 +77,7 @@
         }
 
         IPowerStatsHALWrapper createPowerStatsHALWrapperImpl() {
-            return new PowerStatsHALWrapperImpl();
+            return PowerStatsHALWrapper.getPowerStatsHalImpl();
         }
 
         PowerStatsLogger createPowerStatsLogger(Context context, File dataStoragePath,
@@ -143,7 +142,7 @@
     private void onSystemServiceReady() {
         mPowerStatsHALWrapper = mInjector.createPowerStatsHALWrapperImpl();
 
-        if (mPowerStatsHALWrapper.initialize()) {
+        if (mPowerStatsHALWrapper.isInitialized()) {
             if (DEBUG) Slog.d(TAG, "Starting PowerStatsService");
 
             // Only start logger and triggers if initialization is successful.
diff --git a/services/core/java/com/android/server/powerstats/ProtoStreamUtils.java b/services/core/java/com/android/server/powerstats/ProtoStreamUtils.java
index 5a4256a..5e23b86 100644
--- a/services/core/java/com/android/server/powerstats/ProtoStreamUtils.java
+++ b/services/core/java/com/android/server/powerstats/ProtoStreamUtils.java
@@ -46,23 +46,31 @@
 
     static class PowerEntityInfoUtils {
         public static void print(PowerEntityInfo[] powerEntityInfo) {
+            if (powerEntityInfo == null) return;
+
             for (int i = 0; i < powerEntityInfo.length; i++) {
                 Slog.d(TAG, "PowerEntityId: " + powerEntityInfo[i].powerEntityId
                         + ", PowerEntityName: " + powerEntityInfo[i].powerEntityName);
-                for (int j = 0; j < powerEntityInfo[i].states.length; j++) {
-                    Slog.d(TAG, "  StateId: " + powerEntityInfo[i].states[j].stateId
-                            + ", StateName: " + powerEntityInfo[i].states[j].stateName);
+                if (powerEntityInfo[i].states != null) {
+                    for (int j = 0; j < powerEntityInfo[i].states.length; j++) {
+                        Slog.d(TAG, "  StateId: " + powerEntityInfo[i].states[j].stateId
+                                + ", StateName: " + powerEntityInfo[i].states[j].stateName);
+                    }
                 }
             }
         }
 
         public static void dumpsys(PowerEntityInfo[] powerEntityInfo, PrintWriter pw) {
+            if (powerEntityInfo == null) return;
+
             for (int i = 0; i < powerEntityInfo.length; i++) {
                 pw.println("PowerEntityId: " + powerEntityInfo[i].powerEntityId
                         + ", PowerEntityName: " + powerEntityInfo[i].powerEntityName);
-                for (int j = 0; j < powerEntityInfo[i].states.length; j++) {
-                    pw.println("  StateId: " + powerEntityInfo[i].states[j].stateId
-                            + ", StateName: " + powerEntityInfo[i].states[j].stateName);
+                if (powerEntityInfo[i].states != null) {
+                    for (int j = 0; j < powerEntityInfo[i].states.length; j++) {
+                        pw.println("  StateId: " + powerEntityInfo[i].states[j].stateId
+                                + ", StateName: " + powerEntityInfo[i].states[j].stateName);
+                    }
                 }
             }
         }
@@ -70,6 +78,8 @@
 
     static class StateResidencyResultUtils {
         public static void print(StateResidencyResult[] stateResidencyResult) {
+            if (stateResidencyResult == null) return;
+
             for (int i = 0; i < stateResidencyResult.length; i++) {
                 Slog.d(TAG, "PowerEntityId: " + stateResidencyResult[i].powerEntityId);
                 for (int j = 0; j < stateResidencyResult[i].stateResidencyData.length; j++) {
@@ -90,6 +100,8 @@
         public static void packProtoMessage(ChannelInfo[] channelInfo, ProtoOutputStream pos) {
             long token;
 
+            if (channelInfo == null) return;
+
             for (int i = 0; i < channelInfo.length; i++) {
                 token = pos.start(PowerStatsServiceMeterProto.CHANNEL_INFO);
                 pos.write(ChannelInfoProto.CHANNEL_ID, channelInfo[i].channelId);
@@ -100,6 +112,8 @@
         }
 
         public static void print(ChannelInfo[] channelInfo) {
+            if (channelInfo == null) return;
+
             for (int i = 0; i < channelInfo.length; i++) {
                 Slog.d(TAG, "ChannelId: " + channelInfo[i].channelId
                         + ", ChannelName: " + channelInfo[i].channelName);
@@ -107,6 +121,8 @@
         }
 
         public static void dumpsys(ChannelInfo[] channelInfo, PrintWriter pw) {
+            if (channelInfo == null) return;
+
             for (int i = 0; i < channelInfo.length; i++) {
                 pw.println("ChannelId: " + channelInfo[i].channelId
                         + ", ChannelName: " + channelInfo[i].channelName);
@@ -125,6 +141,8 @@
                 ProtoOutputStream pos) {
             long token;
 
+            if (energyMeasurement == null) return;
+
             for (int i = 0; i < energyMeasurement.length; i++) {
                 token = pos.start(PowerStatsServiceMeterProto.ENERGY_MEASUREMENT);
                 pos.write(EnergyMeasurementProto.CHANNEL_ID, energyMeasurement[i].channelId);
@@ -200,6 +218,8 @@
         }
 
         public static void print(EnergyMeasurement[] energyMeasurement) {
+            if (energyMeasurement == null) return;
+
             for (int i = 0; i < energyMeasurement.length; i++) {
                 Slog.d(TAG, "ChannelId: " + energyMeasurement[i].channelId
                         + ", Timestamp (ms): " + energyMeasurement[i].timestampMs
@@ -212,6 +232,8 @@
         public static void packProtoMessage(int[] energyConsumerId, ProtoOutputStream pos) {
             long token;
 
+            if (energyConsumerId == null) return;
+
             for (int i = 0; i < energyConsumerId.length; i++) {
                 token = pos.start(PowerStatsServiceModelProto.ENERGY_CONSUMER_ID);
                 pos.write(EnergyConsumerIdProto.ENERGY_CONSUMER_ID, energyConsumerId[i]);
@@ -220,12 +242,16 @@
         }
 
         public static void print(int[] energyConsumerId) {
+            if (energyConsumerId == null) return;
+
             for (int i = 0; i < energyConsumerId.length; i++) {
                 Slog.d(TAG, "EnergyConsumerId: " + energyConsumerId[i]);
             }
         }
 
         public static void dumpsys(int[] energyConsumerId, PrintWriter pw) {
+            if (energyConsumerId == null) return;
+
             for (int i = 0; i < energyConsumerId.length; i++) {
                 pw.println("EnergyConsumerId: " + energyConsumerId[i]);
             }
@@ -243,6 +269,8 @@
                 ProtoOutputStream pos) {
             long token;
 
+            if (energyConsumerResult == null) return;
+
             for (int i = 0; i < energyConsumerResult.length; i++) {
                 token = pos.start(PowerStatsServiceModelProto.ENERGY_CONSUMER_RESULT);
                 pos.write(EnergyConsumerResultProto.ENERGY_CONSUMER_ID,
@@ -321,6 +349,8 @@
         }
 
         public static void print(EnergyConsumerResult[] energyConsumerResult) {
+            if (energyConsumerResult == null) return;
+
             for (int i = 0; i < energyConsumerResult.length; i++) {
                 Slog.d(TAG, "EnergyConsumerId: " + energyConsumerResult[i].energyConsumerId
                         + ", Timestamp (ms): " + energyConsumerResult[i].timestampMs
diff --git a/services/core/java/com/android/server/recoverysystem/RecoverySystemService.java b/services/core/java/com/android/server/recoverysystem/RecoverySystemService.java
index 990055e..5c01e43 100644
--- a/services/core/java/com/android/server/recoverysystem/RecoverySystemService.java
+++ b/services/core/java/com/android/server/recoverysystem/RecoverySystemService.java
@@ -32,6 +32,8 @@
 import android.os.ResultReceiver;
 import android.os.ShellCallback;
 import android.os.SystemProperties;
+import android.util.ArrayMap;
+import android.util.ArraySet;
 import android.util.Slog;
 
 import com.android.internal.annotations.GuardedBy;
@@ -49,10 +51,6 @@
 import java.io.FileWriter;
 import java.io.IOException;
 import java.nio.charset.StandardCharsets;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Set;
 
 /**
  * The recovery system service is responsible for coordinating recovery related
@@ -84,9 +82,9 @@
     private final Context mContext;
 
     @GuardedBy("this")
-    private final Map<String, IntentSender> mCallerPendingRequest = new HashMap<>();
+    private final ArrayMap<String, IntentSender> mCallerPendingRequest = new ArrayMap<>();
     @GuardedBy("this")
-    private final Set<String> mCallerPreparedForReboot = new HashSet<>();
+    private final ArraySet<String> mCallerPreparedForReboot = new ArraySet<>();
 
     /**
      * Need to prepare for resume on reboot.
@@ -121,7 +119,7 @@
     @IntDef({ ROR_NEED_PREPARATION,
             ROR_SKIP_PREPARATION_AND_NOTIFY,
             ROR_SKIP_PREPARATION_NOT_NOTIFY })
-    @interface ResumeOnRebootActionsOnRequest {}
+    private @interface ResumeOnRebootActionsOnRequest {}
 
     /**
      * The action to perform upon resume on reboot clear request for a given client.
@@ -129,7 +127,7 @@
     @IntDef({ROR_NOT_REQUESTED,
             ROR_REQUESTED_NEED_CLEAR,
             ROR_REQUESTED_SKIP_CLEAR})
-    @interface ResumeOnRebootActionsOnClear{}
+    private @interface ResumeOnRebootActionsOnClear{}
 
     static class Injector {
         protected final Context mContext;
@@ -342,9 +340,8 @@
                 != PackageManager.PERMISSION_GRANTED
                 && mContext.checkCallingOrSelfPermission(android.Manifest.permission.REBOOT)
                         != PackageManager.PERMISSION_GRANTED) {
-            throw new SecurityException("Caller or self must have "
-                    + android.Manifest.permission.RECOVERY + " or "
-                    + android.Manifest.permission.REBOOT + " for resume on reboot.");
+            throw new SecurityException("Caller must have " + android.Manifest.permission.RECOVERY
+                    + " or " + android.Manifest.permission.REBOOT + " for resume on reboot.");
         }
     }
 
@@ -414,10 +411,14 @@
             Slog.w(TAG, "onPreparedForReboot called when some clients have prepared.");
         }
 
+        if (mCallerPendingRequest.isEmpty()) {
+            Slog.w(TAG, "onPreparedForReboot called but no client has requested.");
+        }
+
         // Send intents to notify callers
-        for (Map.Entry<String, IntentSender> entry : mCallerPendingRequest.entrySet()) {
-            sendPreparedForRebootIntentIfNeeded(entry.getValue());
-            mCallerPreparedForReboot.add(entry.getKey());
+        for (int i = 0; i < mCallerPendingRequest.size(); i++) {
+            sendPreparedForRebootIntentIfNeeded(mCallerPendingRequest.valueAt(i));
+            mCallerPreparedForReboot.add(mCallerPendingRequest.keyAt(i));
         }
         mCallerPendingRequest.clear();
     }
@@ -475,9 +476,7 @@
         return needClear ? ROR_REQUESTED_NEED_CLEAR : ROR_REQUESTED_SKIP_CLEAR;
     }
 
-    @Override // Binder call
-    public boolean rebootWithLskf(String packageName, String reason, boolean slotSwitch) {
-        enforcePermissionForResumeOnReboot();
+    private boolean rebootWithLskfImpl(String packageName, String reason, boolean slotSwitch) {
         if (packageName == null) {
             Slog.w(TAG, "Missing packageName when rebooting with lskf.");
             return false;
@@ -498,11 +497,29 @@
         return true;
     }
 
+    @Override // Binder call for the legacy rebootWithLskf
+    public boolean rebootWithLskfAssumeSlotSwitch(String packageName, String reason) {
+        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.RECOVERY, null);
+        return rebootWithLskfImpl(packageName, reason, true);
+    }
+
     @Override // Binder call
-    public synchronized boolean isLskfCaptured(String packageName) {
+    public boolean rebootWithLskf(String packageName, String reason, boolean slotSwitch) {
         enforcePermissionForResumeOnReboot();
-        if (!mCallerPreparedForReboot.contains(packageName)) {
-            Slog.i(TAG, "Reboot requested before prepare completed for caller " + packageName);
+        return rebootWithLskfImpl(packageName, reason, slotSwitch);
+    }
+
+    @Override // Binder call
+    public boolean isLskfCaptured(String packageName) {
+        enforcePermissionForResumeOnReboot();
+        boolean captured;
+        synchronized (this) {
+            captured = mCallerPreparedForReboot.contains(packageName);
+        }
+
+        if (!captured) {
+            Slog.i(TAG, "Reboot requested before prepare completed for caller "
+                    + packageName);
             return false;
         }
         return true;
diff --git a/services/core/java/com/android/server/storage/StorageUserConnection.java b/services/core/java/com/android/server/storage/StorageUserConnection.java
index 4a32d0f..13cceee 100644
--- a/services/core/java/com/android/server/storage/StorageUserConnection.java
+++ b/services/core/java/com/android/server/storage/StorageUserConnection.java
@@ -135,8 +135,6 @@
      */
     public void freeCache(String volumeUuid, long bytes)
             throws ExternalStorageServiceException {
-        Objects.requireNonNull(volumeUuid);
-
         synchronized (mSessionsLock) {
             for (String sessionId : mSessions.keySet()) {
                 mActiveConnection.freeCache(sessionId, volumeUuid, bytes);
diff --git a/services/core/java/com/android/server/utils/Snapshots.java b/services/core/java/com/android/server/utils/Snapshots.java
index 33b2bd4..f2406ab 100644
--- a/services/core/java/com/android/server/utils/Snapshots.java
+++ b/services/core/java/com/android/server/utils/Snapshots.java
@@ -48,7 +48,7 @@
      * @param dst The destination array.  It must be empty.
      * @param src The source array
      */
-    public <E> void copy(@NonNull SparseArray<E> dst, @NonNull SparseArray<E> src) {
+    public static <E> void copy(@NonNull SparseArray<E> dst, @NonNull SparseArray<E> src) {
         if (dst.size() != 0) {
             throw new IllegalArgumentException("copy destination is not empty");
         }
@@ -83,7 +83,7 @@
      * @param dst The destination array.  It must be empty.
      * @param src The source array
      */
-    public void snapshot(@NonNull SparseIntArray dst, @NonNull SparseIntArray src) {
+    public static void snapshot(@NonNull SparseIntArray dst, @NonNull SparseIntArray src) {
         if (dst.size() != 0) {
             throw new IllegalArgumentException("snapshot destination is not empty");
         }
diff --git a/services/core/java/com/android/server/utils/WatchableIntentResolver.java b/services/core/java/com/android/server/utils/WatchableIntentResolver.java
new file mode 100644
index 0000000..767fc07
--- /dev/null
+++ b/services/core/java/com/android/server/utils/WatchableIntentResolver.java
@@ -0,0 +1,93 @@
+/*
+ * 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.server.utils;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+
+import com.android.server.IntentResolver;
+
+import java.util.List;
+
+/**
+ * A watched {@link IntentResolver}.  The parameters are inherited from the superclass.
+ * @param <F> The filter type
+ * @param <R> The resolver type.
+ * {@hide}
+ */
+public abstract class WatchableIntentResolver<F, R extends Object>
+        extends IntentResolver<F, R>
+        implements Watchable {
+
+    /**
+     * Watchable machinery
+     */
+    private final Watchable mWatchable = new WatchableImpl();
+    /**
+     * Register an observer to receive change notifications.
+     * @param observer The observer to register.
+     */
+    public void registerObserver(@NonNull Watcher observer) {
+        mWatchable.registerObserver(observer);
+    }
+    /**
+     * Unregister the observer, which will no longer receive change notifications.
+     * @param observer The observer to unregister.
+     */
+    public void unregisterObserver(@NonNull Watcher observer) {
+        mWatchable.unregisterObserver(observer);
+    }
+    /**
+     * Notify listeners that the object has changd.  The argument is a hint as to the
+     * source of the change.
+     * @param what The attribute or sub-object that changed, if not null.
+     */
+    public void dispatchChange(@Nullable Watchable what) {
+        mWatchable.dispatchChange(what);
+    }
+    /**
+     * Notify listeners that this object has changed.
+     */
+    protected void onChanged() {
+        dispatchChange(this);
+    }
+
+    @Override
+    public void addFilter(F f) {
+        super.addFilter(f);
+        onChanged();
+    }
+
+    @Override
+    public void removeFilter(F f) {
+        super.removeFilter(f);
+        onChanged();
+    }
+
+    @Override
+    protected void removeFilterInternal(F f) {
+        super.removeFilterInternal(f);
+        onChanged();
+    }
+
+    @Override
+    @SuppressWarnings("unchecked")
+    protected void sortResults(List<R> results) {
+        super.sortResults(results);
+        onChanged();
+    }
+}
diff --git a/services/core/java/com/android/server/vcn/Android.bp b/services/core/java/com/android/server/vcn/Android.bp
new file mode 100644
index 0000000..5ed204f
--- /dev/null
+++ b/services/core/java/com/android/server/vcn/Android.bp
@@ -0,0 +1,4 @@
+filegroup {
+    name: "framework-vcn-util-sources",
+    srcs: ["util/**/*.java"],
+}
\ No newline at end of file
diff --git a/services/core/java/com/android/server/vcn/TelephonySubscriptionTracker.java b/services/core/java/com/android/server/vcn/TelephonySubscriptionTracker.java
new file mode 100644
index 0000000..c060807
--- /dev/null
+++ b/services/core/java/com/android/server/vcn/TelephonySubscriptionTracker.java
@@ -0,0 +1,314 @@
+/*
+ * 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.server.vcn;
+
+import static android.telephony.CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED;
+import static android.telephony.CarrierConfigManager.EXTRA_SLOT_INDEX;
+import static android.telephony.CarrierConfigManager.EXTRA_SUBSCRIPTION_INDEX;
+import static android.telephony.SubscriptionManager.INVALID_SIM_SLOT_INDEX;
+import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.os.Handler;
+import android.os.HandlerExecutor;
+import android.os.ParcelUuid;
+import android.os.PersistableBundle;
+import android.telephony.CarrierConfigManager;
+import android.telephony.SubscriptionInfo;
+import android.telephony.SubscriptionManager;
+import android.telephony.SubscriptionManager.OnSubscriptionsChangedListener;
+import android.util.ArraySet;
+import android.util.Slog;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.annotations.VisibleForTesting.Visibility;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Objects;
+import java.util.Set;
+
+/**
+ * TelephonySubscriptionTracker provides a caching layer for tracking active subscription groups.
+ *
+ * <p>This class performs two roles:
+ *
+ * <ol>
+ *   <li>De-noises subscription changes by ensuring that only changes in active and ready
+ *       subscription groups are acted upon
+ *   <li>Caches mapping between subIds and subscription groups
+ * </ol>
+ *
+ * <p>An subscription group is active and ready if any of its contained subIds has had BOTH the
+ * {@link CarrierConfigManager#isConfigForIdentifiedCarrier()} return true, AND the subscription is
+ * listed as active per SubscriptionManager#getAllSubscriptionInfoList().
+ *
+ * <p>Note that due to the asynchronous nature of callbacks and broadcasts, the output of this class
+ * is (only) eventually consistent.
+ *
+ * @hide
+ */
+public class TelephonySubscriptionTracker extends BroadcastReceiver {
+    @NonNull private static final String TAG = TelephonySubscriptionTracker.class.getSimpleName();
+    private static final boolean LOG_DBG = false; // STOPSHIP if true
+
+    @NonNull private final Context mContext;
+    @NonNull private final Handler mHandler;
+    @NonNull private final TelephonySubscriptionTrackerCallback mCallback;
+    @NonNull private final Dependencies mDeps;
+
+    @NonNull private final SubscriptionManager mSubscriptionManager;
+    @NonNull private final CarrierConfigManager mCarrierConfigManager;
+
+    // TODO (Android T+): Add ability to handle multiple subIds per slot.
+    @NonNull private final Map<Integer, Integer> mReadySubIdsBySlotId = new HashMap<>();
+    @NonNull private final OnSubscriptionsChangedListener mSubscriptionChangedListener;
+
+    @NonNull private TelephonySubscriptionSnapshot mCurrentSnapshot;
+
+    public TelephonySubscriptionTracker(
+            @NonNull Context context,
+            @NonNull Handler handler,
+            @NonNull TelephonySubscriptionTrackerCallback callback) {
+        this(context, handler, callback, new Dependencies());
+    }
+
+    @VisibleForTesting(visibility = Visibility.PRIVATE)
+    TelephonySubscriptionTracker(
+            @NonNull Context context,
+            @NonNull Handler handler,
+            @NonNull TelephonySubscriptionTrackerCallback callback,
+            @NonNull Dependencies deps) {
+        mContext = Objects.requireNonNull(context, "Missing context");
+        mHandler = Objects.requireNonNull(handler, "Missing handler");
+        mCallback = Objects.requireNonNull(callback, "Missing callback");
+        mDeps = Objects.requireNonNull(deps, "Missing deps");
+
+        mSubscriptionManager = mContext.getSystemService(SubscriptionManager.class);
+        mCarrierConfigManager = mContext.getSystemService(CarrierConfigManager.class);
+
+        mSubscriptionChangedListener =
+                new OnSubscriptionsChangedListener() {
+                    @Override
+                    public void onSubscriptionsChanged() {
+                        handleSubscriptionsChanged();
+                    }
+                };
+    }
+
+    /** Registers the receivers, and starts tracking subscriptions. */
+    public void register() {
+        mContext.registerReceiver(
+                this, new IntentFilter(ACTION_CARRIER_CONFIG_CHANGED), null, mHandler);
+        mSubscriptionManager.addOnSubscriptionsChangedListener(
+                new HandlerExecutor(mHandler), mSubscriptionChangedListener);
+    }
+
+    /** Unregisters the receivers, and stops tracking subscriptions. */
+    public void unregister() {
+        mContext.unregisterReceiver(this);
+        mSubscriptionManager.removeOnSubscriptionsChangedListener(mSubscriptionChangedListener);
+    }
+
+    /**
+     * Handles subscription changes, correlating available subscriptions and loaded carrier configs
+     *
+     * <p>The subscription change listener is registered with a HandlerExecutor backed by mHandler,
+     * so callbacks & broadcasts are all serialized on mHandler, avoiding the need for locking.
+     */
+    public void handleSubscriptionsChanged() {
+        final Set<ParcelUuid> activeSubGroups = new ArraySet<>();
+        final Map<Integer, ParcelUuid> newSubIdToGroupMap = new HashMap<>();
+
+        final List<SubscriptionInfo> allSubs = mSubscriptionManager.getAllSubscriptionInfoList();
+        if (allSubs == null) {
+            return; // Telephony crashed; no way to verify subscriptions.
+        }
+
+        // If allSubs is empty, no subscriptions exist. Cache will be cleared by virtue of no active
+        // subscriptions
+        for (SubscriptionInfo subInfo : allSubs) {
+            if (subInfo.getGroupUuid() == null) {
+                continue;
+            }
+
+            // Build subId -> subGrp cache
+            newSubIdToGroupMap.put(subInfo.getSubscriptionId(), subInfo.getGroupUuid());
+
+            // Update subscription groups that are both ready, and active. For a group to be
+            // considered active, both of the following must be true:
+            //
+            // 1. A final CARRIER_CONFIG_CHANGED (where config is for an identified carrier)
+            // broadcast must have been received for the subId
+            // 2. A active subscription (is loaded into a SIM slot) must be part of the subscription
+            // group.
+            if (subInfo.getSimSlotIndex() != INVALID_SIM_SLOT_INDEX
+                    && mReadySubIdsBySlotId.values().contains(subInfo.getSubscriptionId())) {
+                activeSubGroups.add(subInfo.getGroupUuid());
+            }
+        }
+
+        final TelephonySubscriptionSnapshot newSnapshot =
+                new TelephonySubscriptionSnapshot(newSubIdToGroupMap, activeSubGroups);
+
+        // If snapshot was meaningfully updated, fire the callback
+        if (!newSnapshot.equals(mCurrentSnapshot)) {
+            mCurrentSnapshot = newSnapshot;
+            mHandler.post(
+                    () -> {
+                        mCallback.onNewSnapshot(newSnapshot);
+                    });
+        }
+    }
+
+    /**
+     * Broadcast receiver for ACTION_CARRIER_CONFIG_CHANGED
+     *
+     * <p>The broadcast receiver is registered with mHandler, so callbacks & broadcasts are all
+     * serialized on mHandler, avoiding the need for locking.
+     */
+    @Override
+    public void onReceive(Context context, Intent intent) {
+        // Accept sticky broadcasts; if CARRIER_CONFIG_CHANGED was previously broadcast and it
+        // already was for an identified carrier, we can stop waiting for initial load to complete
+        if (!ACTION_CARRIER_CONFIG_CHANGED.equals(intent.getAction())) {
+            return;
+        }
+
+        final int subId = intent.getIntExtra(EXTRA_SUBSCRIPTION_INDEX, INVALID_SUBSCRIPTION_ID);
+        final int slotId = intent.getIntExtra(EXTRA_SLOT_INDEX, INVALID_SIM_SLOT_INDEX);
+
+        if (slotId == INVALID_SIM_SLOT_INDEX) {
+            return;
+        }
+
+        if (SubscriptionManager.isValidSubscriptionId(subId)) {
+            final PersistableBundle carrierConfigs = mCarrierConfigManager.getConfigForSubId(subId);
+            if (mDeps.isConfigForIdentifiedCarrier(carrierConfigs)) {
+                Slog.v(TAG, String.format("SubId %s ready for SlotId %s", subId, slotId));
+                mReadySubIdsBySlotId.put(slotId, subId);
+                handleSubscriptionsChanged();
+            }
+        } else {
+            Slog.v(TAG, "Slot unloaded: " + slotId);
+            mReadySubIdsBySlotId.remove(slotId);
+            handleSubscriptionsChanged();
+        }
+    }
+
+    @VisibleForTesting(visibility = Visibility.PRIVATE)
+    void setReadySubIdsBySlotId(Map<Integer, Integer> readySubIdsBySlotId) {
+        mReadySubIdsBySlotId.putAll(readySubIdsBySlotId);
+    }
+
+    @VisibleForTesting(visibility = Visibility.PRIVATE)
+    Map<Integer, Integer> getReadySubIdsBySlotId() {
+        return Collections.unmodifiableMap(mReadySubIdsBySlotId);
+    }
+
+    /** TelephonySubscriptionSnapshot is a class containing info about active subscriptions */
+    public static class TelephonySubscriptionSnapshot {
+        private final Map<Integer, ParcelUuid> mSubIdToGroupMap;
+        private final Set<ParcelUuid> mActiveGroups;
+
+        @VisibleForTesting(visibility = Visibility.PRIVATE)
+        TelephonySubscriptionSnapshot(
+                @NonNull Map<Integer, ParcelUuid> subIdToGroupMap,
+                @NonNull Set<ParcelUuid> activeGroups) {
+            mSubIdToGroupMap = Collections.unmodifiableMap(
+                    Objects.requireNonNull(subIdToGroupMap, "subIdToGroupMap was null"));
+            mActiveGroups = Collections.unmodifiableSet(
+                    Objects.requireNonNull(activeGroups, "activeGroups was null"));
+        }
+
+        /** Returns the active subscription groups */
+        @NonNull
+        public Set<ParcelUuid> getActiveSubscriptionGroups() {
+            return mActiveGroups;
+        }
+
+        /** Returns the Subscription Group for a given subId. */
+        @Nullable
+        public ParcelUuid getGroupForSubId(int subId) {
+            return mSubIdToGroupMap.get(subId);
+        }
+
+        /**
+         * Returns all the subIds in a given group, including available, but inactive subscriptions.
+         */
+        @NonNull
+        public Set<Integer> getAllSubIdsInGroup(ParcelUuid subGrp) {
+            final Set<Integer> subIds = new ArraySet<>();
+
+            for (Entry<Integer, ParcelUuid> entry : mSubIdToGroupMap.entrySet()) {
+                if (subGrp.equals(entry.getValue())) {
+                    subIds.add(entry.getKey());
+                }
+            }
+
+            return subIds;
+        }
+
+        @Override
+        public int hashCode() {
+            return Objects.hash(mSubIdToGroupMap, mActiveGroups);
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (!(obj instanceof TelephonySubscriptionSnapshot)) {
+                return false;
+            }
+
+            final TelephonySubscriptionSnapshot other = (TelephonySubscriptionSnapshot) obj;
+
+            return mSubIdToGroupMap.equals(other.mSubIdToGroupMap)
+                    && mActiveGroups.equals(other.mActiveGroups);
+        }
+    }
+
+    /**
+     * Interface for listening to changes in subscriptions
+     *
+     * @see TelephonySubscriptionTracker
+     */
+    public interface TelephonySubscriptionTrackerCallback {
+        /**
+         * Called when subscription information changes, and a new subscription snapshot was taken
+         *
+         * @param snapshot the snapshot of subscription information.
+         */
+        void onNewSnapshot(@NonNull TelephonySubscriptionSnapshot snapshot);
+    }
+
+    /** External static dependencies for test injection */
+    @VisibleForTesting(visibility = Visibility.PRIVATE)
+    public static class Dependencies {
+        /** Checks if the given bundle is for an identified carrier */
+        public boolean isConfigForIdentifiedCarrier(PersistableBundle bundle) {
+            return CarrierConfigManager.isConfigForIdentifiedCarrier(bundle);
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 9efa249..3390d67 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -1759,6 +1759,9 @@
         final TaskSnapshot snapshot =
                 mWmService.mTaskSnapshotController.getSnapshot(task.mTaskId, task.mUserId,
                         false /* restoreFromDisk */, false /* isLowResolution */);
+        final int typeParameter = mWmService.mStartingSurfaceController
+                .makeStartingWindowTypeParameter(newTask, taskSwitch, processRunning,
+                        allowTaskSnapshot, activityCreated);
         final int type = getStartingWindowType(newTask, taskSwitch, processRunning,
                 allowTaskSnapshot, activityCreated, snapshot);
 
@@ -1773,7 +1776,7 @@
                     return false;
                 }
             }
-            return createSnapshot(snapshot);
+            return createSnapshot(snapshot, typeParameter);
         }
 
         // If this is a translucent window, then don't show a starting window -- the current
@@ -1833,18 +1836,18 @@
         ProtoLog.v(WM_DEBUG_STARTING_WINDOW, "Creating SplashScreenStartingData");
         mStartingData = new SplashScreenStartingData(mWmService, pkg,
                 theme, compatInfo, nonLocalizedLabel, labelRes, icon, logo, windowFlags,
-                getMergedOverrideConfiguration());
+                getMergedOverrideConfiguration(), typeParameter);
         scheduleAddStartingWindow();
         return true;
     }
 
-    private boolean createSnapshot(TaskSnapshot snapshot) {
+    private boolean createSnapshot(TaskSnapshot snapshot, int typeParams) {
         if (snapshot == null) {
             return false;
         }
 
         ProtoLog.v(WM_DEBUG_STARTING_WINDOW, "Creating SnapshotStartingData");
-        mStartingData = new SnapshotStartingData(mWmService, snapshot);
+        mStartingData = new SnapshotStartingData(mWmService, snapshot, typeParams);
         scheduleAddStartingWindow();
         return true;
     }
diff --git a/services/core/java/com/android/server/wm/Dimmer.java b/services/core/java/com/android/server/wm/Dimmer.java
index 07729d1..029056a 100644
--- a/services/core/java/com/android/server/wm/Dimmer.java
+++ b/services/core/java/com/android/server/wm/Dimmer.java
@@ -204,7 +204,7 @@
     }
 
     private void dim(SurfaceControl.Transaction t, WindowContainer container, int relativeLayer,
-            float alpha) {
+            float alpha, int blurRadius) {
         final DimState d = getDimState(container);
 
         if (d == null) {
@@ -220,6 +220,7 @@
             t.setLayer(d.mDimLayer, Integer.MAX_VALUE);
         }
         t.setAlpha(d.mDimLayer, alpha);
+        t.setBackgroundBlurRadius(d.mDimLayer, blurRadius);
 
         d.mDimming = true;
     }
@@ -247,7 +248,7 @@
      * @param alpha The alpha at which to Dim.
      */
     void dimAbove(SurfaceControl.Transaction t, float alpha) {
-        dim(t, null, 1, alpha);
+        dim(t, null, 1, alpha, 0);
     }
 
     /**
@@ -260,19 +261,21 @@
      * @param alpha     The alpha at which to Dim.
      */
     void dimAbove(SurfaceControl.Transaction t, WindowContainer container, float alpha) {
-        dim(t, container, 1, alpha);
+        dim(t, container, 1, alpha, 0);
     }
 
     /**
      * Like {@link #dimAbove} but places the dim below the given container.
      *
-     * @param t         A transaction in which to apply the Dim.
-     * @param container The container which to dim below. Should be a child of our host.
-     * @param alpha     The alpha at which to Dim.
+     * @param t          A transaction in which to apply the Dim.
+     * @param container  The container which to dim below. Should be a child of our host.
+     * @param alpha      The alpha at which to Dim.
+     * @param blurRadius The amount of blur added to the Dim.
      */
 
-    void dimBelow(SurfaceControl.Transaction t, WindowContainer container, float alpha) {
-        dim(t, container, -1, alpha);
+    void dimBelow(SurfaceControl.Transaction t, WindowContainer container, float alpha,
+                  int blurRadius) {
+        dim(t, container, -1, alpha, blurRadius);
     }
 
     /**
diff --git a/services/core/java/com/android/server/wm/DisplayAreaOrganizerController.java b/services/core/java/com/android/server/wm/DisplayAreaOrganizerController.java
index c475da3..53f7009 100644
--- a/services/core/java/com/android/server/wm/DisplayAreaOrganizerController.java
+++ b/services/core/java/com/android/server/wm/DisplayAreaOrganizerController.java
@@ -134,7 +134,7 @@
 
     @Override
     public DisplayAreaAppearedInfo createTaskDisplayArea(IDisplayAreaOrganizer organizer,
-            int displayId, int rootFeatureId, String name) {
+            int displayId, int parentFeatureId, String name) {
         enforceTaskPermission("createTaskDisplayArea()");
         final long uid = Binder.getCallingUid();
         final long origId = Binder.clearCallingIdentity();
@@ -149,13 +149,26 @@
                             + displayId);
                 }
 
-                final DisplayArea root = display.getItemFromDisplayAreas(da ->
-                        da.asRootDisplayArea() != null && da.mFeatureId == rootFeatureId
-                                ? da
+                // The parentFeatureId can be either a RootDisplayArea or a TaskDisplayArea.
+                // Check if there is a RootDisplayArea with the given parentFeatureId.
+                final RootDisplayArea parentRoot = display.getItemFromDisplayAreas(da ->
+                        da.asRootDisplayArea() != null && da.mFeatureId == parentFeatureId
+                                ? da.asRootDisplayArea()
                                 : null);
-                if (root == null) {
-                    throw new IllegalArgumentException("Can't find RootDisplayArea with featureId="
-                            + rootFeatureId);
+                final TaskDisplayArea parentTda;
+                if (parentRoot == null) {
+                    // There is no RootDisplayArea matching the parentFeatureId.
+                    // Check if there is a TaskDisplayArea with the given parentFeatureId.
+                    parentTda = display.getItemFromTaskDisplayAreas(taskDisplayArea ->
+                            taskDisplayArea.mFeatureId == parentFeatureId
+                                    ? taskDisplayArea
+                                    : null);
+                } else {
+                    parentTda = null;
+                }
+                if (parentRoot == null && parentTda == null) {
+                    throw new IllegalArgumentException(
+                            "Can't find a parent DisplayArea with featureId=" + parentFeatureId);
                 }
 
                 final int taskDisplayAreaFeatureId = mNextTaskDisplayAreaFeatureId++;
@@ -166,10 +179,13 @@
                     // Oh well...
                 }
 
-                final TaskDisplayArea tda = createTaskDisplayArea(root.asRootDisplayArea(), name,
-                        taskDisplayAreaFeatureId);
-                return organizeDisplayArea(organizer, tda,
+                final TaskDisplayArea tda = parentRoot != null
+                        ? createTaskDisplayArea(parentRoot, name, taskDisplayAreaFeatureId)
+                        : createTaskDisplayArea(parentTda, name, taskDisplayAreaFeatureId);
+                final DisplayAreaAppearedInfo tdaInfo = organizeDisplayArea(organizer, tda,
                         "DisplayAreaOrganizerController.createTaskDisplayArea");
+                mOrganizersByFeatureIds.put(taskDisplayAreaFeatureId, organizer);
+                return tdaInfo;
             }
         } finally {
             Binder.restoreCallingIdentity(origId);
@@ -196,6 +212,7 @@
                                     + "TaskDisplayArea=" + taskDisplayArea);
                 }
 
+                mOrganizersByFeatureIds.remove(taskDisplayArea.mFeatureId);
                 deleteTaskDisplayArea(taskDisplayArea);
             }
         } finally {
@@ -253,6 +270,9 @@
                 new SurfaceControl(displayArea.getSurfaceControl(), callsite));
     }
 
+    /**
+     * Creates a {@link TaskDisplayArea} as the topmost TDA below the given {@link RootDisplayArea}.
+     */
     private TaskDisplayArea createTaskDisplayArea(RootDisplayArea root, String name,
             int taskDisplayAreaFeatureId) {
         final TaskDisplayArea taskDisplayArea = new TaskDisplayArea(root.mDisplayContent,
@@ -283,6 +303,21 @@
         return taskDisplayArea;
     }
 
+    /**
+     * Creates a {@link TaskDisplayArea} as the topmost child of the given {@link TaskDisplayArea}.
+     */
+    private TaskDisplayArea createTaskDisplayArea(TaskDisplayArea parentTda, String name,
+            int taskDisplayAreaFeatureId) {
+        final TaskDisplayArea taskDisplayArea = new TaskDisplayArea(parentTda.mDisplayContent,
+                parentTda.mWmService, name, taskDisplayAreaFeatureId,
+                true /* createdByOrganizer */);
+
+        // Insert the TaskDisplayArea on the top.
+        parentTda.addChild(taskDisplayArea, WindowContainer.POSITION_TOP);
+
+        return taskDisplayArea;
+    }
+
     private void deleteTaskDisplayArea(TaskDisplayArea taskDisplayArea) {
         taskDisplayArea.setOrganizer(null);
         mService.mRootWindowContainer.mTaskSupervisor.beginDeferResume();
diff --git a/services/core/java/com/android/server/wm/DisplayAreaPolicy.java b/services/core/java/com/android/server/wm/DisplayAreaPolicy.java
index f8c3754..d4b319a 100644
--- a/services/core/java/com/android/server/wm/DisplayAreaPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayAreaPolicy.java
@@ -99,41 +99,23 @@
 
             // Define the features that will be supported under the root of the whole logical
             // display. The policy will build the DisplayArea hierarchy based on this.
-            final HierarchyBuilder rootHierarchy = new HierarchyBuilder(root);
-            if (content.isTrusted()) {
-                // Only trusted display can have system decorations.
-                configureTrustedHierarchyBuilder(rootHierarchy, wmService, content);
-            }
-            // Set the essential containers (even the display doesn't support IME).
-            rootHierarchy.setImeContainer(imeContainer).setTaskDisplayAreas(tdaList);
-
-            // Instantiate the policy with the hierarchy defined above. This will create and attach
-            // all the necessary DisplayAreas to the root.
-            return new DisplayAreaPolicyBuilder().setRootHierarchy(rootHierarchy).build(wmService);
-        }
-
-        private void configureTrustedHierarchyBuilder(HierarchyBuilder rootHierarchy,
-                WindowManagerService wmService, DisplayContent content) {
-            // WindowedMagnification should be on the top so that there is only one surface
-            // to be magnified.
-            rootHierarchy.addFeature(new Feature.Builder(wmService.mPolicy, "WindowedMagnification",
-                    FEATURE_WINDOWED_MAGNIFICATION)
-                    .upTo(TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY)
-                    .except(TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY)
-                    // Make the DA dimmable so that the magnify window also mirrors the dim layer.
-                    .setNewDisplayAreaSupplier(DisplayArea.Dimmable::new)
-                    .build());
-            if (content.isDefaultDisplay) {
-                // Only default display can have cutout.
-                // See LocalDisplayAdapter.LocalDisplayDevice#getDisplayDeviceInfoLocked.
-                rootHierarchy.addFeature(new Feature.Builder(wmService.mPolicy, "HideDisplayCutout",
-                        FEATURE_HIDE_DISPLAY_CUTOUT)
-                        .all()
-                        .except(TYPE_NAVIGATION_BAR, TYPE_NAVIGATION_BAR_PANEL,
-                                TYPE_STATUS_BAR, TYPE_NOTIFICATION_SHADE)
-                        .build());
-            }
-            rootHierarchy
+            HierarchyBuilder rootHierarchy = new HierarchyBuilder(root)
+                    // WindowedMagnification should be on the top so that there is only one surface
+                    // to be magnified.
+                    .addFeature(new Feature.Builder(wmService.mPolicy, "WindowedMagnification",
+                            FEATURE_WINDOWED_MAGNIFICATION)
+                            .upTo(TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY)
+                            .except(TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY)
+                            // Make the DA dimmable so that the magnify window also mirrors the dim
+                            // layer
+                            .setNewDisplayAreaSupplier(DisplayArea.Dimmable::new)
+                            .build())
+                    .addFeature(new Feature.Builder(wmService.mPolicy, "HideDisplayCutout",
+                            FEATURE_HIDE_DISPLAY_CUTOUT)
+                            .all()
+                            .except(TYPE_NAVIGATION_BAR, TYPE_NAVIGATION_BAR_PANEL, TYPE_STATUS_BAR,
+                                    TYPE_NOTIFICATION_SHADE)
+                            .build())
                     .addFeature(new Feature.Builder(wmService.mPolicy, "OneHanded",
                             FEATURE_ONE_HANDED)
                             .all()
@@ -149,7 +131,13 @@
                     .addFeature(new Feature.Builder(wmService.mPolicy, "ImePlaceholder",
                             FEATURE_IME_PLACEHOLDER)
                             .and(TYPE_INPUT_METHOD, TYPE_INPUT_METHOD_DIALOG)
-                            .build());
+                            .build())
+                    .setImeContainer(imeContainer)
+                    .setTaskDisplayAreas(tdaList);
+
+            // Instantiate the policy with the hierarchy defined above. This will create and attach
+            // all the necessary DisplayAreas to the root.
+            return new DisplayAreaPolicyBuilder().setRootHierarchy(rootHierarchy).build(wmService);
         }
     }
 
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index fc9753c..4c60a3d 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -283,6 +283,12 @@
      */
     private SurfaceControl mOverlayLayer;
 
+    /**
+     * The direct child layer of the display to put all non-overlay windows. This is also used for
+     * screen rotation animation so that there is a parent layer to put the animation leash.
+     */
+    private final SurfaceControl mWindowingLayer;
+
     // Contains all IME window containers. Note that the z-ordering of the IME windows will depend
     // on the IME target. We mainly have this container grouping so we can keep track of all the IME
     // window containers together and move them in-sync if/when needed. We use a subclass of
@@ -294,7 +300,6 @@
     final DisplayAreaPolicy mDisplayAreaPolicy;
 
     private WindowState mTmpWindow;
-    private WindowState mTmpWindow2;
     private boolean mUpdateImeTarget;
     private boolean mTmpInitial;
     private int mMaxUiWidth;
@@ -459,10 +464,6 @@
     private final ApplySurfaceChangesTransactionState mTmpApplySurfaceChangesTransactionState =
             new ApplySurfaceChangesTransactionState();
 
-    // True if this display is in the process of being removed. Used to determine if the removal of
-    // the display's direct children should be allowed.
-    private boolean mRemovingDisplay = false;
-
     // {@code false} if this display is in the processing of being created.
     private boolean mDisplayReady = false;
 
@@ -1023,6 +1024,27 @@
                 .setContainerLayer()
                 .setCallsite("DisplayContent");
         mSurfaceControl = b.setName("Root").setContainerLayer().build();
+
+        // Setup the policy and build the display area hierarchy.
+        mDisplayAreaPolicy = mWmService.getDisplayAreaPolicyProvider().instantiate(
+                mWmService, this /* content */, this /* root */, mImeWindowsContainers);
+
+        final List<DisplayArea<? extends WindowContainer>> areas =
+                mDisplayAreaPolicy.getDisplayAreas(FEATURE_WINDOWED_MAGNIFICATION);
+        final DisplayArea<?> area = areas.size() == 1 ? areas.get(0) : null;
+        if (area != null && area.getParent() == this) {
+            // The windowed magnification area should contain all non-overlay windows, so just use
+            // it as the windowing layer.
+            mWindowingLayer = area.mSurfaceControl;
+        } else {
+            // Need an additional layer for screen level animation, so move the layer containing
+            // the windows to the new root.
+            mWindowingLayer = mSurfaceControl;
+            mSurfaceControl = b.setName("RootWrapper").build();
+            getPendingTransaction().reparent(mWindowingLayer, mSurfaceControl)
+                    .show(mWindowingLayer);
+        }
+
         mOverlayLayer = b.setName("Display Overlays").setParent(mSurfaceControl).build();
 
         getPendingTransaction()
@@ -1033,10 +1055,6 @@
                 .show(mOverlayLayer);
         getPendingTransaction().apply();
 
-        // Setup the policy and build the display area hierarchy.
-        mDisplayAreaPolicy = mWmService.getDisplayAreaPolicyProvider().instantiate(
-                mWmService, this /* content */, this /* root */, mImeWindowsContainers);
-
         // Sets the display content for the children.
         onDisplayChanged(this);
 
@@ -2300,10 +2318,9 @@
         return count[0];
     }
 
-    @VisibleForTesting
     @Nullable
     Task getTopRootTask() {
-        return getItemFromTaskDisplayAreas(TaskDisplayArea::getTopRootTask);
+        return getRootTask(t -> true);
     }
 
     /**
@@ -2797,7 +2814,6 @@
 
     @Override
     void removeImmediately() {
-        mRemovingDisplay = true;
         mDeferredRemoval = false;
         try {
             if (mParentWindow != null) {
@@ -2821,7 +2837,6 @@
             mWmService.mDisplayNotificationController.dispatchDisplayRemoved(this);
         } finally {
             mDisplayReady = false;
-            mRemovingDisplay = false;
         }
 
         // Apply the pending transaction here since we may not be able to reach the DisplayContent
@@ -4191,7 +4206,6 @@
 
         // Used to indicate that we have processed the dream window and all additional attached
         // windows are behind it.
-        mTmpWindow2 = mTmpWindow;
         mTmpWindow = null;
 
         // Now perform layout of attached windows, which usually depend on the position of the
@@ -4861,19 +4875,8 @@
         }, false /* traverseTopToBottom */);
     }
 
-    private DisplayArea getWindowContainers() {
-        List<DisplayArea<? extends WindowContainer>> windowContainers =
-                mDisplayAreaPolicy.getDisplayAreas(FEATURE_WINDOWED_MAGNIFICATION);
-        if (windowContainers.size() != 1) {
-            throw new IllegalStateException("There should be only one DisplayArea for "
-                    + "FEATURE_WINDOWED_MAGNIFICATION");
-        }
-        return windowContainers.get(0);
-    }
-
-    @VisibleForTesting
     SurfaceControl getWindowingLayer() {
-        return getWindowContainers().getSurfaceControl();
+        return mWindowingLayer;
     }
 
     DisplayArea.Tokens getImeContainer() {
@@ -5479,12 +5482,12 @@
             return;
         }
 
-        // Check if all task display areas have only the empty home stacks left.
-        boolean hasNonEmptyHomeStack = forAllRootTasks(stack ->
-                !stack.isActivityTypeHome() || stack.hasChild());
-        if (!hasNonEmptyHomeStack && getRootTaskCount() > 0) {
-            // Release this display if only empty home stack(s) are left. This display will be
-            // released along with the stack(s) removal.
+        // Check if all task display areas have only the empty home root tasks left.
+        boolean hasNonEmptyHomeRootTask = forAllRootTasks(rootTask ->
+                !rootTask.isActivityTypeHome() || rootTask.hasChild());
+        if (!hasNonEmptyHomeRootTask && getRootTaskCount() > 0) {
+            // Release this display if only empty home root task(s) are left. This display will be
+            // released along with the root task(s) removal.
             forAllRootTasks(Task::removeIfPossible);
         } else if (getTopRootTask() == null) {
             removeIfPossible();
@@ -5525,12 +5528,14 @@
             return;
         }
         mInEnsureActivitiesVisible = true;
+        mAtmService.mTaskSupervisor.beginActivityVisibilityUpdate();
         try {
-            forAllTaskDisplayAreas(taskDisplayArea -> {
-                taskDisplayArea.ensureActivitiesVisible(starting, configChanges,
-                        preserveWindows, notifyClients, userLeaving);
+            forAllRootTasks(rootTask -> {
+                rootTask.ensureActivitiesVisible(starting, configChanges, preserveWindows,
+                        notifyClients, userLeaving);
             });
         } finally {
+            mAtmService.mTaskSupervisor.endActivityVisibilityUpdate();
             mInEnsureActivitiesVisible = false;
         }
     }
diff --git a/services/core/java/com/android/server/wm/InputManagerCallback.java b/services/core/java/com/android/server/wm/InputManagerCallback.java
index 35f5615..6e89581 100644
--- a/services/core/java/com/android/server/wm/InputManagerCallback.java
+++ b/services/core/java/com/android/server/wm/InputManagerCallback.java
@@ -26,9 +26,7 @@
 import android.annotation.NonNull;
 import android.os.Debug;
 import android.os.IBinder;
-import android.os.RemoteException;
 import android.util.Slog;
-import android.view.IWindow;
 import android.view.InputApplicationHandle;
 import android.view.KeyEvent;
 import android.view.WindowManager;
@@ -37,7 +35,6 @@
 import com.android.server.input.InputManagerService;
 
 import java.io.PrintWriter;
-import java.util.concurrent.atomic.AtomicReference;
 
 final class InputManagerCallback implements InputManagerService.WindowManagerCallbacks {
     private static final String TAG = TAG_WITH_CLASS_NAME ? "InputManagerCallback" : TAG_WM;
@@ -60,13 +57,6 @@
     // which point the ActivityManager will enable dispatching.
     private boolean mInputDispatchEnabled;
 
-    // TODO(b/141749603)) investigate if this can be part of client focus change dispatch
-    // Tracks the currently focused window used to update pointer capture state in clients
-    private AtomicReference<IWindow> mFocusedWindow = new AtomicReference<>();
-
-    // Tracks focused window pointer capture state
-    private boolean mFocusedWindowHasCapture;
-
     public InputManagerCallback(WindowManagerService service) {
         mService = service;
     }
@@ -234,59 +224,9 @@
     }
 
     @Override
-    public boolean notifyFocusChanged(IBinder oldToken, IBinder newToken) {
-        boolean requestRefreshConfiguration = false;
-        final IWindow newFocusedWindow;
-        final WindowState win;
-
-        // TODO(b/141749603) investigate if this can be part of client focus change dispatch
-        synchronized (mService.mGlobalLock) {
-            win = mService.mInputToWindowMap.get(newToken);
-        }
-        newFocusedWindow = (win != null) ? win.mClient : null;
-
-        final IWindow focusedWindow = mFocusedWindow.get();
-        if (focusedWindow != null) {
-            if (newFocusedWindow != null
-                    && newFocusedWindow.asBinder() == focusedWindow.asBinder()) {
-                Slog.w(TAG, "notifyFocusChanged called with unchanged mFocusedWindow="
-                        + focusedWindow);
-                return false;
-            }
-            requestRefreshConfiguration = dispatchPointerCaptureChanged(focusedWindow, false);
-        }
-        mFocusedWindow.set(newFocusedWindow);
-        mService.mH.sendMessage(PooledLambda.obtainMessage(mService::reportFocusChanged,
-                oldToken, newToken));
-        return requestRefreshConfiguration;
-    }
-
-    @Override
-    public boolean requestPointerCapture(IBinder windowToken, boolean enabled) {
-        final IWindow focusedWindow = mFocusedWindow.get();
-        if (focusedWindow == null || focusedWindow.asBinder() != windowToken) {
-            Slog.e(TAG, "requestPointerCapture called for a window that has no focus: "
-                    + windowToken);
-            return false;
-        }
-        if (mFocusedWindowHasCapture == enabled) {
-            Slog.i(TAG, "requestPointerCapture: already " + (enabled ? "enabled" : "disabled"));
-            return false;
-        }
-        return dispatchPointerCaptureChanged(focusedWindow, enabled);
-    }
-
-    private boolean dispatchPointerCaptureChanged(IWindow focusedWindow, boolean enabled) {
-        if (mFocusedWindowHasCapture != enabled) {
-            mFocusedWindowHasCapture = enabled;
-            try {
-                focusedWindow.dispatchPointerCaptureChanged(enabled);
-            } catch (RemoteException ex) {
-                /* ignore */
-            }
-            return true;
-        }
-        return false;
+    public void notifyFocusChanged(IBinder oldToken, IBinder newToken) {
+        mService.mH.sendMessage(PooledLambda.obtainMessage(
+                mService::reportFocusChanged, oldToken, newToken));
     }
 
     /** Waits until the built-in input devices have been configured. */
diff --git a/services/core/java/com/android/server/wm/RecentsAnimation.java b/services/core/java/com/android/server/wm/RecentsAnimation.java
index 05dcd36..5bcb287 100644
--- a/services/core/java/com/android/server/wm/RecentsAnimation.java
+++ b/services/core/java/com/android/server/wm/RecentsAnimation.java
@@ -413,9 +413,10 @@
 
     @Override
     public void onRootTaskOrderChanged(Task rootTask) {
-        ProtoLog.d(WM_DEBUG_RECENTS_ANIMATIONS, "onStackOrderChanged(): stack=%s", rootTask);
-        if (mDefaultTaskDisplayArea.getIndexOf(rootTask) == -1 || !rootTask.shouldBeVisible(null)) {
-            // The stack is not visible, so ignore this change
+        ProtoLog.d(WM_DEBUG_RECENTS_ANIMATIONS, "onRootTaskOrderChanged(): rootTask=%s", rootTask);
+        if (mDefaultTaskDisplayArea.getRootTask(t -> t == rootTask) == null
+                || !rootTask.shouldBeVisible(null)) {
+            // The root task is not visible, so ignore this change
             return;
         }
         final RecentsAnimationController controller =
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index 8ca49eb..d926a36 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -1013,7 +1013,7 @@
         mWmService.scheduleAnimationLocked();
 
         // Send any pending task-info changes that were queued-up during a layout deferment
-        mWmService.mAtmService.mTaskOrganizerController.dispatchPendingEvents();
+        mWmService.mAtmService.mTaskOrganizerController.dispatchPendingTaskInfoChanges();
 
         if (DEBUG_WINDOW_TRACE) Slog.e(TAG, "performSurfacePlacementInner exit");
     }
@@ -1828,19 +1828,19 @@
     }
 
     /**
-     * @return a list of activities which are the top ones in each visible stack. The first
+     * @return a list of activities which are the top ones in each visible root task. The first
      * entry will be the focused activity.
      */
     List<IBinder> getTopVisibleActivities() {
         final ArrayList<IBinder> topActivityTokens = new ArrayList<>();
-        final Task topFocusedStack = getTopDisplayFocusedRootTask();
+        final Task topFocusedRootTask = getTopDisplayFocusedRootTask();
         // Traverse all displays.
-        forAllRootTasks(stack -> {
-            // Get top activity from a visible stack and add it to the list.
-            if (stack.shouldBeVisible(null /* starting */)) {
-                final ActivityRecord top = stack.getTopNonFinishingActivity();
+        forAllRootTasks(rootTask -> {
+            // Get top activity from a visible root task and add it to the list.
+            if (rootTask.shouldBeVisible(null /* starting */)) {
+                final ActivityRecord top = rootTask.getTopNonFinishingActivity();
                 if (top != null) {
-                    if (stack == topFocusedStack) {
+                    if (rootTask == topFocusedRootTask) {
                         topActivityTokens.add(0, top.appToken);
                     } else {
                         topActivityTokens.add(top.appToken);
@@ -1854,9 +1854,9 @@
     @Nullable
     Task getTopDisplayFocusedRootTask() {
         for (int i = getChildCount() - 1; i >= 0; --i) {
-            final Task focusedStack = getChildAt(i).getFocusedRootTask();
-            if (focusedStack != null) {
-                return focusedStack;
+            final Task focusedRootTask = getChildAt(i).getFocusedRootTask();
+            if (focusedRootTask != null) {
+                return focusedRootTask;
             }
         }
         return null;
@@ -1864,15 +1864,15 @@
 
     @Nullable
     ActivityRecord getTopResumedActivity() {
-        final Task focusedStack = getTopDisplayFocusedRootTask();
-        if (focusedStack == null) {
+        final Task focusedRootTask = getTopDisplayFocusedRootTask();
+        if (focusedRootTask == null) {
             return null;
         }
-        final ActivityRecord resumedActivity = focusedStack.getResumedActivity();
+        final ActivityRecord resumedActivity = focusedRootTask.getResumedActivity();
         if (resumedActivity != null && resumedActivity.app != null) {
             return resumedActivity;
         }
-        // The top focused stack might not have a resumed activity yet - look on all displays in
+        // The top focused root task might not have a resumed activity yet - look on all displays in
         // focus order.
         return getItemFromTaskDisplayAreas(TaskDisplayArea::getFocusedActivity);
     }
@@ -1997,36 +1997,36 @@
     }
 
     boolean switchUser(int userId, UserState uss) {
-        final Task topFocusedStack = getTopDisplayFocusedRootTask();
-        final int focusStackId = topFocusedStack != null
-                ? topFocusedStack.getRootTaskId() : INVALID_TASK_ID;
-        // We dismiss the docked stack whenever we switch users.
+        final Task topFocusedRootTask = getTopDisplayFocusedRootTask();
+        final int focusRootTaskId = topFocusedRootTask != null
+                ? topFocusedRootTask.getRootTaskId() : INVALID_TASK_ID;
+        // We dismiss the docked root task whenever we switch users.
         if (getDefaultTaskDisplayArea().isSplitScreenModeActivated()) {
             getDefaultTaskDisplayArea().onSplitScreenModeDismissed();
         }
-        // Also dismiss the pinned stack whenever we switch users. Removing the pinned stack will
-        // also cause all tasks to be moved to the fullscreen stack at a position that is
+        // Also dismiss the pinned root task whenever we switch users. Removing the pinned root task
+        // will also cause all tasks to be moved to the fullscreen root task at a position that is
         // appropriate.
         removeRootTasksInWindowingModes(WINDOWING_MODE_PINNED);
 
-        mUserRootTaskInFront.put(mCurrentUser, focusStackId);
+        mUserRootTaskInFront.put(mCurrentUser, focusRootTaskId);
         mCurrentUser = userId;
 
         mTaskSupervisor.mStartingUsers.add(uss);
-        forAllRootTasks(stack -> {
-            stack.switchUser(userId);
+        forAllRootTasks(rootTask -> {
+            rootTask.switchUser(userId);
         });
 
-        final int restoreStackId = mUserRootTaskInFront.get(userId);
-        Task stack = getRootTask(restoreStackId);
-        if (stack == null) {
-            stack = getDefaultTaskDisplayArea().getOrCreateRootHomeTask();
+        final int restoreRootTaskId = mUserRootTaskInFront.get(userId);
+        Task rootTask = getRootTask(restoreRootTaskId);
+        if (rootTask == null) {
+            rootTask = getDefaultTaskDisplayArea().getOrCreateRootHomeTask();
         }
-        final boolean homeInFront = stack.isActivityTypeHome();
-        if (stack.isOnHomeDisplay()) {
-            stack.moveToFront("switchUserOnHomeDisplay");
+        final boolean homeInFront = rootTask.isActivityTypeHome();
+        if (rootTask.isOnHomeDisplay()) {
+            rootTask.moveToFront("switchUserOnHomeDisplay");
         } else {
-            // Stack was moved to another display while user was swapped out.
+            // Root task was moved to another display while user was swapped out.
             resumeHomeActivity(null, "switchUserOnOtherDisplay", getDefaultTaskDisplayArea());
         }
         return homeInFront;
@@ -2350,7 +2350,7 @@
         return result;
     }
 
-    void applySleepTokens(boolean applyToStacks) {
+    void applySleepTokens(boolean applyToRootTasks) {
         for (int displayNdx = getChildCount() - 1; displayNdx >= 0; --displayNdx) {
             // Set the sleeping state of the display.
             final DisplayContent display = getChildAt(displayNdx);
@@ -2360,17 +2360,17 @@
             }
             display.setIsSleeping(displayShouldSleep);
 
-            if (!applyToStacks) {
+            if (!applyToRootTasks) {
                 continue;
             }
 
-            // Set the sleeping state of the stacks on the display.
-            display.forAllRootTasks(stack -> {
+            // Set the sleeping state of the root tasks on the display.
+            display.forAllRootTasks(rootTask -> {
                 if (displayShouldSleep) {
-                    stack.goToSleepIfPossible(false /* shuttingDown */);
+                    rootTask.goToSleepIfPossible(false /* shuttingDown */);
                 } else {
-                    stack.awakeFromSleepingLocked();
-                    if (stack.isFocusedStackOnDisplay()
+                    rootTask.awakeFromSleepingLocked();
+                    if (rootTask.isFocusedStackOnDisplay()
                             && !mTaskSupervisor.getKeyguardController()
                             .isKeyguardOrAodShowing(display.mDisplayId)) {
                         // If the keyguard is unlocked - resume immediately.
@@ -2378,13 +2378,13 @@
                         // process the keyguard going away, which can happen before the sleep
                         // token is released. As a result, it is important we resume the
                         // activity here.
-                        stack.resumeTopActivityUncheckedLocked(null, null);
+                        rootTask.resumeTopActivityUncheckedLocked(null, null);
                     }
                     // The visibility update must not be called before resuming the top, so the
                     // display orientation can be updated first if needed. Otherwise there may
                     // have redundant configuration changes due to apply outdated display
                     // orientation (from keyguard) to activity.
-                    stack.ensureActivitiesVisible(null /* starting */, 0 /* configChanges */,
+                    rootTask.ensureActivitiesVisible(null /* starting */, 0 /* configChanges */,
                             false /* preserveWindows */);
                 }
             });
@@ -2427,7 +2427,7 @@
         task.fillTaskInfo(info);
 
         // A task might be not attached to a display.
-        info.position = taskDisplayArea != null ? taskDisplayArea.getIndexOf(task) : 0;
+        info.position = taskDisplayArea != null ? taskDisplayArea.getTaskIndexOf(task) : 0;
         info.visible = task.shouldBeVisible(null);
         task.getBounds(info.bounds);
 
@@ -2471,21 +2471,21 @@
     }
 
     RootTaskInfo getRootTaskInfo(int windowingMode, int activityType) {
-        final Task stack = getRootTask(windowingMode, activityType);
-        return (stack != null) ? getRootTaskInfo(stack) : null;
+        final Task rootTask = getRootTask(windowingMode, activityType);
+        return (rootTask != null) ? getRootTaskInfo(rootTask) : null;
     }
 
     RootTaskInfo getRootTaskInfo(int windowingMode, int activityType, int displayId) {
-        final Task stack = getRootTask(windowingMode, activityType, displayId);
-        return (stack != null) ? getRootTaskInfo(stack) : null;
+        final Task rootTask = getRootTask(windowingMode, activityType, displayId);
+        return (rootTask != null) ? getRootTaskInfo(rootTask) : null;
     }
 
     /** If displayId == INVALID_DISPLAY, this will get root task infos on all displays */
     ArrayList<RootTaskInfo> getAllRootTaskInfos(int displayId) {
         final ArrayList<RootTaskInfo> list = new ArrayList<>();
         if (displayId == INVALID_DISPLAY) {
-            forAllRootTasks(stack -> {
-                list.add(getRootTaskInfo(stack));
+            forAllRootTasks(rootTask -> {
+                list.add(getRootTaskInfo(rootTask));
             });
             return list;
         }
@@ -2493,8 +2493,8 @@
         if (display == null) {
             return list;
         }
-        display.forAllRootTasks(stack -> {
-            list.add(getRootTaskInfo(stack));
+        display.forAllRootTasks(rootTask -> {
+            list.add(getRootTaskInfo(rootTask));
         });
         return list;
     }
@@ -2955,8 +2955,8 @@
         }
 
         // If {@code r} is already in target display area and its task is the same as the candidate
-        // task, the intention should be getting a launch stack for the reusable activity, so we can
-        // use the existing stack.
+        // task, the intention should be getting a launch root task for the reusable activity, so we
+        // can use the existing root task.
         if (candidateTask != null) {
             final TaskDisplayArea attachedTaskDisplayArea = candidateTask.getDisplayArea();
             if (attachedTaskDisplayArea == null || attachedTaskDisplayArea == taskDisplayArea) {
@@ -2965,9 +2965,9 @@
             // Or the candidate task is already a root task that can be reused by reparenting
             // it to the target display.
             if (candidateTask.isRootTask()) {
-                final Task stack = candidateTask.getRootTask();
-                stack.reparent(taskDisplayArea, true /* onTop */);
-                return stack;
+                final Task rootTask = candidateTask.getRootTask();
+                rootTask.reparent(taskDisplayArea, true /* onTop */);
+                return rootTask;
             }
         }
 
@@ -2984,16 +2984,16 @@
         windowingMode = taskDisplayArea.validateWindowingMode(windowingMode, r, candidateTask,
                 r.getActivityType());
 
-        // Return the topmost valid stack on the display.
+        // Return the topmost valid root task on the display.
         final int targetWindowingMode = windowingMode;
-        final Task topmostValidStack = taskDisplayArea.getRootTask(stack ->
-                isValidLaunchRootTask(stack, r, targetWindowingMode));
-        if (topmostValidStack != null) {
-            return topmostValidStack;
+        final Task topmostValidRootTask = taskDisplayArea.getRootTask(rootTask ->
+                isValidLaunchRootTask(rootTask, r, targetWindowingMode));
+        if (topmostValidRootTask != null) {
+            return topmostValidRootTask;
         }
 
-        // If there is no valid stack on the secondary display area - check if new dynamic stack
-        // will do.
+        // If there is no valid root task on the secondary display area - check if new dynamic root
+        // task will do.
         if (taskDisplayArea != getDisplayContent(taskDisplayArea.getDisplayId())
                 .getDefaultTaskDisplayArea()) {
             final int activityType =
@@ -3224,8 +3224,8 @@
     }
 
     void finishVoiceTask(IVoiceInteractionSession session) {
-        forAllRootTasks(stack -> {
-            stack.finishVoiceTask(session);
+        forAllRootTasks(rootTask -> {
+            rootTask.finishVoiceTask(session);
         });
     }
 
@@ -3284,8 +3284,8 @@
 
     boolean allResumedActivitiesVisible() {
         boolean[] foundResumed = {false};
-        final boolean foundInvisibleResumedActivity = forAllRootTasks(stack -> {
-            final ActivityRecord r = stack.getResumedActivity();
+        final boolean foundInvisibleResumedActivity = forAllRootTasks(rootTask -> {
+            final ActivityRecord r = rootTask.getResumedActivity();
             if (r != null) {
                 if (!r.nowVisible) {
                     return true;
@@ -3529,9 +3529,9 @@
             }
         } else {
             final ArrayList<ActivityRecord> activities = new ArrayList<>();
-            forAllRootTasks(stack -> {
-                if (!dumpVisibleStacksOnly || stack.shouldBeVisible(null)) {
-                    activities.addAll(stack.getDumpActivitiesLocked(name));
+            forAllRootTasks(rootTask -> {
+                if (!dumpVisibleStacksOnly || rootTask.shouldBeVisible(null)) {
+                    activities.addAll(rootTask.getDumpActivitiesLocked(name));
                 }
             });
             return activities;
@@ -3581,11 +3581,11 @@
             pw.print("Display #");
             pw.print(displayContent.mDisplayId);
             pw.println(" (activities from top to bottom):");
-            displayContent.forAllRootTasks(stack -> {
+            displayContent.forAllRootTasks(rootTask -> {
                 if (needSep[0]) {
                     pw.println();
                 }
-                needSep[0] = stack.dump(fd, pw, dumpAll, dumpClient, dumpPackage, false);
+                needSep[0] = rootTask.dump(fd, pw, dumpAll, dumpClient, dumpPackage, false);
                 printed[0] |= needSep[0];
             });
             displayContent.forAllTaskDisplayAreas(taskDisplayArea -> {
diff --git a/services/core/java/com/android/server/wm/SnapshotStartingData.java b/services/core/java/com/android/server/wm/SnapshotStartingData.java
index 6ad3f15..2124ed6 100644
--- a/services/core/java/com/android/server/wm/SnapshotStartingData.java
+++ b/services/core/java/com/android/server/wm/SnapshotStartingData.java
@@ -28,14 +28,15 @@
     private final WindowManagerService mService;
     private final TaskSnapshot mSnapshot;
 
-    SnapshotStartingData(WindowManagerService service, TaskSnapshot snapshot) {
-        super(service);
+    SnapshotStartingData(WindowManagerService service, TaskSnapshot snapshot, int typeParams) {
+        super(service, typeParams);
         mService = service;
         mSnapshot = snapshot;
     }
 
     @Override
     StartingSurface createStartingSurface(ActivityRecord activity) {
-        return mService.mTaskSnapshotController.createStartingSurface(activity, mSnapshot);
+        return mService.mStartingSurfaceController.createTaskSnapshotSurface(activity,
+                mSnapshot);
     }
 }
diff --git a/services/core/java/com/android/server/wm/SplashScreenStartingData.java b/services/core/java/com/android/server/wm/SplashScreenStartingData.java
index 50a101d..185a317 100644
--- a/services/core/java/com/android/server/wm/SplashScreenStartingData.java
+++ b/services/core/java/com/android/server/wm/SplashScreenStartingData.java
@@ -38,8 +38,8 @@
 
     SplashScreenStartingData(WindowManagerService service, String pkg, int theme,
             CompatibilityInfo compatInfo, CharSequence nonLocalizedLabel, int labelRes, int icon,
-            int logo, int windowFlags, Configuration mergedOverrideConfiguration) {
-        super(service);
+            int logo, int windowFlags, Configuration mergedOverrideConfiguration, int typeParams) {
+        super(service, typeParams);
         mPkg = pkg;
         mTheme = theme;
         mCompatInfo = compatInfo;
diff --git a/services/core/java/com/android/server/wm/StartingData.java b/services/core/java/com/android/server/wm/StartingData.java
index 2e6e777..a5bd797 100644
--- a/services/core/java/com/android/server/wm/StartingData.java
+++ b/services/core/java/com/android/server/wm/StartingData.java
@@ -24,9 +24,11 @@
 public abstract class StartingData {
 
     protected final WindowManagerService mService;
+    protected final int mTypeParams;
 
-    protected StartingData(WindowManagerService service) {
+    protected StartingData(WindowManagerService service, int typeParams) {
         mService = service;
+        mTypeParams = typeParams;
     }
 
     /**
diff --git a/services/core/java/com/android/server/wm/StartingSurfaceController.java b/services/core/java/com/android/server/wm/StartingSurfaceController.java
index 6d7ddf6..94e14dd 100644
--- a/services/core/java/com/android/server/wm/StartingSurfaceController.java
+++ b/services/core/java/com/android/server/wm/StartingSurfaceController.java
@@ -16,9 +16,20 @@
 
 package com.android.server.wm;
 
+import static android.window.StartingWindowInfo.TYPE_PARAMETER_ACTIVITY_CREATED;
+import static android.window.StartingWindowInfo.TYPE_PARAMETER_ALLOW_TASK_SNAPSHOT;
+import static android.window.StartingWindowInfo.TYPE_PARAMETER_NEW_TASK;
+import static android.window.StartingWindowInfo.TYPE_PARAMETER_PROCESS_RUNNING;
+import static android.window.StartingWindowInfo.TYPE_PARAMETER_TASK_SWITCH;
+
+import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
+import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
+
 import android.content.res.CompatibilityInfo;
 import android.content.res.Configuration;
 import android.os.SystemProperties;
+import android.util.Slog;
+import android.window.TaskSnapshot;
 
 import com.android.server.policy.WindowManagerPolicy.StartingSurface;
 
@@ -26,7 +37,8 @@
  * Managing to create and release a starting window surface.
  */
 public class StartingSurfaceController {
-
+    private static final String TAG = TAG_WITH_CLASS_NAME
+            ? StartingSurfaceController.class.getSimpleName() : TAG_WM;
     /** Set to {@code true} to enable shell starting surface drawer. */
     private static final boolean DEBUG_ENABLE_SHELL_DRAWER =
             SystemProperties.getBoolean("persist.debug.shell_starting_surface", false);
@@ -49,15 +61,79 @@
         final Task task = activity.getTask();
         if (task != null && mService.mAtmService.mTaskOrganizerController.addStartingWindow(task,
                 activity.token)) {
-            return new SplashScreenContainerSurface(task);
+            return new ShellStartingSurface(task);
         }
         return null;
     }
 
-    private final class SplashScreenContainerSurface implements StartingSurface {
+    int makeStartingWindowTypeParameter(boolean newTask, boolean taskSwitch,
+            boolean processRunning, boolean allowTaskSnapshot, boolean activityCreated) {
+        int parameter = 0;
+        if (newTask) {
+            parameter |= TYPE_PARAMETER_NEW_TASK;
+        }
+        if (taskSwitch) {
+            parameter |= TYPE_PARAMETER_TASK_SWITCH;
+        }
+        if (processRunning) {
+            parameter |= TYPE_PARAMETER_PROCESS_RUNNING;
+        }
+        if (allowTaskSnapshot) {
+            parameter |= TYPE_PARAMETER_ALLOW_TASK_SNAPSHOT;
+        }
+        if (activityCreated) {
+            parameter |= TYPE_PARAMETER_ACTIVITY_CREATED;
+        }
+        return parameter;
+    }
+
+    StartingSurface createTaskSnapshotSurface(ActivityRecord activity, TaskSnapshot taskSnapshot) {
+        final WindowState topFullscreenOpaqueWindow;
+        final Task task;
+        synchronized (mService.mGlobalLock) {
+            final WindowState mainWindow = activity.findMainWindow();
+            task = activity.getTask();
+            if (task == null) {
+                Slog.w(TAG, "TaskSnapshotSurface.create: Failed to find task for activity="
+                        + activity);
+                return null;
+            }
+            final ActivityRecord topFullscreenActivity =
+                    activity.getTask().getTopFullscreenActivity();
+            if (topFullscreenActivity == null) {
+                Slog.w(TAG, "TaskSnapshotSurface.create: Failed to find top fullscreen for task="
+                        + task);
+                return null;
+            }
+            topFullscreenOpaqueWindow = topFullscreenActivity.getTopFullscreenOpaqueWindow();
+            if (mainWindow == null || topFullscreenOpaqueWindow == null) {
+                Slog.w(TAG, "TaskSnapshotSurface.create: Failed to find main window for activity="
+                        + activity);
+                return null;
+            }
+            if (topFullscreenActivity.getWindowConfiguration().getRotation()
+                    != taskSnapshot.getRotation()) {
+                // The snapshot should have been checked by ActivityRecord#isSnapshotCompatible
+                // that the activity will be updated to the same rotation as the snapshot. Since
+                // the transition is not started yet, fixed rotation transform needs to be applied
+                // earlier to make the snapshot show in a rotated container.
+                activity.mDisplayContent.handleTopActivityLaunchingInDifferentOrientation(
+                        topFullscreenActivity, false /* checkOpening */);
+            }
+        }
+        if (!DEBUG_ENABLE_SHELL_DRAWER) {
+            return mService.mTaskSnapshotController
+                    .createStartingSurface(activity, taskSnapshot);
+        }
+        mService.mAtmService.mTaskOrganizerController.addStartingWindow(task, activity.token);
+        return new ShellStartingSurface(task);
+    }
+
+
+    private final class ShellStartingSurface implements StartingSurface {
         private final Task mTask;
 
-        SplashScreenContainerSurface(Task task) {
+        ShellStartingSurface(Task task) {
             mTask = task;
         }
 
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index abd51ee..79a32e4 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -156,7 +156,6 @@
 import android.app.Activity;
 import android.app.ActivityManager;
 import android.app.ActivityManager.TaskDescription;
-import android.window.TaskSnapshot;
 import android.app.ActivityOptions;
 import android.app.ActivityTaskManager;
 import android.app.AppGlobals;
@@ -207,6 +206,8 @@
 import android.view.WindowManager;
 import android.view.WindowManager.TransitionOldType;
 import android.window.ITaskOrganizer;
+import android.window.StartingWindowInfo;
+import android.window.TaskSnapshot;
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
@@ -4145,6 +4146,34 @@
         return info;
     }
 
+    StartingWindowInfo getStartingWindowInfo() {
+        final StartingWindowInfo info = new StartingWindowInfo();
+        info.taskInfo = getTaskInfo();
+
+        final ActivityRecord topActivity = getTopMostActivity();
+        if (topActivity != null) {
+            info.startingWindowTypeParameter =
+                    topActivity.mStartingData != null
+                            ? topActivity.mStartingData.mTypeParams
+                            : 0;
+            final WindowState mainWindow = topActivity.findMainWindow();
+            if (mainWindow != null) {
+                info.mainWindowLayoutParams = mainWindow.getAttrs();
+            }
+        }
+        final ActivityRecord topFullscreenActivity = getTopFullscreenActivity();
+        if (topFullscreenActivity != null) {
+            final WindowState topFullscreenOpaqueWindow =
+                    topFullscreenActivity.getTopFullscreenOpaqueWindow();
+            if (topFullscreenOpaqueWindow != null) {
+                info.topOpaqueWindowInsetsState =
+                        topFullscreenOpaqueWindow.getInsetsStateWithVisibilityOverride();
+                info.topOpaqueWindowLayoutParams = topFullscreenOpaqueWindow.getAttrs();
+            }
+        }
+        return info;
+    }
+
     boolean isTaskId(int taskId) {
         return mTaskId == taskId;
     }
@@ -4955,6 +4984,7 @@
             }
         } else {
             // No longer managed by any organizer.
+            mTaskAppearedSent = false;
             setForceHidden(FLAG_FORCE_HIDDEN_FOR_TASK_ORG, false /* set */);
             if (mCreatedByOrganizer) {
                 removeImmediately();
@@ -4979,6 +5009,11 @@
      * @return {@code true} if task organizer changed.
      */
     boolean updateTaskOrganizerState(boolean forceUpdate, boolean skipTaskAppeared) {
+        if (getSurfaceControl() == null) {
+            // Can't call onTaskAppeared without a surfacecontrol, so defer this until after one
+            // is created.
+            return false;
+        }
         if (!canBeOrganized()) {
             return setTaskOrganizer(null);
         }
@@ -4988,10 +5023,6 @@
         final ITaskOrganizer organizer = controller.getTaskOrganizer(windowingMode);
         if (!forceUpdate && mTaskOrganizer == organizer) {
             return false;
-        } else if (organizer != null && getSurfaceControl() == null) {
-            // Can't call onTaskAppeared without a surfacecontrol, so defer this until after one
-            // is created.
-            return false;
         }
         return setTaskOrganizer(organizer, skipTaskAppeared);
     }
@@ -5318,20 +5349,19 @@
         final TaskDisplayArea taskDisplayArea = getDisplayArea();
 
         if (inSplitScreenSecondaryWindowingMode()) {
-            // If the stack is in split-screen secondary mode, we need to make sure we move the
-            // primary split-screen stack forward in the case it is currently behind a fullscreen
-            // stack so both halves of the split-screen appear on-top and the fullscreen stack isn't
-            // cutting between them.
+            // If the root task is in split-screen secondary mode, we need to make sure we move the
+            // primary split-screen root task forward in the case it is currently behind a
+            // fullscreen root task so both halves of the split-screen appear on-top and the
+            // fullscreen root task isn't cutting between them.
             // TODO(b/70677280): This is a workaround until we can fix as part of b/70677280.
-            final Task topFullScreenStack =
+            final Task topFullScreenRootTask =
                     taskDisplayArea.getTopRootTaskInWindowingMode(WINDOWING_MODE_FULLSCREEN);
-            if (topFullScreenStack != null) {
-                final Task primarySplitScreenStack =
+            if (topFullScreenRootTask != null) {
+                final Task primarySplitScreenRootTask =
                         taskDisplayArea.getRootSplitScreenPrimaryTask();
-                if (primarySplitScreenStack != null
-                        && taskDisplayArea.getIndexOf(topFullScreenStack)
-                        > taskDisplayArea.getIndexOf(primarySplitScreenStack)) {
-                    primarySplitScreenStack.moveToFront(reason + " splitScreenToTop");
+                if (primarySplitScreenRootTask != null
+                        && topFullScreenRootTask.compareTo(primarySplitScreenRootTask) > 0) {
+                    primarySplitScreenRootTask.moveToFront(reason + " splitScreenToTop");
                 }
             }
         }
@@ -5746,7 +5776,7 @@
     }
 
     /**
-     * @return {@code true} if this is the focused stack on its current display, {@code false}
+     * @return {@code true} if this is the focused root task on its current display, {@code false}
      * otherwise.
      */
     boolean isFocusedStackOnDisplay() {
@@ -6698,18 +6728,21 @@
         });
     }
 
-    /** @return true if the stack behind this one is a standard activity type. */
-    private boolean inFrontOfStandardStack() {
+    /** @return true if the root task behind this one is a standard activity type. */
+    private boolean inFrontOfStandardRootTask() {
         final TaskDisplayArea taskDisplayArea = getDisplayArea();
         if (taskDisplayArea == null) {
             return false;
         }
-        final int index = taskDisplayArea.getIndexOf(this);
+        final int index = taskDisplayArea.getTaskIndexOf(this);
         if (index == 0) {
             return false;
         }
-        final Task stackBehind = taskDisplayArea.getChildAt(index - 1);
-        return stackBehind.isActivityTypeStandard();
+        final int[] indexCount = new int[1];
+        final Task rootTaskBehind = taskDisplayArea.getRootTask(
+                // From bottom to top, find the one behind this Task.
+                task -> ++indexCount[0] == index, false /* traverseTopToBottom */);
+        return rootTaskBehind.isActivityTypeStandard();
     }
 
     boolean shouldUpRecreateTaskLocked(ActivityRecord srec, String destAffinity) {
@@ -6730,7 +6763,7 @@
         if (srec.isRootOfTask() && task.getBaseIntent() != null
                 && task.getBaseIntent().isDocument()) {
             // Okay, this activity is at the root of its task.  What to do, what to do...
-            if (!inFrontOfStandardStack()) {
+            if (!inFrontOfStandardRootTask()) {
                 // Finishing won't return to an application, so we need to recreate.
                 return true;
             }
@@ -7631,7 +7664,7 @@
 
     void dispatchTaskInfoChangedIfNeeded(boolean force) {
         if (isOrganized()) {
-            mAtmService.mTaskOrganizerController.onTaskInfoChanged(this, force);
+            mAtmService.mTaskOrganizerController.dispatchTaskInfoChanged(this, force);
         }
     }
 
diff --git a/services/core/java/com/android/server/wm/TaskDisplayArea.java b/services/core/java/com/android/server/wm/TaskDisplayArea.java
index 7fed840..866abbd 100644
--- a/services/core/java/com/android/server/wm/TaskDisplayArea.java
+++ b/services/core/java/com/android/server/wm/TaskDisplayArea.java
@@ -71,8 +71,10 @@
 
 /**
  * {@link DisplayArea} that represents a section of a screen that contains app window containers.
+ *
+ * The children can be either {@link Task} or {@link TaskDisplayArea}.
  */
-final class TaskDisplayArea extends DisplayArea<Task> {
+final class TaskDisplayArea extends DisplayArea<WindowContainer> {
 
     DisplayContent mDisplayContent;
 
@@ -106,9 +108,9 @@
     // TODO(b/159029784): Remove when getStack() behavior is cleaned-up
     private Task mRootRecentsTask;
 
-    private final ArrayList<Task> mTmpAlwaysOnTopRootTasks = new ArrayList<>();
-    private final ArrayList<Task> mTmpNormalRootTasks = new ArrayList<>();
-    private final ArrayList<Task> mTmpHomeRootTasks = new ArrayList<>();
+    private final ArrayList<WindowContainer> mTmpAlwaysOnTopChildren = new ArrayList<>();
+    private final ArrayList<WindowContainer> mTmpNormalChildren = new ArrayList<>();
+    private final ArrayList<WindowContainer> mTmpHomeChildren = new ArrayList<>();
     private final IntArray mTmpNeedsZBoostIndexes = new IntArray();
     private int mTmpLayerForSplitScreenDividerAnchor;
     private int mTmpLayerForAnimationLayer;
@@ -179,9 +181,10 @@
     }
 
     /**
-     * Returns the topmost stack on the display that is compatible with the input windowing mode
-     * and activity type. Null is no compatible stack on the display.
+     * Returns the topmost root task on the display that is compatible with the input windowing mode
+     * and activity type. Null is no compatible root task on the display.
      */
+    @Nullable
     Task getRootTask(int windowingMode, int activityType) {
         if (activityType == ACTIVITY_TYPE_HOME) {
             return mRootHomeTask;
@@ -193,30 +196,48 @@
         } else if (windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) {
             return mRootSplitScreenPrimaryTask;
         }
-        for (int i = getChildCount() - 1; i >= 0; --i) {
-            final Task stack = getChildAt(i);
+        return getRootTask(rootTask -> {
             if (activityType == ACTIVITY_TYPE_UNDEFINED
-                    && windowingMode == stack.getWindowingMode()) {
-                // Passing in undefined type means we want to match the topmost stack with the
+                    && windowingMode == rootTask.getWindowingMode()) {
+                // Passing in undefined type means we want to match the topmost root task with the
                 // windowing mode.
-                return stack;
+                return true;
             }
-            if (stack.isCompatible(windowingMode, activityType)) {
-                return stack;
-            }
-        }
-        return null;
+            return rootTask.isCompatible(windowingMode, activityType);
+        });
     }
 
     @VisibleForTesting
     Task getTopRootTask() {
-        final int count = getChildCount();
-        return count > 0 ? getChildAt(count - 1) : null;
+        return getRootTask(t -> true);
     }
 
-    // TODO: Figure-out a way to remove since it might be a source of confusion.
-    int getIndexOf(Task task) {
-        return mChildren.indexOf(task);
+    // TODO(b/175832855): Figure-out a way to remove since it might be a source of confusion.
+    /**
+     * Gets the order of the given {@link Task} as its z-order in the hierarchy below this TDA.
+     * The Task can be a direct child of a child TaskDisplayArea. {@code -1} if not found.
+     */
+    int getTaskIndexOf(Task task) {
+        int index = 0;
+        final int childCount = getChildCount();
+        for (int i = 0; i < childCount; i++) {
+            final WindowContainer wc = getChildAt(i);
+            if (wc.asTask() != null) {
+                if (wc.asTask() == task) {
+                    return index;
+                }
+                index++;
+            } else {
+                final TaskDisplayArea tda = wc.asTaskDisplayArea();
+                final int subIndex = tda.getTaskIndexOf(task);
+                if (subIndex > -1) {
+                    return index + subIndex;
+                } else {
+                    index += tda.getRootTaskCount();
+                }
+            }
+        }
+        return -1;
     }
 
     @Nullable
@@ -238,9 +259,11 @@
     }
 
     Task getRootSplitScreenSecondaryTask() {
+        // Only check the direct child Task for now, since the primary is also a direct child Task.
         for (int i = mChildren.size() - 1; i >= 0; --i) {
-            if (mChildren.get(i).inSplitScreenSecondaryWindowingMode()) {
-                return mChildren.get(i);
+            final Task task = mChildren.get(i).asTask();
+            if (task != null && task.inSplitScreenSecondaryWindowingMode()) {
+                return task;
             }
         }
         return null;
@@ -323,7 +346,22 @@
     }
 
     @Override
-    void addChild(Task task, int position) {
+    void addChild(WindowContainer child, int position) {
+        if (child.asTaskDisplayArea() != null) {
+            if (DEBUG_ROOT_TASK) {
+                Slog.d(TAG_WM, "Set TaskDisplayArea=" + child + " on taskDisplayArea=" + this);
+            }
+            super.addChild(child, position);
+        } else if (child.asTask() != null) {
+            addChildTask(child.asTask(), position);
+        } else {
+            throw new IllegalArgumentException(
+                    "TaskDisplayArea can only add Task and TaskDisplayArea, but found "
+                            + child);
+        }
+    }
+
+    private void addChildTask(Task task, int position) {
         if (DEBUG_ROOT_TASK) Slog.d(TAG_WM, "Set task=" + task + " on taskDisplayArea=" + this);
 
         addRootTaskReferenceIfNeeded(task);
@@ -335,11 +373,23 @@
     }
 
     @Override
-    protected void removeChild(Task stack) {
-        super.removeChild(stack);
-        onRootTaskRemoved(stack);
+    protected void removeChild(WindowContainer child) {
+        if (child.asTaskDisplayArea() != null) {
+            super.removeChild(child);
+        } else if (child.asTask() != null) {
+            removeChildTask(child.asTask());
+        } else {
+            throw new IllegalArgumentException(
+                    "TaskDisplayArea can only remove Task and TaskDisplayArea, but found "
+                            + child);
+        }
+    }
+
+    private void removeChildTask(Task task) {
+        super.removeChild(task);
+        onRootTaskRemoved(task);
         mAtmService.updateSleepIfNeededLocked();
-        removeRootTaskReferenceIfNeeded(stack);
+        removeRootTaskReferenceIfNeeded(task);
     }
 
     @Override
@@ -349,21 +399,33 @@
     }
 
     @Override
-    void positionChildAt(int position, Task child, boolean includingParents) {
+    void positionChildAt(int position, WindowContainer child, boolean includingParents) {
+        if (child.asTaskDisplayArea() != null) {
+            super.positionChildAt(position, child, includingParents);
+        } else if (child.asTask() != null) {
+            positionChildTaskAt(position, child.asTask(), includingParents);
+        } else {
+            throw new IllegalArgumentException(
+                    "TaskDisplayArea can only position Task and TaskDisplayArea, but found "
+                            + child);
+        }
+    }
+
+    private void positionChildTaskAt(int position, Task child, boolean includingParents) {
         final boolean moveToTop = position >= getChildCount() - 1;
         final boolean moveToBottom = position <= 0;
 
         final int oldPosition = mChildren.indexOf(child);
         if (child.getWindowConfiguration().isAlwaysOnTop() && !moveToTop) {
-            // This stack is always-on-top, override the default behavior.
-            Slog.w(TAG_WM, "Ignoring move of always-on-top stack=" + this + " to bottom");
+            // This root task is always-on-top, override the default behavior.
+            Slog.w(TAG_WM, "Ignoring move of always-on-top root task=" + this + " to bottom");
 
             // Moving to its current position, as we must call super but we don't want to
             // perform any meaningful action.
             super.positionChildAt(oldPosition, child, false /* includingParents */);
             return;
         }
-        // We don't allow untrusted display to top when task stack moves to top,
+        // We don't allow untrusted display to top when root task moves to top,
         // until user tapping this display to change display position as top intentionally.
         if (!mDisplayContent.isTrusted() && !getParent().isOnTop()) {
             includingParents = false;
@@ -432,41 +494,78 @@
     @Override
     boolean forAllTaskDisplayAreas(Function<TaskDisplayArea, Boolean> callback,
             boolean traverseTopToBottom) {
-        return callback.apply(this);
+        // Apply the callback to all TDAs at or below this container. If the callback returns true,
+        // stop early.
+        if (traverseTopToBottom) {
+            // When it is top to bottom, run on child TDA first as they are on top of the parent.
+            return super.forAllTaskDisplayAreas(callback, traverseTopToBottom)
+                    || callback.apply(this);
+        }
+        return callback.apply(this) || super.forAllTaskDisplayAreas(callback, traverseTopToBottom);
     }
 
     @Override
     void forAllTaskDisplayAreas(Consumer<TaskDisplayArea> callback, boolean traverseTopToBottom) {
-        callback.accept(this);
+        if (traverseTopToBottom) {
+            super.forAllTaskDisplayAreas(callback, traverseTopToBottom);
+            callback.accept(this);
+        } else {
+            callback.accept(this);
+            super.forAllTaskDisplayAreas(callback, traverseTopToBottom);
+        }
     }
 
     @Nullable
     @Override
     <R> R reduceOnAllTaskDisplayAreas(BiFunction<TaskDisplayArea, R, R> accumulator,
             @Nullable R initValue, boolean traverseTopToBottom) {
-        return accumulator.apply(this, initValue);
+        if (traverseTopToBottom) {
+            final R result =
+                    super.reduceOnAllTaskDisplayAreas(accumulator, initValue, traverseTopToBottom);
+            return accumulator.apply(this, result);
+        } else {
+            final R result = accumulator.apply(this, initValue);
+            return super.reduceOnAllTaskDisplayAreas(accumulator, result, traverseTopToBottom);
+
+        }
     }
 
     @Nullable
     @Override
     <R> R getItemFromTaskDisplayAreas(Function<TaskDisplayArea, R> callback,
             boolean traverseTopToBottom) {
-        return callback.apply(this);
+        if (traverseTopToBottom) {
+            final R item = super.getItemFromTaskDisplayAreas(callback, traverseTopToBottom);
+            return item != null ? item : callback.apply(this);
+        } else {
+            final R item = callback.apply(this);
+            return item != null
+                    ? item
+                    : super.getItemFromTaskDisplayAreas(callback, traverseTopToBottom);
+        }
     }
 
     /**
-     * Assigns a priority number to stack types. This priority defines an order between the types
-     * of stacks that are added to the task display area.
+     * Assigns a priority number to root task types. This priority defines an order between the
+     * types of root task that are added to the task display area.
      *
-     * Higher priority number indicates that the stack should have a higher z-order.
+     * Higher priority number indicates that the root task should have a higher z-order.
      *
-     * @return the priority of the stack
+     * For child {@link TaskDisplayArea}, it will be the priority of its top child.
+     *
+     * @return the priority of the root task
      */
-    private int getPriority(Task stack) {
-        if (mWmService.mAssistantOnTopOfDream && stack.isActivityTypeAssistant()) return 4;
-        if (stack.isActivityTypeDream()) return 3;
-        if (stack.inPinnedWindowingMode()) return 2;
-        if (stack.isAlwaysOnTop()) return 1;
+    private int getPriority(WindowContainer child) {
+        final TaskDisplayArea tda = child.asTaskDisplayArea();
+        if (tda != null) {
+            // Use the top child priority as the TaskDisplayArea priority.
+            return tda.getPriority(tda.getTopChild());
+        }
+        final Task rootTask = child.asTask();
+        if (mWmService.mAssistantOnTopOfDream && rootTask.isActivityTypeAssistant()) return 4;
+        if (rootTask.isActivityTypeDream()) return 3;
+        if (rootTask.inPinnedWindowingMode()) return 2;
+        if (rootTask.isAlwaysOnTop()) return 1;
         return 0;
     }
 
@@ -481,10 +580,12 @@
         }
 
         if (rootTask.isAlwaysOnTop()) {
-            // Since a stack could be repositioned while still being one of the children, we check
-            // if this always-on-top stack already exists and if so, set the minPosition to its
-            // previous position.
-            final int currentIndex = getIndexOf(rootTask);
+            // Since a root task could be repositioned while still being one of the children, we
+            // check if this always-on-top root task already exists and if so, set the minPosition
+            // to its previous position.
+            // Use mChildren.indexOf instead of getTaskIndexOf because we need to place the rootTask
+            // as a direct child.
+            final int currentIndex = mChildren.indexOf(rootTask);
             if (currentIndex > minPosition) {
                 minPosition = currentIndex;
             }
@@ -494,9 +595,9 @@
 
     private int findMaxPositionForRootTask(Task rootTask) {
         for (int i = mChildren.size() - 1; i >= 0; --i) {
-            final Task curr = mChildren.get(i);
-            // Since a stack could be repositioned while still being one of the children, we check
-            // if 'curr' is the same stack and skip it if so
+            final WindowContainer curr = mChildren.get(i);
+            // Since a root task could be repositioned while still being one of the children, we
+            // check if 'curr' is the same root task and skip it if so
             final boolean sameRootTask = curr == rootTask;
             if (getPriority(curr) <= getPriority(rootTask) && !sameRootTask) {
                 return i;
@@ -506,29 +607,29 @@
     }
 
     /**
-     * When stack is added or repositioned, find a proper position for it.
+     * When root task is added or repositioned, find a proper position for it.
      *
      * The order is defined as:
      * - Dream is on top of everything
      * - PiP is directly below the Dream
-     * - always-on-top stacks are directly below PiP; new always-on-top stacks are added above
-     * existing ones
-     * - other non-always-on-top stacks come directly below always-on-top stacks; new
-     * non-always-on-top stacks are added directly below always-on-top stacks and above existing
-     * non-always-on-top stacks
+     * - always-on-top root tasks are directly below PiP; new always-on-top root tasks are added
+     * above existing ones
+     * - other non-always-on-top root tasks come directly below always-on-top root tasks; new
+     * non-always-on-top root tasks are added directly below always-on-top root tasks and above
+     * existing non-always-on-top root tasks
      * - if {@link #mAssistantOnTopOfDream} is enabled, then Assistant is on top of everything
-     * (including the Dream); otherwise, it is a normal non-always-on-top stack
+     * (including the Dream); otherwise, it is a normal non-always-on-top root task
      *
      * @param requestedPosition Position requested by caller.
      * @param rootTask          Root task to be added or positioned.
-     * @param adding            Flag indicates whether we're adding a new stack or positioning an
-     *                          existing.
-     * @return The proper position for the stack.
+     * @param adding            Flag indicates whether we're adding a new root task or positioning
+     *                          an existing.
+     * @return The proper position for the root task.
      */
     private int findPositionForRootTask(int requestedPosition, Task rootTask, boolean adding) {
-        // The max possible position we can insert the stack at.
+        // The max possible position we can insert the root task at.
         int maxPosition = findMaxPositionForRootTask(rootTask);
-        // The min possible position we can insert the stack at.
+        // The min possible position we can insert the root task at.
         int minPosition = findMinPositionForRootTask(rootTask);
 
         // Cap the requested position to something reasonable for the previous position check
@@ -547,8 +648,8 @@
         // The positions we calculated above (maxPosition, minPosition) do not take into
         // consideration the following edge cases.
         // 1) We need to adjust the position depending on the value "adding".
-        // 2) When we are moving a stack to another position, we also need to adjust the
-        //    position depending on whether the stack is moving to a higher or lower position.
+        // 2) When we are moving a root task to another position, we also need to adjust the
+        //    position depending on whether the root task is moving to a higher or lower position.
         if ((targetPosition != requestedPosition) && (adding || targetPosition < prevPosition)) {
             targetPosition++;
         }
@@ -579,13 +680,19 @@
 
     private boolean forAllExitingAppTokenWindows(ToBooleanFunction<WindowState> callback,
             boolean traverseTopToBottom) {
-        // For legacy reasons we process the TaskStack.mExitingActivities first here before the
+        // For legacy reasons we process the RootTask.mExitingActivities first here before the
         // app tokens.
         // TODO: Investigate if we need to continue to do this or if we can just process them
         // in-order.
         if (traverseTopToBottom) {
             for (int i = mChildren.size() - 1; i >= 0; --i) {
-                final List<ActivityRecord> activities = mChildren.get(i).mExitingActivities;
+                // Only run on those of direct Task child, because child TaskDisplayArea has run on
+                // its child in #forAllWindows()
+                if (mChildren.get(i).asTask() == null) {
+                    continue;
+                }
+                final List<ActivityRecord> activities =
+                        mChildren.get(i).asTask().mExitingActivities;
                 for (int j = activities.size() - 1; j >= 0; --j) {
                     if (activities.get(j).forAllWindowsUnchecked(callback,
                             traverseTopToBottom)) {
@@ -596,7 +703,13 @@
         } else {
             final int count = mChildren.size();
             for (int i = 0; i < count; ++i) {
-                final List<ActivityRecord> activities = mChildren.get(i).mExitingActivities;
+                // Only run on those of direct Task child, because child TaskDisplayArea has run on
+                // its child in #forAllWindows()
+                if (mChildren.get(i).asTask() == null) {
+                    continue;
+                }
+                final List<ActivityRecord> activities =
+                        mChildren.get(i).asTask().mExitingActivities;
                 final int appTokensCount = activities.size();
                 for (int j = 0; j < appTokensCount; j++) {
                     if (activities.get(j).forAllWindowsUnchecked(callback,
@@ -612,9 +725,18 @@
     @Override
     int getOrientation(int candidate) {
         mLastOrientationSource = null;
-        if (!canSpecifyOrientation()) {
+        if (mIgnoreOrientationRequest) {
             return SCREEN_ORIENTATION_UNSET;
         }
+        if (!canSpecifyOrientation()) {
+            // We only respect orientation of the focused TDA, which can be a child of this TDA.
+            return reduceOnAllTaskDisplayAreas((taskDisplayArea, orientation) -> {
+                if (taskDisplayArea == this || orientation != SCREEN_ORIENTATION_UNSET) {
+                    return orientation;
+                }
+                return taskDisplayArea.getOrientation(candidate);
+            }, SCREEN_ORIENTATION_UNSET);
+        }
 
         if (isRootTaskVisible(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY)) {
             // Apps and their containers are not allowed to specify an orientation while using
@@ -671,8 +793,7 @@
         assignRootTaskOrdering(t);
 
         for (int i = 0; i < mChildren.size(); i++) {
-            final Task s = mChildren.get(i);
-            s.assignChildLayers(t);
+            mChildren.get(i).assignChildLayers(t);
         }
     }
 
@@ -680,33 +801,49 @@
         if (getParent() == null) {
             return;
         }
-        mTmpAlwaysOnTopRootTasks.clear();
-        mTmpHomeRootTasks.clear();
-        mTmpNormalRootTasks.clear();
+        mTmpAlwaysOnTopChildren.clear();
+        mTmpHomeChildren.clear();
+        mTmpNormalChildren.clear();
         for (int i = 0; i < mChildren.size(); ++i) {
-            final Task s = mChildren.get(i);
-            if (s.isAlwaysOnTop()) {
-                mTmpAlwaysOnTopRootTasks.add(s);
-            } else if (s.isActivityTypeHome()) {
-                mTmpHomeRootTasks.add(s);
+            final WindowContainer child = mChildren.get(i);
+            final TaskDisplayArea childTda = child.asTaskDisplayArea();
+            if (childTda != null) {
+                final Task childTdaTopRootTask = childTda.getTopRootTask();
+                if (childTdaTopRootTask == null) {
+                    mTmpNormalChildren.add(childTda);
+                } else if (childTdaTopRootTask.isAlwaysOnTop()) {
+                    mTmpAlwaysOnTopChildren.add(childTda);
+                } else if (childTdaTopRootTask.isActivityTypeHome()) {
+                    mTmpHomeChildren.add(childTda);
+                } else {
+                    mTmpNormalChildren.add(childTda);
+                }
+                continue;
+            }
+
+            final Task childTask = child.asTask();
+            if (childTask.isAlwaysOnTop()) {
+                mTmpAlwaysOnTopChildren.add(childTask);
+            } else if (childTask.isActivityTypeHome()) {
+                mTmpHomeChildren.add(childTask);
             } else {
-                mTmpNormalRootTasks.add(s);
+                mTmpNormalChildren.add(childTask);
             }
         }
 
         int layer = 0;
         // Place home stacks to the bottom.
-        layer = adjustRootTaskLayer(t, mTmpHomeRootTasks, layer, false /* normalStacks */);
+        layer = adjustRootTaskLayer(t, mTmpHomeChildren, layer, false /* normalRootTasks */);
         // The home animation layer is between the home stacks and the normal stacks.
         final int layerForHomeAnimationLayer = layer++;
         mTmpLayerForSplitScreenDividerAnchor = layer++;
         mTmpLayerForAnimationLayer = layer++;
-        layer = adjustRootTaskLayer(t, mTmpNormalRootTasks, layer, true /* normalStacks */);
+        layer = adjustRootTaskLayer(t, mTmpNormalChildren, layer, true /* normalRootTasks */);
 
         // The boosted animation layer is between the normal stacks and the always on top
         // stacks.
         final int layerForBoostedAnimationLayer = layer++;
-        adjustRootTaskLayer(t, mTmpAlwaysOnTopRootTasks, layer, false /* normalStacks */);
+        adjustRootTaskLayer(t, mTmpAlwaysOnTopChildren, layer, false /* normalRootTasks */);
 
         t.setLayer(mHomeAppAnimationLayer, layerForHomeAnimationLayer);
         t.setLayer(mAppAnimationLayer, mTmpLayerForAnimationLayer);
@@ -714,13 +851,14 @@
         t.setLayer(mBoostedAppAnimationLayer, layerForBoostedAnimationLayer);
     }
 
-    private int adjustNormalRootTaskLayer(Task s, int layer) {
-        if (s.inSplitScreenWindowingMode()) {
+    private int adjustNormalRootTaskLayer(WindowContainer child, int layer) {
+        if (child.asTask() != null && child.inSplitScreenWindowingMode()) {
             // The split screen divider anchor is located above the split screen window.
             mTmpLayerForSplitScreenDividerAnchor = layer++;
         }
-        if (s.isAnimatingByRecents() || s.isAppTransitioning()) {
-            // The animation layer is located above the highest animating stack and no
+        if ((child.asTask() != null && child.asTask().isAnimatingByRecents())
+                || child.isAppTransitioning()) {
+            // The animation layer is located above the highest animating root task and no
             // higher.
             mTmpLayerForAnimationLayer = layer++;
         }
@@ -728,23 +866,30 @@
     }
 
     /**
-     * Adjusts the layer of the stack which belongs to the same group.
-     * Note that there are three stack groups: home stacks, always on top stacks, and normal stacks.
+     * Adjusts the layer of the root task which belongs to the same group.
+     * Note that there are three root task groups: home rootTasks, always on top rootTasks, and
+     * normal rootTasks.
      *
-     * @param startLayer   The beginning layer of this group of stacks.
-     * @param normalStacks Set {@code true} if this group is neither home nor always on top.
+     * @param startLayer   The beginning layer of this group of rootTasks.
+     * @param normalRootTasks Set {@code true} if this group is neither home nor always on top.
      * @return The adjusted layer value.
      */
-    private int adjustRootTaskLayer(SurfaceControl.Transaction t, ArrayList<Task> stacks,
-            int startLayer, boolean normalStacks) {
+    private int adjustRootTaskLayer(SurfaceControl.Transaction t,
+            ArrayList<WindowContainer> children, int startLayer, boolean normalRootTasks) {
         mTmpNeedsZBoostIndexes.clear();
-        final int stackSize = stacks.size();
-        for (int i = 0; i < stackSize; i++) {
-            final Task stack = stacks.get(i);
-            if (!stack.needsZBoost()) {
-                stack.assignLayer(t, startLayer++);
-                if (normalStacks) {
-                    startLayer = adjustNormalRootTaskLayer(stack, startLayer);
+        final int childCount = children.size();
+        for (int i = 0; i < childCount; i++) {
+            final WindowContainer child = children.get(i);
+            final TaskDisplayArea childTda = child.asTaskDisplayArea();
+
+            boolean childNeedsZBoost = childTda != null
+                    ? childTda.childrenNeedZBoost()
+                    : child.needsZBoost();
+
+            if (!childNeedsZBoost) {
+                child.assignLayer(t, startLayer++);
+                if (normalRootTasks) {
+                    startLayer = adjustNormalRootTaskLayer(child, startLayer);
                 }
             } else {
                 mTmpNeedsZBoostIndexes.add(i);
@@ -753,15 +898,23 @@
 
         final int zBoostSize = mTmpNeedsZBoostIndexes.size();
         for (int i = 0; i < zBoostSize; i++) {
-            final Task stack = stacks.get(mTmpNeedsZBoostIndexes.get(i));
-            stack.assignLayer(t, startLayer++);
-            if (normalStacks) {
-                startLayer = adjustNormalRootTaskLayer(stack, startLayer);
+            final WindowContainer child = children.get(mTmpNeedsZBoostIndexes.get(i));
+            child.assignLayer(t, startLayer++);
+            if (normalRootTasks) {
+                startLayer = adjustNormalRootTaskLayer(child, startLayer);
             }
         }
         return startLayer;
     }
 
+    private boolean childrenNeedZBoost() {
+        final boolean[] needsZBoost = new boolean[1];
+        forAllRootTasks(task -> {
+            needsZBoost[0] |= task.needsZBoost();
+        });
+        return needsZBoost[0];
+    }
+
     @Override
     SurfaceControl getAppAnimationLayer(@AnimationLayer int animationLayer) {
         switch (animationLayer) {
@@ -1027,15 +1180,25 @@
             return null;
         }
         for (int i = mChildren.size() - 1; i >= 0; --i) {
-            final Task t = mChildren.get(i);
-            if (!t.mCreatedByOrganizer || t.getRequestedOverrideWindowingMode() != windowingMode) {
+            final WindowContainer child = mChildren.get(i);
+            if (child.asTaskDisplayArea() != null) {
+                final Task t = child.asTaskDisplayArea().updateLaunchRootTask(windowingMode);
+                if (t != null) {
+                    return t;
+                }
+                continue;
+            }
+
+            final Task t = mChildren.get(i).asTask();
+            if (t == null || !t.mCreatedByOrganizer
+                    || t.getRequestedOverrideWindowingMode() != windowingMode) {
                 continue;
             }
             // If not already set, pick a launch root which is not the one we are launching into.
             if (mLaunchRootTask == null) {
                 for (int j = 0, n = mChildren.size(); j < n; ++j) {
-                    final Task tt = mChildren.get(j);
-                    if (tt.mCreatedByOrganizer && tt != t) {
+                    final Task tt = mChildren.get(j).asTask();
+                    if (tt != null && tt.mCreatedByOrganizer && tt != t) {
                         mLaunchRootTask = tt;
                         break;
                     }
@@ -1081,8 +1244,8 @@
     }
 
     /**
-     * Get the preferred focusable stack in priority. If the preferred stack does not exist, find a
-     * focusable and visible stack from the top of stacks in this display.
+     * Get the preferred focusable root task in priority. If the preferred root task does not exist,
+     * find a focusable and visible root task from the top of root tasks in this display.
      */
     Task getFocusedRootTask() {
         if (mPreferredTopFocusableRootTask != null) {
@@ -1090,9 +1253,18 @@
         }
 
         for (int i = mChildren.size() - 1; i >= 0; --i) {
-            final Task stack = mChildren.get(i);
-            if (stack.isFocusableAndVisible()) {
-                return stack;
+            final WindowContainer child = mChildren.get(i);
+            if (child.asTaskDisplayArea() != null) {
+                final Task rootTask = child.asTaskDisplayArea().getFocusedRootTask();
+                if (rootTask != null) {
+                    return rootTask;
+                }
+                continue;
+            }
+
+            final Task rootTask = mChildren.get(i).asTask();
+            if (rootTask.isFocusableAndVisible()) {
+                return rootTask;
             }
         }
 
@@ -1105,7 +1277,17 @@
 
         Task candidate = null;
         for (int i = mChildren.size() - 1; i >= 0; --i) {
-            final Task rootTask = mChildren.get(i);
+            final WindowContainer child = mChildren.get(i);
+            if (child.asTaskDisplayArea() != null) {
+                final Task rootTask = child.asTaskDisplayArea()
+                        .getNextFocusableRootTask(currentFocus, ignoreCurrent);
+                if (rootTask != null) {
+                    return rootTask;
+                }
+                continue;
+            }
+
+            final Task rootTask = mChildren.get(i).asTask();
             if (ignoreCurrent && rootTask == currentFocus) {
                 continue;
             }
@@ -1115,18 +1297,19 @@
 
             if (currentWindowingMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY
                     && candidate == null && rootTask.inSplitScreenPrimaryWindowingMode()) {
-                // If the currently focused stack is in split-screen secondary we save off the
-                // top primary split-screen stack as a candidate for focus because we might
-                // prefer focus to move to an other stack to avoid primary split-screen stack
-                // overlapping with a fullscreen stack when a fullscreen stack is higher in z
-                // than the next split-screen stack. Assistant stack, I am looking at you...
-                // We only move the focus to the primary-split screen stack if there isn't a
+                // If the currently focused root task is in split-screen secondary we save off the
+                // top primary split-screen root task as a candidate for focus because we might
+                // prefer focus to move to an other root task to avoid primary split-screen root
+                // task overlapping with a fullscreen root task when a fullscreen root task is
+                // higher in z than the next split-screen root task. Assistant root task, I am
+                // looking at you...
+                // We only move the focus to the primary-split screen root task if there isn't a
                 // better alternative.
                 candidate = rootTask;
                 continue;
             }
             if (candidate != null && rootTask.inSplitScreenSecondaryWindowingMode()) {
-                // Use the candidate stack since we are now at the secondary split-screen.
+                // Use the candidate root task since we are now at the secondary split-screen.
                 return candidate;
             }
             return rootTask;
@@ -1135,21 +1318,21 @@
     }
 
     ActivityRecord getFocusedActivity() {
-        final Task focusedStack = getFocusedRootTask();
-        if (focusedStack == null) {
+        final Task focusedRootTask = getFocusedRootTask();
+        if (focusedRootTask == null) {
             return null;
         }
         // TODO(b/111541062): Move this into ActivityStack#getResumedActivity()
-        // Check if the focused stack has the resumed activity
-        ActivityRecord resumedActivity = focusedStack.getResumedActivity();
+        // Check if the focused root task has the resumed activity
+        ActivityRecord resumedActivity = focusedRootTask.getResumedActivity();
         if (resumedActivity == null || resumedActivity.app == null) {
-            // If there is no registered resumed activity in the stack or it is not running -
+            // If there is no registered resumed activity in the root task or it is not running -
             // try to use previously resumed one.
-            resumedActivity = focusedStack.getPausingActivity();
+            resumedActivity = focusedRootTask.getPausingActivity();
             if (resumedActivity == null || resumedActivity.app == null) {
                 // If previously resumed activity doesn't work either - find the topmost running
                 // activity that can be focused.
-                resumedActivity = focusedStack.topRunningActivity(true /* focusableOnly */);
+                resumedActivity = focusedRootTask.topRunningActivity(true /* focusableOnly */);
             }
         }
         return resumedActivity;
@@ -1184,27 +1367,35 @@
     }
 
     boolean allResumedActivitiesComplete() {
-        for (int stackNdx = mChildren.size() - 1; stackNdx >= 0; --stackNdx) {
-            final ActivityRecord r = mChildren.get(stackNdx).getResumedActivity();
+        for (int i = mChildren.size() - 1; i >= 0; --i) {
+            final WindowContainer child = mChildren.get(i);
+            if (child.asTaskDisplayArea() != null) {
+                if (!child.asTaskDisplayArea().allResumedActivitiesComplete()) {
+                    return false;
+                }
+                continue;
+            }
+
+            final ActivityRecord r = mChildren.get(i).asTask().getResumedActivity();
             if (r != null && !r.isState(RESUMED)) {
                 return false;
             }
         }
-        final Task currentFocusedStack = getFocusedRootTask();
+        final Task currentFocusedRootTask = getFocusedRootTask();
         if (ActivityTaskManagerDebugConfig.DEBUG_ROOT_TASK) {
-            Slog.d(TAG_ROOT_TASK, "allResumedActivitiesComplete: mLastFocusedStack changing from="
-                    + mLastFocusedRootTask + " to=" + currentFocusedStack);
+            Slog.d(TAG_ROOT_TASK, "allResumedActivitiesComplete: currentFocusedRootTask "
+                    + "changing from=" + mLastFocusedRootTask + " to=" + currentFocusedRootTask);
         }
-        mLastFocusedRootTask = currentFocusedStack;
+        mLastFocusedRootTask = currentFocusedRootTask;
         return true;
     }
 
     /**
-     * Pause all activities in either all of the stacks or just the back stacks. This is done before
-     * resuming a new activity and to make sure that previously active activities are
-     * paused in stacks that are no longer visible or in pinned windowing mode. This does not
-     * pause activities in visible stacks, so if an activity is launched within the same stack/task,
-     * then we should explicitly pause that stack's top activity.
+     * Pause all activities in either all of the root tasks or just the back root tasks. This is
+     * done before resuming a new activity and to make sure that previously active activities are
+     * paused in root tasks that are no longer visible or in pinned windowing mode. This does not
+     * pause activities in visible root tasks, so if an activity is launched within the same root
+     * task, hen we should explicitly pause that root task's top activity.
      *
      * @param userLeaving Passed to pauseActivity() to indicate whether to call onUserLeaving().
      * @param resuming    The resuming activity.
@@ -1217,10 +1408,10 @@
             if (resumedActivity != null
                     && (task.getVisibility(resuming) != TASK_VISIBILITY_VISIBLE
                     || !task.isTopActivityFocusable())) {
-                ProtoLog.d(WM_DEBUG_STATES, "pauseBackStacks: task=%s "
+                ProtoLog.d(WM_DEBUG_STATES, "pauseBackTasks: task=%s "
                         + "mResumedActivity=%s", task, resumedActivity);
                 if (task.startPausingLocked(userLeaving, false /* uiSleeping*/,
-                        resuming, "pauseBackStacks")) {
+                        resuming, "pauseBackTasks")) {
                     someActivityPaused[0]++;
                 }
             }
@@ -1234,18 +1425,21 @@
     void findTaskLocked(final ActivityRecord r, final boolean isPreferredDisplayArea,
             RootWindowContainer.FindTaskResult result) {
         mTmpFindTaskResult.clear();
-        for (int stackNdx = mChildren.size() - 1; stackNdx >= 0; --stackNdx) {
-            final Task stack = mChildren.get(stackNdx);
-            if (!r.hasCompatibleActivityType(stack) && stack.isLeafTask()) {
-                ProtoLog.d(WM_DEBUG_TASKS, "Skipping stack: (mismatch activity/stack) "
-                        + "%s", stack);
+        for (int i = mChildren.size() - 1; i >= 0; --i) {
+            final Task rootTask = mChildren.get(i).asTask();
+            if (rootTask == null) {
+                continue;
+            }
+            if (!r.hasCompatibleActivityType(rootTask) && rootTask.isLeafTask()) {
+                ProtoLog.d(WM_DEBUG_TASKS, "Skipping rootTask: (mismatch activity/rootTask) "
+                        + "%s", rootTask);
                 continue;
             }
 
-            mTmpFindTaskResult.process(r, stack);
-            // It is possible to have tasks in multiple stacks with the same root affinity, so
+            mTmpFindTaskResult.process(r, rootTask);
+            // It is possible to have tasks in multiple root tasks with the same root affinity, so
             // we should keep looking after finding an affinity match to see if there is a
-            // better match in another stack. Also, task affinity isn't a good enough reason
+            // better match in another root task. Also, task affinity isn't a good enough reason
             // to target a display which isn't the source of the intent, so skip any affinity
             // matches not on the specified display.
             if (mTmpFindTaskResult.mRecord != null) {
@@ -1253,9 +1447,9 @@
                     result.setTo(mTmpFindTaskResult);
                     return;
                 } else if (isPreferredDisplayArea) {
-                    // Note: since the traversing through the stacks is top down, the floating
+                    // Note: since the traversing through the root tasks is top down, the floating
                     // tasks should always have lower priority than any affinity-matching tasks
-                    // in the fullscreen stacks
+                    // in the fullscreen root tasks
                     result.setTo(mTmpFindTaskResult);
                 }
             }
@@ -1474,20 +1668,29 @@
      */
     ActivityRecord topRunningActivity(boolean considerKeyguardState) {
         ActivityRecord topRunning = null;
-        final Task focusedStack = getFocusedRootTask();
-        if (focusedStack != null) {
-            topRunning = focusedStack.topRunningActivity();
+        final Task focusedRootTask = getFocusedRootTask();
+        if (focusedRootTask != null) {
+            topRunning = focusedRootTask.topRunningActivity();
         }
 
-        // Look in other focusable stacks.
+        // Look in other focusable root tasks.
         if (topRunning == null) {
             for (int i = mChildren.size() - 1; i >= 0; --i) {
-                final Task stack = mChildren.get(i);
-                // Only consider focusable stacks other than the current focused one.
-                if (stack == focusedStack || !stack.isTopActivityFocusable()) {
+                final WindowContainer child = mChildren.get(i);
+                if (child.asTaskDisplayArea() != null) {
+                    topRunning =
+                            child.asTaskDisplayArea().topRunningActivity(considerKeyguardState);
+                    if (topRunning != null) {
+                        break;
+                    }
                     continue;
                 }
-                topRunning = stack.topRunningActivity();
+                final Task rootTask = mChildren.get(i).asTask();
+                // Only consider focusable root tasks other than the current focused one.
+                if (rootTask == focusedRootTask || !rootTask.isTopActivityFocusable()) {
+                    continue;
+                }
+                topRunning = rootTask.topRunningActivity();
                 if (topRunning != null) {
                     break;
                 }
@@ -1593,35 +1796,44 @@
     }
 
     /**
-     * Adjusts the {@param stack} behind the last visible stack in the display if necessary.
+     * Adjusts the {@param rootTask} behind the last visible rootTask in the display if necessary.
      * Generally used in conjunction with {@link #moveRootTaskBehindRootTask}.
      */
     // TODO(b/151575894): Remove special stack movement methods.
     void moveRootTaskBehindBottomMostVisibleRootTask(Task rootTask) {
         if (rootTask.shouldBeVisible(null)) {
-            // Skip if the stack is already visible
+            // Skip if the root task is already visible
             return;
         }
 
-        // Move the stack to the bottom to not affect the following visibility checks
+        // Move the root task to the bottom to not affect the following visibility checks
         rootTask.getParent().positionChildAt(POSITION_BOTTOM, rootTask,
                 false /* includingParents */);
 
-        // Find the next position where the stack should be placed
+        // Find the next position where the root task should be placed
         final boolean isRootTask = rootTask.isRootTask();
         final int numRootTasks =
                 isRootTask ? mChildren.size() : rootTask.getParent().getChildCount();
         for (int rootTaskNdx = 0; rootTaskNdx < numRootTasks; rootTaskNdx++) {
-            final Task s = isRootTask ? mChildren.get(rootTaskNdx)
-                    : (Task) rootTask.getParent().getChildAt(rootTaskNdx);
-            if (s == rootTask) {
+            Task s;
+            if (isRootTask) {
+                final WindowContainer child = mChildren.get(rootTaskNdx);
+                if (child.asTaskDisplayArea() != null) {
+                    s = child.asTaskDisplayArea().getBottomMostVisibleRootTask(rootTask);
+                } else {
+                    s = child.asTask();
+                }
+            } else {
+                s = rootTask.getParent().getChildAt(rootTaskNdx).asTask();
+            }
+            if (s == rootTask || s == null) {
                 continue;
             }
             final int winMode = s.getWindowingMode();
             final boolean isValidWindowingMode = winMode == WINDOWING_MODE_FULLSCREEN
                     || winMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
             if (s.shouldBeVisible(null) && isValidWindowingMode) {
-                // Move the provided stack to behind this stack
+                // Move the provided root task to behind this root task
                 final int position = Math.max(0, rootTaskNdx - 1);
                 rootTask.getParent().positionChildAt(position, rootTask,
                         false /*includingParents */);
@@ -1630,6 +1842,16 @@
         }
     }
 
+    @Nullable
+    private Task getBottomMostVisibleRootTask(Task excludeRootTask) {
+        return getRootTask(task -> {
+            final int winMode = task.getWindowingMode();
+            final boolean isValidWindowingMode = winMode == WINDOWING_MODE_FULLSCREEN
+                    || winMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
+            return task.shouldBeVisible(null) && isValidWindowingMode;
+        }, false /* traverseTopToBottom */);
+    }
+
     /**
      * Moves the {@param stack} behind the given {@param behindStack} if possible. If
      * {@param behindStack} is not currently in the display, then then the stack is moved to the
@@ -1735,77 +1957,82 @@
             boolean preserveWindows, boolean notifyClients, boolean userLeaving) {
         mAtmService.mTaskSupervisor.beginActivityVisibilityUpdate();
         try {
-            for (int stackNdx = mChildren.size() - 1; stackNdx >= 0; --stackNdx) {
-                final Task stack = mChildren.get(stackNdx);
-                stack.ensureActivitiesVisible(starting, configChanges, preserveWindows,
+            forAllRootTasks(rootTask -> {
+                rootTask.ensureActivitiesVisible(starting, configChanges, preserveWindows,
                         notifyClients, userLeaving);
-            }
+            });
         } finally {
             mAtmService.mTaskSupervisor.endActivityVisibilityUpdate();
         }
     }
 
     /**
-     * Removes the stacks in the node applying the content removal node from the display.
+     * Removes the root tasks in the node applying the content removal node from the display.
      *
-     * @return last reparented stack, or {@code null} if the stacks had to be destroyed.
+     * @return last reparented root task, or {@code null} if the root tasks had to be destroyed.
      */
     Task remove() {
         mPreferredTopFocusableRootTask = null;
         // TODO(b/153090332): Allow setting content removal mode per task display area
         final boolean destroyContentOnRemoval = mDisplayContent.shouldDestroyContentOnRemove();
         final TaskDisplayArea toDisplayArea = mRootWindowContainer.getDefaultTaskDisplayArea();
-        Task lastReparentedStack = null;
+        Task lastReparentedRootTask = null;
 
-        // Stacks could be reparented from the removed display area to other display area. After
-        // reparenting the last stack of the removed display area, the display area becomes ready to
-        // be released (no more ActivityStack-s). But, we cannot release it at that moment or the
-        // related WindowContainer will also be removed. So, we set display area as removed after
-        // reparenting stack finished.
+        // Root tasks could be reparented from the removed display area to other display area. After
+        // reparenting the last root task of the removed display area, the display area becomes
+        // ready to be released (no more ActivityStack-s). But, we cannot release it at that moment
+        // or the related WindowContainer will also be removed. So, we set display area as removed
+        // after reparenting root task finished.
         // Keep the order from bottom to top.
-        int numStacks = mChildren.size();
+        int numRootTasks = mChildren.size();
 
         final boolean splitScreenActivated = toDisplayArea.isSplitScreenModeActivated();
-        final Task rootStack = splitScreenActivated ? toDisplayArea
+        final Task splitScreenRoot = splitScreenActivated ? toDisplayArea
                 .getTopRootTaskInWindowingMode(WINDOWING_MODE_SPLIT_SCREEN_SECONDARY) : null;
-        for (int stackNdx = 0; stackNdx < numStacks; stackNdx++) {
-            final Task stack = mChildren.get(stackNdx);
-            // Always finish non-standard type stacks and stacks created by a organizer.
+        for (int i = 0; i < numRootTasks; i++) {
+            final WindowContainer child = mChildren.get(i);
+            if (child.asTaskDisplayArea() != null) {
+                lastReparentedRootTask = child.asTaskDisplayArea().remove();
+                continue;
+            }
+            final Task task = mChildren.get(i).asTask();
+            // Always finish non-standard type root tasks and root tasks created by a organizer.
             // TODO: For stacks created by organizer, consider reparenting children tasks if the use
             //       case arises in the future.
             if (destroyContentOnRemoval
-                    || !stack.isActivityTypeStandardOrUndefined()
-                    || stack.mCreatedByOrganizer) {
-                stack.finishAllActivitiesImmediately();
+                    || !task.isActivityTypeStandardOrUndefined()
+                    || task.mCreatedByOrganizer) {
+                task.finishAllActivitiesImmediately();
             } else {
-                // Reparent the stack to the root task of secondary-split-screen or display area.
-                stack.reparent(stack.supportsSplitScreenWindowingMode() && rootStack != null
-                        ? rootStack : toDisplayArea, POSITION_TOP);
+                // Reparent the root task to the root task of secondary-split-screen or display
+                // area.
+                task.reparent(task.supportsSplitScreenWindowingMode() && splitScreenRoot != null
+                        ? splitScreenRoot : toDisplayArea, POSITION_TOP);
 
-                // Set the windowing mode to undefined by default to let the stack inherited the
+                // Set the windowing mode to undefined by default to let the root task inherited the
                 // windowing mode.
-                stack.setWindowingMode(WINDOWING_MODE_UNDEFINED);
-                lastReparentedStack = stack;
+                task.setWindowingMode(WINDOWING_MODE_UNDEFINED);
+                lastReparentedRootTask = task;
             }
-            // Stacks may be removed from this display. Ensure each stack will be processed
+            // Root task may be removed from this display. Ensure each root task will be processed
             // and the loop will end.
-            stackNdx -= numStacks - mChildren.size();
-            numStacks = mChildren.size();
+            i -= numRootTasks - mChildren.size();
+            numRootTasks = mChildren.size();
         }
-        if (lastReparentedStack != null && splitScreenActivated) {
-            if (!lastReparentedStack.supportsSplitScreenWindowingMode()) {
+        if (lastReparentedRootTask != null && splitScreenActivated) {
+            if (!lastReparentedRootTask.supportsSplitScreenWindowingMode()) {
                 mAtmService.getTaskChangeNotificationController()
                         .notifyActivityDismissingDockedStack();
-                toDisplayArea.onSplitScreenModeDismissed(lastReparentedStack);
-            } else if (rootStack != null) {
+                toDisplayArea.onSplitScreenModeDismissed(lastReparentedRootTask);
+            } else if (splitScreenRoot != null) {
                 // update focus
-                rootStack.moveToFront("display-removed");
+                splitScreenRoot.moveToFront("display-removed");
             }
         }
 
         mRemoved = true;
 
-        return lastReparentedStack;
+        return lastReparentedRootTask;
     }
 
     /** Whether this task display area can request orientation. */
@@ -1842,8 +2069,13 @@
         }
         final String triplePrefix = doublePrefix + "  ";
         pw.println(doublePrefix + "Application tokens in top down Z order:");
-        for (int rootTaskNdx = getChildCount() - 1; rootTaskNdx >= 0; --rootTaskNdx) {
-            final Task rootTask = getChildAt(rootTaskNdx);
+        for (int index = getChildCount() - 1; index >= 0; --index) {
+            final WindowContainer child = getChildAt(index);
+            if (child.asTaskDisplayArea() != null) {
+                child.dump(pw, doublePrefix, dumpAll);
+                continue;
+            }
+            final Task rootTask = child.asTask();
             pw.println(doublePrefix + "* " + rootTask);
             rootTask.dump(pw, triplePrefix, dumpAll);
         }
diff --git a/services/core/java/com/android/server/wm/TaskOrganizerController.java b/services/core/java/com/android/server/wm/TaskOrganizerController.java
index 9f8c35b..929d7bf 100644
--- a/services/core/java/com/android/server/wm/TaskOrganizerController.java
+++ b/services/core/java/com/android/server/wm/TaskOrganizerController.java
@@ -39,6 +39,7 @@
 import android.view.SurfaceControl;
 import android.window.ITaskOrganizer;
 import android.window.ITaskOrganizerController;
+import android.window.StartingWindowInfo;
 import android.window.TaskAppearedInfo;
 import android.window.WindowContainerToken;
 
@@ -116,10 +117,10 @@
         }
 
         void addStartingWindow(Task task, IBinder appToken) {
-            final RunningTaskInfo taskInfo = task.getTaskInfo();
+            final StartingWindowInfo info = task.getStartingWindowInfo();
             mDeferTaskOrgCallbacksConsumer.accept(() -> {
                 try {
-                    mTaskOrganizer.addStartingWindow(taskInfo, appToken);
+                    mTaskOrganizer.addStartingWindow(info, appToken);
                 } catch (RemoteException e) {
                     Slog.e(TAG, "Exception sending onTaskStart callback", e);
                 }
@@ -127,10 +128,9 @@
         }
 
         void removeStartingWindow(Task task) {
-            final RunningTaskInfo taskInfo = task.getTaskInfo();
             mDeferTaskOrgCallbacksConsumer.accept(() -> {
                 try {
-                    mTaskOrganizer.removeStartingWindow(taskInfo);
+                    mTaskOrganizer.removeStartingWindow(task.mTaskId);
                 } catch (RemoteException e) {
                     Slog.e(TAG, "Exception sending onStartTaskFinished callback", e);
                 }
@@ -152,23 +152,27 @@
             ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "Task appeared taskId=%d", task.mTaskId);
             final boolean visible = task.isVisible();
             final RunningTaskInfo taskInfo = task.getTaskInfo();
-            try {
-                mTaskOrganizer.onTaskAppeared(taskInfo, prepareLeash(task, visible,
-                        "TaskOrganizerController.onTaskAppeared"));
-            } catch (RemoteException e) {
-                Slog.e(TAG, "Exception sending onTaskAppeared callback", e);
-            }
+            mDeferTaskOrgCallbacksConsumer.accept(() -> {
+                try {
+                    mTaskOrganizer.onTaskAppeared(taskInfo, prepareLeash(task, visible,
+                            "TaskOrganizerController.onTaskAppeared"));
+                } catch (RemoteException e) {
+                    Slog.e(TAG, "Exception sending onTaskAppeared callback", e);
+                }
+            });
         }
 
 
         void onTaskVanished(Task task) {
             ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "Task vanished taskId=%d", task.mTaskId);
             final RunningTaskInfo taskInfo = task.getTaskInfo();
-            try {
-                mTaskOrganizer.onTaskVanished(taskInfo);
-            } catch (RemoteException e) {
-                Slog.e(TAG, "Exception sending onTaskVanished callback", e);
-            }
+            mDeferTaskOrgCallbacksConsumer.accept(() -> {
+                try {
+                    mTaskOrganizer.onTaskVanished(taskInfo);
+                } catch (RemoteException e) {
+                    Slog.e(TAG, "Exception sending onTaskVanished callback", e);
+                }
+            });
         }
 
         void onTaskInfoChanged(Task task, ActivityManager.RunningTaskInfo taskInfo) {
@@ -177,18 +181,20 @@
                 return;
             }
             ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "Task info changed taskId=%d", task.mTaskId);
-            if (!task.isOrganized()) {
-                // This is safe to ignore if the task is no longer organized
-                return;
-            }
-            try {
-                // Purposely notify of task info change immediately instead of deferring (like
-                // appear and vanish) to allow info changes (such as new PIP params) to flow
-                // without waiting.
-                mTaskOrganizer.onTaskInfoChanged(taskInfo);
-            } catch (RemoteException e) {
-                Slog.e(TAG, "Exception sending onTaskInfoChanged callback", e);
-            }
+            mDeferTaskOrgCallbacksConsumer.accept(() -> {
+                if (!task.isOrganized()) {
+                    // This is safe to ignore if the task is no longer organized
+                    return;
+                }
+                try {
+                    // Purposely notify of task info change immediately instead of deferring (like
+                    // appear and vanish) to allow info changes (such as new PIP params) to flow
+                    // without waiting.
+                    mTaskOrganizer.onTaskInfoChanged(taskInfo);
+                } catch (RemoteException e) {
+                    Slog.e(TAG, "Exception sending onTaskInfoChanged callback", e);
+                }
+            });
         }
 
         void onBackPressedOnTaskRoot(Task task) {
@@ -198,15 +204,17 @@
                 // Skip if the task has not yet received taskAppeared().
                 return;
             }
-            if (!task.isOrganized()) {
-                // This is safe to ignore if the task is no longer organized
-                return;
-            }
-            try {
-                mTaskOrganizer.onBackPressedOnTaskRoot(task.getTaskInfo());
-            } catch (Exception e) {
-                Slog.e(TAG, "Exception sending onBackPressedOnTaskRoot callback", e);
-            }
+            mDeferTaskOrgCallbacksConsumer.accept(() -> {
+                if (!task.isOrganized()) {
+                    // This is safe to ignore if the task is no longer organized
+                    return;
+                }
+                try {
+                    mTaskOrganizer.onBackPressedOnTaskRoot(task.getTaskInfo());
+                } catch (Exception e) {
+                    Slog.e(TAG, "Exception sending onBackPressedOnTaskRoot callback", e);
+                }
+            });
         }
     }
 
@@ -251,34 +259,28 @@
             return mOrganizer.prepareLeash(t, t.isVisible(), reason);
         }
 
-        private boolean addTask(Task t) {
-            if (t.mTaskAppearedSent) {
-                return false;
-            }
+        void addTask(Task t) {
+            if (t.mTaskAppearedSent) return;
 
             if (!mOrganizedTasks.contains(t)) {
                 mOrganizedTasks.add(t);
             }
-
             if (t.taskAppearedReady()) {
                 t.mTaskAppearedSent = true;
-                return true;
+                mOrganizer.onTaskAppeared(t);
             }
-            return false;
         }
 
-        private boolean removeTask(Task t) {
-            mOrganizedTasks.remove(t);
-            mInterceptBackPressedOnRootTasks.remove(t.mTaskId);
-
+        void removeTask(Task t) {
             if (t.mTaskAppearedSent) {
                 if (t.getSurfaceControl() != null) {
                     t.migrateToNewSurfaceControl();
                 }
                 t.mTaskAppearedSent = false;
-                return true;
+                mOrganizer.onTaskVanished(t);
             }
-            return false;
+            mOrganizedTasks.remove(t);
+            mInterceptBackPressedOnRootTasks.remove(t.mTaskId);
         }
 
         void dispose() {
@@ -290,7 +292,7 @@
             while (!mOrganizedTasks.isEmpty()) {
                 final Task t = mOrganizedTasks.get(0);
                 if (!t.updateTaskOrganizerState(true /* forceUpdate */)) {
-                    TaskOrganizerController.this.onTaskVanished(mOrganizer.mTaskOrganizer, t);
+                    removeTask(t);
                 }
             }
 
@@ -304,33 +306,6 @@
         }
     }
 
-    static class PendingTaskEvent {
-        static final int EVENT_APPEARED = 0;
-        static final int EVENT_VANISHED = 1;
-        static final int EVENT_INFO_CHANGED = 2;
-        static final int EVENT_ROOT_BACK_PRESSED = 3;
-
-        final int mEventType;
-        final Task mTask;
-        final ITaskOrganizer mTaskOrg;
-        boolean mForce;
-
-        PendingTaskEvent(Task task, int event) {
-            this(task, task.mTaskOrganizer, event);
-        }
-
-        PendingTaskEvent(Task task, ITaskOrganizer taskOrg, int eventType) {
-            mTask = task;
-            mTaskOrg = taskOrg;
-            mEventType = eventType;
-        }
-
-        boolean isLifecycleEvent() {
-            return mEventType == EVENT_APPEARED || mEventType == EVENT_VANISHED
-                    || mEventType == EVENT_INFO_CHANGED;
-        }
-    }
-
     private final ActivityTaskManagerService mService;
     private final WindowManagerGlobalLock mGlobalLock;
 
@@ -338,8 +313,7 @@
     private final LinkedList<ITaskOrganizer> mTaskOrganizers = new LinkedList<>();
     private final HashMap<IBinder, TaskOrganizerState> mTaskOrganizerStates = new HashMap<>();
     private final WeakHashMap<Task, RunningTaskInfo> mLastSentTaskInfos = new WeakHashMap<>();
-    // Pending task events due to layout deferred.
-    private final ArrayList<PendingTaskEvent> mPendingTaskEvents = new ArrayList<>();
+    private final ArrayList<Task> mPendingTaskInfoChanges = new ArrayList<>();
     // Set of organized tasks (by taskId) that dispatch back pressed to their organizers
     private final HashSet<Integer> mInterceptBackPressedOnRootTasks = new HashSet();
 
@@ -364,12 +338,6 @@
     public void setDeferTaskOrgCallbacksConsumer(Consumer<Runnable> consumer) {
         mDeferTaskOrgCallbacksConsumer = consumer;
     }
-
-    @VisibleForTesting
-    ArrayList<PendingTaskEvent> getPendingEventList() {
-        return mPendingTaskEvents;
-    }
-
     /**
      * Register a TaskOrganizer to manage tasks as they enter the a supported windowing mode.
      */
@@ -475,33 +443,13 @@
 
     void onTaskAppeared(ITaskOrganizer organizer, Task task) {
         final TaskOrganizerState state = mTaskOrganizerStates.get(organizer.asBinder());
-        if (state != null && state.addTask(task)) {
-            PendingTaskEvent pending = getPendingTaskEvent(task, PendingTaskEvent.EVENT_APPEARED);
-            if (pending == null) {
-                pending = new PendingTaskEvent(task, PendingTaskEvent.EVENT_APPEARED);
-                mPendingTaskEvents.add(pending);
-            }
-        }
+        state.addTask(task);
     }
 
     void onTaskVanished(ITaskOrganizer organizer, Task task) {
         final TaskOrganizerState state = mTaskOrganizerStates.get(organizer.asBinder());
-        if (state != null && state.removeTask(task)) {
-            for (int i = mPendingTaskEvents.size() - 1; i >= 0; i--) {
-                PendingTaskEvent entry = mPendingTaskEvents.get(i);
-                if (task.mTaskId == entry.mTask.mTaskId) {
-                    // This task will vanished so remove all pending event of it.
-                    mPendingTaskEvents.remove(i);
-                    if (entry.mEventType == PendingTaskEvent.EVENT_APPEARED) {
-                        // If task still not appeared, ignore this callback.
-                        return;
-                    }
-                }
-            }
-
-            PendingTaskEvent pending =
-                    new PendingTaskEvent(task, organizer, PendingTaskEvent.EVENT_VANISHED);
-            mPendingTaskEvents.add(pending);
+        if (state != null) {
+            state.removeTask(task);
         }
     }
 
@@ -566,76 +514,30 @@
         }
     }
 
-    void dispatchPendingEvents() {
-        if (mService.mWindowManager.mWindowPlacerLocked.isLayoutDeferred()
-                || mPendingTaskEvents.isEmpty()) {
+    void dispatchPendingTaskInfoChanges() {
+        if (mService.mWindowManager.mWindowPlacerLocked.isLayoutDeferred()) {
             return;
         }
-
-        for (int i = 0, n = mPendingTaskEvents.size(); i < n; i++) {
-            PendingTaskEvent event = mPendingTaskEvents.get(i);
-            final Task task = event.mTask;
-            final TaskOrganizerState state;
-            switch (event.mEventType) {
-                case PendingTaskEvent.EVENT_APPEARED:
-                    state = mTaskOrganizerStates.get(event.mTaskOrg.asBinder());
-                    if (state != null && task.taskAppearedReady()) {
-                        state.mOrganizer.onTaskAppeared(task);
-                    }
-                    break;
-                case PendingTaskEvent.EVENT_VANISHED:
-                    state = mTaskOrganizerStates.get(event.mTaskOrg.asBinder());
-                    if (state != null) {
-                        state.mOrganizer.onTaskVanished(task);
-                    }
-                    break;
-                case PendingTaskEvent.EVENT_INFO_CHANGED:
-                    dispatchTaskInfoChanged(event.mTask, event.mForce);
-                    break;
-                case PendingTaskEvent.EVENT_ROOT_BACK_PRESSED:
-                    state = mTaskOrganizerStates.get(event.mTaskOrg.asBinder());
-                    if (state != null) {
-                        state.mOrganizer.onBackPressedOnTaskRoot(task);
-                    }
-                    break;
-            }
+        for (int i = 0, n = mPendingTaskInfoChanges.size(); i < n; ++i) {
+            dispatchTaskInfoChanged(mPendingTaskInfoChanges.get(i), false /* force */);
         }
-        mPendingTaskEvents.clear();
+        mPendingTaskInfoChanges.clear();
     }
 
-    void onTaskInfoChanged(Task task, boolean force) {
-        if (!task.mTaskAppearedSent) {
-            // Skip if task still not appeared.
+    void dispatchTaskInfoChanged(Task task, boolean force) {
+        if (!force && mService.mWindowManager.mWindowPlacerLocked.isLayoutDeferred()) {
+            // Defer task info reporting while layout is deferred. This is because layout defer
+            // blocks tend to do lots of re-ordering which can mess up animations in receivers.
+            mPendingTaskInfoChanges.remove(task);
+            mPendingTaskInfoChanges.add(task);
             return;
         }
-
-        // Defer task info reporting while layout is deferred. This is because layout defer
-        // blocks tend to do lots of re-ordering which can mess up animations in receivers.
-        PendingTaskEvent pending = getPendingLifecycleTaskEvent(task);
-        if (pending == null) {
-            pending = new PendingTaskEvent(task, PendingTaskEvent.EVENT_INFO_CHANGED);
-        } else {
-            if (pending.mEventType != PendingTaskEvent.EVENT_INFO_CHANGED) {
-                // If queued event is appeared, it means task still not appeared so ignore
-                // this info changed. If queued event is vanished, it means task should
-                // will vanished early so do not need this info changed.
-                return;
-            }
-            // Remove and add for re-ordering.
-            mPendingTaskEvents.remove(pending);
-        }
-        pending.mForce = force;
-        mPendingTaskEvents.add(pending);
-    }
-
-    private void dispatchTaskInfoChanged(Task task, boolean force) {
         RunningTaskInfo lastInfo = mLastSentTaskInfos.get(task);
         if (mTmpTaskInfo == null) {
             mTmpTaskInfo = new RunningTaskInfo();
         }
         mTmpTaskInfo.configuration.unset();
         task.fillTaskInfo(mTmpTaskInfo);
-
         boolean changed = !mTmpTaskInfo.equalsForTaskOrganizer(lastInfo);
         if (!changed) {
             int cfgChanges = mTmpTaskInfo.configuration.diff(lastInfo.configuration);
@@ -837,48 +739,11 @@
             return false;
         }
 
-        PendingTaskEvent pendingVanished =
-                getPendingTaskEvent(task, PendingTaskEvent.EVENT_VANISHED);
-        if (pendingVanished != null) {
-            // This task will vanish before this callback so just ignore.
-            return false;
-        }
-
-        PendingTaskEvent pending = getPendingTaskEvent(
-                task, PendingTaskEvent.EVENT_ROOT_BACK_PRESSED);
-        if (pending == null) {
-            pending = new PendingTaskEvent(task, PendingTaskEvent.EVENT_ROOT_BACK_PRESSED);
-        } else {
-            // Pending already exist, remove and add for re-ordering.
-            mPendingTaskEvents.remove(pending);
-        }
-        mPendingTaskEvents.add(pending);
+        final TaskOrganizerState state = mTaskOrganizerStates.get(task.mTaskOrganizer.asBinder());
+        state.mOrganizer.onBackPressedOnTaskRoot(task);
         return true;
     }
 
-    @Nullable
-    private PendingTaskEvent getPendingTaskEvent(Task task, int type) {
-        for (int i = mPendingTaskEvents.size() - 1; i >= 0; i--) {
-            PendingTaskEvent entry = mPendingTaskEvents.get(i);
-            if (task.mTaskId == entry.mTask.mTaskId && type == entry.mEventType) {
-                return entry;
-            }
-        }
-        return null;
-    }
-
-    @VisibleForTesting
-    @Nullable
-    PendingTaskEvent getPendingLifecycleTaskEvent(Task task) {
-        for (int i = mPendingTaskEvents.size() - 1; i >= 0; i--) {
-            PendingTaskEvent entry = mPendingTaskEvents.get(i);
-            if (task.mTaskId == entry.mTask.mTaskId && entry.isLifecycleEvent()) {
-                return entry;
-            }
-        }
-        return null;
-    }
-
     public void dump(PrintWriter pw, String prefix) {
         final String innerPrefix = prefix + "  ";
         pw.print(prefix); pw.println("TaskOrganizerController:");
diff --git a/services/core/java/com/android/server/wm/TaskSnapshotSurface.java b/services/core/java/com/android/server/wm/TaskSnapshotSurface.java
index d5e4dac..8c458a2 100644
--- a/services/core/java/com/android/server/wm/TaskSnapshotSurface.java
+++ b/services/core/java/com/android/server/wm/TaskSnapshotSurface.java
@@ -49,7 +49,6 @@
 
 import android.annotation.Nullable;
 import android.app.ActivityManager.TaskDescription;
-import android.window.TaskSnapshot;
 import android.app.ActivityThread;
 import android.content.Context;
 import android.graphics.Canvas;
@@ -78,6 +77,7 @@
 import android.view.WindowManager;
 import android.view.WindowManagerGlobal;
 import android.window.ClientWindowFrames;
+import android.window.TaskSnapshot;
 
 import com.android.internal.R;
 import com.android.internal.annotations.VisibleForTesting;
@@ -100,7 +100,7 @@
      * with a window with the exact same dimensions etc. However, these flags are not used in layout
      * and might cause other side effects so we exclude them.
      */
-    private static final int FLAG_INHERIT_EXCLUDES = FLAG_NOT_FOCUSABLE
+    static final int FLAG_INHERIT_EXCLUDES = FLAG_NOT_FOCUSABLE
             | FLAG_NOT_TOUCHABLE
             | FLAG_NOT_TOUCH_MODAL
             | FLAG_ALT_FOCUSABLE_IM
@@ -180,34 +180,10 @@
         synchronized (service.mGlobalLock) {
             final WindowState mainWindow = activity.findMainWindow();
             final Task task = activity.getTask();
-            if (task == null) {
-                Slog.w(TAG, "TaskSnapshotSurface.create: Failed to find task for activity="
-                        + activity);
-                return null;
-            }
             final ActivityRecord topFullscreenActivity =
                     activity.getTask().getTopFullscreenActivity();
-            if (topFullscreenActivity == null) {
-                Slog.w(TAG, "TaskSnapshotSurface.create: Failed to find top fullscreen for task="
-                        + task);
-                return null;
-            }
+            // Already check the nullity in StartingSurfaceController#createTaskSnapshotSurface
             topFullscreenOpaqueWindow = topFullscreenActivity.getTopFullscreenOpaqueWindow();
-            if (mainWindow == null || topFullscreenOpaqueWindow == null) {
-                Slog.w(TAG, "TaskSnapshotSurface.create: Failed to find main window for activity="
-                        + activity);
-                return null;
-            }
-            if (topFullscreenActivity.getWindowConfiguration().getRotation()
-                    != snapshot.getRotation()) {
-                // The snapshot should have been checked by ActivityRecord#isSnapshotCompatible
-                // that the activity will be updated to the same rotation as the snapshot. Since
-                // the transition is not started yet, fixed rotation transform needs to be applied
-                // earlier to make the snapshot show in a rotated container.
-                activity.mDisplayContent.handleTopActivityLaunchingInDifferentOrientation(
-                        topFullscreenActivity, false /* checkOpening */);
-            }
-
             WindowManager.LayoutParams attrs = topFullscreenOpaqueWindow.mAttrs;
             appearance = attrs.insetsFlags.appearance;
             windowFlags = attrs.flags;
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index d310260..1805ddd 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -2624,16 +2624,24 @@
         // events can slip to activity from letterbox.
         mActivityRecord.getLetterboxInnerBounds(mTmpRect);
         if (mTmpRect.isEmpty()) {
-            // If this is a modal window we need to dismiss it if it's not full screen
-            // and the touch happens outside of the frame that displays the content. This
-            // means we need to intercept touches outside of that window. The dim layer
-            // user associated with the window (task or stack) will give us the good
-            // bounds, as they would be used to display the dim layer.
-            final Task task = getTask();
-            if (task != null) {
-                task.getDimBounds(mTmpRect);
-            } else if (getRootTask() != null) {
-                getRootTask().getDimBounds(mTmpRect);
+            final Rect transformedBounds = mActivityRecord.getFixedRotationTransformDisplayBounds();
+            if (transformedBounds != null) {
+                // Task is in the same orientation as display, so the rotated bounds should be
+                // chosen as the touchable region. Then when the surface layer transforms the
+                // region to display space, the orientation will be consistent.
+                mTmpRect.set(transformedBounds);
+            } else {
+                // If this is a modal window we need to dismiss it if it's not full screen
+                // and the touch happens outside of the frame that displays the content. This
+                // means we need to intercept touches outside of that window. The dim layer
+                // user associated with the window (task or stack) will give us the good
+                // bounds, as they would be used to display the dim layer.
+                final Task task = getTask();
+                if (task != null) {
+                    task.getDimBounds(mTmpRect);
+                } else if (getRootTask() != null) {
+                    getRootTask().getDimBounds(mTmpRect);
+                }
             }
         }
         adjustRegionInFreefromWindowMode(mTmpRect);
@@ -5229,14 +5237,17 @@
         if (!mAnimatingExit && mAppDied) {
             mIsDimming = true;
             getDimmer().dimAbove(getSyncTransaction(), this, DEFAULT_DIM_AMOUNT_DEAD_WINDOW);
-        } else if ((mAttrs.flags & FLAG_DIM_BEHIND) != 0 && isVisibleNow() && !mHidden) {
-            // Only show a dim behind when the following is satisfied:
-            // 1. The window has the flag FLAG_DIM_BEHIND
+        } else if (((mAttrs.flags & FLAG_DIM_BEHIND) != 0 || mAttrs.backgroundBlurRadius != 0)
+                   && isVisibleNow() && !mHidden) {
+            // Only show the Dimmer when the following is satisfied:
+            // 1. The window has the flag FLAG_DIM_BEHIND or background blur is requested
             // 2. The WindowToken is not hidden so dims aren't shown when the window is exiting.
             // 3. The WS is considered visible according to the isVisible() method
             // 4. The WS is not hidden.
             mIsDimming = true;
-            getDimmer().dimBelow(getSyncTransaction(), this, mAttrs.dimAmount);
+            final float dimAmount = (mAttrs.flags & FLAG_DIM_BEHIND) != 0 ? mAttrs.dimAmount : 0;
+            getDimmer().dimBelow(
+                    getSyncTransaction(), this, mAttrs.dimAmount, mAttrs.backgroundBlurRadius);
         }
     }
 
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index badfe96..585db1e 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -802,7 +802,6 @@
 
         if (displayed) {
             w.mToken.hasVisible = true;
-            mSurfaceController.setBackgroundBlurRadius(w.mAttrs.backgroundBlurRadius);
         }
     }
 
diff --git a/services/core/java/com/android/server/wm/WindowSurfaceController.java b/services/core/java/com/android/server/wm/WindowSurfaceController.java
index 788f004..f59eba9 100644
--- a/services/core/java/com/android/server/wm/WindowSurfaceController.java
+++ b/services/core/java/com/android/server/wm/WindowSurfaceController.java
@@ -64,8 +64,6 @@
     private float mLastDsdy = 0;
     private float mLastDtdy = 1;
 
-    private int mLastBackgroundBlurRadius = 0;
-
     private float mSurfaceAlpha = 0;
 
     private int mSurfaceLayer = 0;
@@ -242,26 +240,6 @@
         }
     }
 
-    void setBackgroundBlurRadius(int radius) {
-        ProtoLog.i(WM_SHOW_TRANSACTIONS, "SURFACE backgroundBlur=%o: %s", radius, title);
-
-        if (mSurfaceControl == null || radius == mLastBackgroundBlurRadius) {
-            return;
-        }
-        mLastBackgroundBlurRadius = radius;
-
-        if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG, ">>> OPEN TRANSACTION setBackgroundBlurRadius");
-        mService.openSurfaceTransaction();
-        try {
-            getGlobalTransaction().setBackgroundBlurRadius(mSurfaceControl, radius);
-        } finally {
-            mService.closeSurfaceTransaction("setBackgroundBlurRadius");
-            if (SHOW_LIGHT_TRANSACTIONS) {
-                Slog.i(TAG, "<<< CLOSE TRANSACTION setBackgroundBlurRadius");
-            }
-        }
-    }
-
     void setSecure(boolean isSecure) {
         ProtoLog.i(WM_SHOW_TRANSACTIONS, "SURFACE isSecure=%b: %s", isSecure, title);
 
diff --git a/services/core/jni/Android.bp b/services/core/jni/Android.bp
index 2c4eb1b..77ca4e9 100644
--- a/services/core/jni/Android.bp
+++ b/services/core/jni/Android.bp
@@ -40,6 +40,7 @@
         "com_android_server_locksettings_SyntheticPasswordManager.cpp",
         "com_android_server_net_NetworkStatsService.cpp",
         "com_android_server_power_PowerManagerService.cpp",
+        "com_android_server_powerstats_PowerStatsService.cpp",
         "com_android_server_security_VerityUtils.cpp",
         "com_android_server_SerialService.cpp",
         "com_android_server_soundtrigger_middleware_AudioSessionProviderImpl.cpp",
diff --git a/services/core/jni/OWNERS b/services/core/jni/OWNERS
index 7fc5565..995cfe9 100644
--- a/services/core/jni/OWNERS
+++ b/services/core/jni/OWNERS
@@ -23,6 +23,7 @@
 per-file com_android_server_net_* = file:/services/core/java/com/android/server/net/OWNERS
 per-file com_android_server_pm_* = file:/services/core/java/com/android/server/pm/OWNERS
 per-file com_android_server_power_* = file:/services/core/java/com/android/server/power/OWNERS
+per-file com_android_server_powerstats_* = file:/services/core/java/com/android/server/powerstats/OWNERS
 per-file com_android_server_se_* = file:/core/java/android/se/OWNERS
 per-file com_android_server_security_* = file:/core/java/android/security/OWNERS
 per-file com_android_server_tv_* = file:/media/java/android/media/tv/OWNERS
diff --git a/services/core/jni/com_android_server_input_InputManagerService.cpp b/services/core/jni/com_android_server_input_InputManagerService.cpp
index 27634bf..57d28ba 100644
--- a/services/core/jni/com_android_server_input_InputManagerService.cpp
+++ b/services/core/jni/com_android_server_input_InputManagerService.cpp
@@ -62,11 +62,11 @@
 #include <nativehelper/ScopedPrimitiveArray.h>
 #include <nativehelper/ScopedUtfChars.h>
 
-#include "com_android_server_power_PowerManagerService.h"
+#include "android_hardware_display_DisplayViewport.h"
 #include "android_hardware_input_InputApplicationHandle.h"
 #include "android_hardware_input_InputWindowHandle.h"
-#include "android_hardware_display_DisplayViewport.h"
 #include "android_util_Binder.h"
+#include "com_android_server_power_PowerManagerService.h"
 
 #include <vector>
 
@@ -101,6 +101,8 @@
     jmethodID notifyConnectionUnresponsive;
     jmethodID notifyConnectionResponsive;
     jmethodID notifyFocusChanged;
+    jmethodID notifySensorEvent;
+    jmethodID notifySensorAccuracy;
     jmethodID notifyUntrustedTouch;
     jmethodID filterInputEvent;
     jmethodID interceptKeyBeforeQueueing;
@@ -157,6 +159,29 @@
     jmethodID size;
 } gSparseArrayClassInfo;
 
+struct InputSensorInfoOffsets {
+    jclass clazz;
+    // fields
+    jfieldID name;
+    jfieldID vendor;
+    jfieldID version;
+    jfieldID handle;
+    jfieldID maxRange;
+    jfieldID resolution;
+    jfieldID power;
+    jfieldID minDelay;
+    jfieldID fifoReservedEventCount;
+    jfieldID fifoMaxEventCount;
+    jfieldID stringType;
+    jfieldID requiredPermission;
+    jfieldID maxDelay;
+    jfieldID flags;
+    jfieldID type;
+    jfieldID id;
+    // methods
+    jmethodID init;
+} gInputSensorInfo;
+
 // --- Global functions ---
 
 template<typename T>
@@ -224,7 +249,8 @@
                                                                    const std::string& name);
     base::Result<std::unique_ptr<InputChannel>> createInputMonitor(JNIEnv* env, int32_t displayId,
                                                                    bool isGestureMonitor,
-                                                                   const std::string& name);
+                                                                   const std::string& name,
+                                                                   int32_t pid);
     status_t removeInputChannel(JNIEnv* env, const sp<IBinder>& connectionToken);
     status_t pilferPointers(const sp<IBinder>& token);
 
@@ -267,6 +293,11 @@
     void notifyConnectionResponsive(const sp<IBinder>& token) override;
     void notifyInputChannelBroken(const sp<IBinder>& token) override;
     void notifyFocusChanged(const sp<IBinder>& oldToken, const sp<IBinder>& newToken) override;
+    void notifySensorEvent(int32_t deviceId, InputDeviceSensorType sensorType,
+                           InputDeviceSensorAccuracy accuracy, nsecs_t timestamp,
+                           const std::vector<float>& values) override;
+    void notifySensorAccuracy(int32_t deviceId, InputDeviceSensorType sensorType,
+                              InputDeviceSensorAccuracy accuracy) override;
     void notifyUntrustedTouch(const std::string& obscuringPackage) override;
     bool filterInputEvent(const InputEvent* inputEvent, uint32_t policyFlags) override;
     void getDispatcherConfiguration(InputDispatcherConfiguration* outConfig) override;
@@ -457,9 +488,11 @@
 }
 
 base::Result<std::unique_ptr<InputChannel>> NativeInputManager::createInputMonitor(
-        JNIEnv* /* env */, int32_t displayId, bool isGestureMonitor, const std::string& name) {
+        JNIEnv* /* env */, int32_t displayId, bool isGestureMonitor, const std::string& name,
+        int32_t pid) {
     ATRACE_CALL();
-    return mInputManager->getDispatcher()->createInputMonitor(displayId, isGestureMonitor, name);
+    return mInputManager->getDispatcher()->createInputMonitor(displayId, isGestureMonitor, name,
+                                                              pid);
 }
 
 status_t NativeInputManager::removeInputChannel(JNIEnv* /* env */,
@@ -820,6 +853,35 @@
     checkAndClearExceptionFromCallback(env, "notifyFocusChanged");
 }
 
+void NativeInputManager::notifySensorEvent(int32_t deviceId, InputDeviceSensorType sensorType,
+                                           InputDeviceSensorAccuracy accuracy, nsecs_t timestamp,
+                                           const std::vector<float>& values) {
+#if DEBUG_INPUT_DISPATCHER_POLICY
+    ALOGD("notifySensorEvent");
+#endif
+    ATRACE_CALL();
+    JNIEnv* env = jniEnv();
+    ScopedLocalFrame localFrame(env);
+    jfloatArray arr = env->NewFloatArray(values.size());
+    env->SetFloatArrayRegion(arr, 0, values.size(), values.data());
+    env->CallVoidMethod(mServiceObj, gServiceClassInfo.notifySensorEvent, deviceId,
+                        static_cast<jint>(sensorType), accuracy, timestamp, arr);
+    checkAndClearExceptionFromCallback(env, "notifySensorEvent");
+}
+
+void NativeInputManager::notifySensorAccuracy(int32_t deviceId, InputDeviceSensorType sensorType,
+                                              InputDeviceSensorAccuracy accuracy) {
+#if DEBUG_INPUT_DISPATCHER_POLICY
+    ALOGD("notifySensorAccuracy");
+#endif
+    ATRACE_CALL();
+    JNIEnv* env = jniEnv();
+    ScopedLocalFrame localFrame(env);
+    env->CallVoidMethod(mServiceObj, gServiceClassInfo.notifySensorAccuracy, deviceId,
+                        static_cast<jint>(sensorType), accuracy);
+    checkAndClearExceptionFromCallback(env, "notifySensorAccuracy");
+}
+
 void NativeInputManager::getDispatcherConfiguration(InputDispatcherConfiguration* outConfig) {
     ATRACE_CALL();
     JNIEnv* env = jniEnv();
@@ -1444,7 +1506,7 @@
 }
 
 static jobject nativeCreateInputMonitor(JNIEnv* env, jclass /* clazz */, jlong ptr, jint displayId,
-                                        jboolean isGestureMonitor, jstring nameObj) {
+                                        jboolean isGestureMonitor, jstring nameObj, jint pid) {
     NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
 
     if (displayId == ADISPLAY_ID_NONE) {
@@ -1457,7 +1519,7 @@
     std::string name = nameChars.c_str();
 
     base::Result<std::unique_ptr<InputChannel>> inputChannel =
-            im->createInputMonitor(env, displayId, isGestureMonitor, name);
+            im->createInputMonitor(env, displayId, isGestureMonitor, name, pid);
 
     if (!inputChannel) {
         std::string message = inputChannel.error().message();
@@ -1911,6 +1973,111 @@
     im->setMotionClassifierEnabled(enabled);
 }
 
+static jobject createInputSensorInfo(JNIEnv* env, jstring name, jstring vendor, jint version,
+                                     jint handle, jint type, jfloat maxRange, jfloat resolution,
+                                     jfloat power, jfloat minDelay, jint fifoReservedEventCount,
+                                     jint fifoMaxEventCount, jstring stringType,
+                                     jstring requiredPermission, jint maxDelay, jint flags,
+                                     jint id) {
+    // SensorInfo sensorInfo = new Sensor();
+    jobject sensorInfo = env->NewObject(gInputSensorInfo.clazz, gInputSensorInfo.init, "");
+
+    if (sensorInfo != NULL) {
+        env->SetObjectField(sensorInfo, gInputSensorInfo.name, name);
+        env->SetObjectField(sensorInfo, gInputSensorInfo.vendor, vendor);
+        env->SetIntField(sensorInfo, gInputSensorInfo.version, version);
+        env->SetIntField(sensorInfo, gInputSensorInfo.handle, handle);
+        env->SetFloatField(sensorInfo, gInputSensorInfo.maxRange, maxRange);
+        env->SetFloatField(sensorInfo, gInputSensorInfo.resolution, resolution);
+        env->SetFloatField(sensorInfo, gInputSensorInfo.power, power);
+        env->SetIntField(sensorInfo, gInputSensorInfo.minDelay, minDelay);
+        env->SetIntField(sensorInfo, gInputSensorInfo.fifoReservedEventCount,
+                         fifoReservedEventCount);
+        env->SetIntField(sensorInfo, gInputSensorInfo.fifoMaxEventCount, fifoMaxEventCount);
+        env->SetObjectField(sensorInfo, gInputSensorInfo.requiredPermission, requiredPermission);
+        env->SetIntField(sensorInfo, gInputSensorInfo.maxDelay, maxDelay);
+        env->SetIntField(sensorInfo, gInputSensorInfo.flags, flags);
+        env->SetObjectField(sensorInfo, gInputSensorInfo.stringType, stringType);
+        env->SetIntField(sensorInfo, gInputSensorInfo.type, type);
+        env->SetIntField(sensorInfo, gInputSensorInfo.id, id);
+    }
+    return sensorInfo;
+}
+
+static jobjectArray nativeGetSensorList(JNIEnv* env, jclass /* clazz */, jlong ptr, jint deviceId) {
+    NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
+    std::vector<InputDeviceInfo> devices = im->getInputManager()->getReader()->getInputDevices();
+    // Find the input device by deviceId
+    auto it = std::find_if(devices.begin(), devices.end(),
+                           [deviceId](InputDeviceInfo& info) { return info.getId() == deviceId; });
+
+    if (it == devices.end()) {
+        // Return an array of size 0
+        return env->NewObjectArray(0, gInputSensorInfo.clazz, nullptr);
+    }
+
+    std::vector<InputDeviceSensorType> types = it->getSensorTypes();
+    jobjectArray arr = env->NewObjectArray(types.size(), gInputSensorInfo.clazz, nullptr);
+    for (int i = 0; i < types.size(); i++) {
+        const InputDeviceSensorInfo* sensorInfo = it->getSensorInfo(types[i]);
+        if (sensorInfo == nullptr) {
+            ALOGW("Failed to get input device %d sensor info for type %s", deviceId,
+                  NamedEnum::string(types[i]).c_str());
+            continue;
+        }
+
+        jobject info =
+                createInputSensorInfo(env, env->NewStringUTF(sensorInfo->name.c_str()),
+                                      env->NewStringUTF(sensorInfo->vendor.c_str()),
+                                      (jint)sensorInfo->version, 0 /* handle */,
+                                      (jint)sensorInfo->type, (jfloat)sensorInfo->maxRange,
+                                      (jfloat)sensorInfo->resolution, (jfloat)sensorInfo->power,
+                                      (jfloat)sensorInfo->minDelay,
+                                      (jint)sensorInfo->fifoReservedEventCount,
+                                      (jint)sensorInfo->fifoMaxEventCount,
+                                      env->NewStringUTF(sensorInfo->stringType.c_str()),
+                                      env->NewStringUTF("") /* requiredPermission */,
+                                      (jint)sensorInfo->maxDelay, (jint)sensorInfo->flags,
+                                      (jint)sensorInfo->id);
+        env->SetObjectArrayElement(arr, i, info);
+        env->DeleteLocalRef(info);
+    }
+    return arr;
+}
+
+static jboolean nativeEnableSensor(JNIEnv* env, jclass /* clazz */, jlong ptr, jint deviceId,
+                                   jint sensorType, jint samplingPeriodUs,
+                                   jint maxBatchReportLatencyUs) {
+    NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
+
+    return im->getInputManager()
+            ->getReader()
+            ->enableSensor(deviceId, static_cast<InputDeviceSensorType>(sensorType),
+                           std::chrono::microseconds(samplingPeriodUs),
+                           std::chrono::microseconds(maxBatchReportLatencyUs));
+    return true;
+}
+
+static void nativeDisableSensor(JNIEnv* env, jclass /* clazz */, jlong ptr, jint deviceId,
+                                jint sensorType) {
+    NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
+
+    im->getInputManager()->getReader()->disableSensor(deviceId,
+                                                      static_cast<InputDeviceSensorType>(
+                                                              sensorType));
+}
+
+static jboolean nativeFlushSensor(JNIEnv* env, jclass /* clazz */, jlong ptr, jint deviceId,
+                                  jint sensorType) {
+    NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
+
+    im->getInputManager()->getReader()->flushSensor(deviceId,
+                                                    static_cast<InputDeviceSensorType>(sensorType));
+    return im->getInputManager()->getDispatcher()->flushSensor(deviceId,
+                                                               static_cast<InputDeviceSensorType>(
+                                                                       sensorType));
+}
+
 // ----------------------------------------------------------------------------
 
 static const JNINativeMethod gInputManagerMethods[] = {
@@ -1928,7 +2095,7 @@
         {"nativeHasKeys", "(JII[I[Z)Z", (void*)nativeHasKeys},
         {"nativeCreateInputChannel", "(JLjava/lang/String;)Landroid/view/InputChannel;",
          (void*)nativeCreateInputChannel},
-        {"nativeCreateInputMonitor", "(JIZLjava/lang/String;)Landroid/view/InputChannel;",
+        {"nativeCreateInputMonitor", "(JIZLjava/lang/String;I)Landroid/view/InputChannel;",
          (void*)nativeCreateInputMonitor},
         {"nativeRemoveInputChannel", "(JLandroid/os/IBinder;)V", (void*)nativeRemoveInputChannel},
         {"nativePilferPointers", "(JLandroid/os/IBinder;)V", (void*)nativePilferPointers},
@@ -1976,6 +2143,11 @@
         {"nativeCanDispatchToDisplay", "(JII)Z", (void*)nativeCanDispatchToDisplay},
         {"nativeNotifyPortAssociationsChanged", "(J)V", (void*)nativeNotifyPortAssociationsChanged},
         {"nativeSetMotionClassifierEnabled", "(JZ)V", (void*)nativeSetMotionClassifierEnabled},
+        {"nativeGetSensorList", "(JI)[Landroid/hardware/input/InputSensorInfo;",
+         (void*)nativeGetSensorList},
+        {"nativeEnableSensor", "(JIIII)Z", (void*)nativeEnableSensor},
+        {"nativeDisableSensor", "(JII)V", (void*)nativeDisableSensor},
+        {"nativeFlushSensor", "(JII)Z", (void*)nativeFlushSensor},
 };
 
 #define FIND_CLASS(var, className) \
@@ -2021,6 +2193,10 @@
     GET_METHOD_ID(gServiceClassInfo.notifyFocusChanged, clazz,
             "notifyFocusChanged", "(Landroid/os/IBinder;Landroid/os/IBinder;)V");
 
+    GET_METHOD_ID(gServiceClassInfo.notifySensorEvent, clazz, "notifySensorEvent", "(IIIJ[F)V");
+
+    GET_METHOD_ID(gServiceClassInfo.notifySensorAccuracy, clazz, "notifySensorAccuracy", "(III)V");
+
     GET_METHOD_ID(gServiceClassInfo.notifyUntrustedTouch, clazz, "notifyUntrustedTouch",
                   "(Ljava/lang/String;)V");
 
@@ -2145,6 +2321,33 @@
     GET_METHOD_ID(gSparseArrayClassInfo.valueAt, gSparseArrayClassInfo.clazz, "valueAt",
                   "(I)Ljava/lang/Object;");
     GET_METHOD_ID(gSparseArrayClassInfo.size, gSparseArrayClassInfo.clazz, "size", "()I");
+    // InputSensorInfo
+    // android.hardware.input.InputDeviceSensorInfo
+    FIND_CLASS(clazz, "android/hardware/input/InputSensorInfo");
+    gInputSensorInfo.clazz = reinterpret_cast<jclass>(env->NewGlobalRef(clazz));
+
+    GET_FIELD_ID(gInputSensorInfo.name, gInputSensorInfo.clazz, "mName", "Ljava/lang/String;");
+    GET_FIELD_ID(gInputSensorInfo.vendor, gInputSensorInfo.clazz, "mVendor", "Ljava/lang/String;");
+    GET_FIELD_ID(gInputSensorInfo.version, gInputSensorInfo.clazz, "mVersion", "I");
+    GET_FIELD_ID(gInputSensorInfo.handle, gInputSensorInfo.clazz, "mHandle", "I");
+    GET_FIELD_ID(gInputSensorInfo.maxRange, gInputSensorInfo.clazz, "mMaxRange", "F");
+    GET_FIELD_ID(gInputSensorInfo.resolution, gInputSensorInfo.clazz, "mResolution", "F");
+    GET_FIELD_ID(gInputSensorInfo.power, gInputSensorInfo.clazz, "mPower", "F");
+    GET_FIELD_ID(gInputSensorInfo.minDelay, gInputSensorInfo.clazz, "mMinDelay", "I");
+    GET_FIELD_ID(gInputSensorInfo.fifoReservedEventCount, gInputSensorInfo.clazz,
+                 "mFifoReservedEventCount", "I");
+    GET_FIELD_ID(gInputSensorInfo.fifoMaxEventCount, gInputSensorInfo.clazz, "mFifoMaxEventCount",
+                 "I");
+    GET_FIELD_ID(gInputSensorInfo.stringType, gInputSensorInfo.clazz, "mStringType",
+                 "Ljava/lang/String;");
+    GET_FIELD_ID(gInputSensorInfo.requiredPermission, gInputSensorInfo.clazz, "mRequiredPermission",
+                 "Ljava/lang/String;");
+    GET_FIELD_ID(gInputSensorInfo.maxDelay, gInputSensorInfo.clazz, "mMaxDelay", "I");
+    GET_FIELD_ID(gInputSensorInfo.flags, gInputSensorInfo.clazz, "mFlags", "I");
+    GET_FIELD_ID(gInputSensorInfo.type, gInputSensorInfo.clazz, "mType", "I");
+    GET_FIELD_ID(gInputSensorInfo.id, gInputSensorInfo.clazz, "mId", "I");
+
+    GET_METHOD_ID(gInputSensorInfo.init, gInputSensorInfo.clazz, "<init>", "()V");
 
     return 0;
 }
diff --git a/services/core/jni/com_android_server_powerstats_PowerStatsService.cpp b/services/core/jni/com_android_server_powerstats_PowerStatsService.cpp
new file mode 100644
index 0000000..f5b851f
--- /dev/null
+++ b/services/core/jni/com_android_server_powerstats_PowerStatsService.cpp
@@ -0,0 +1,440 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "PowerStatsService"
+
+#include <android/hardware/power/stats/1.0/IPowerStats.h>
+#include <jni.h>
+#include <nativehelper/JNIHelp.h>
+
+#include <log/log.h>
+
+using android::hardware::hidl_vec;
+using android::hardware::Return;
+using android::hardware::power::stats::V1_0::EnergyData;
+using android::hardware::power::stats::V1_0::RailInfo;
+using android::hardware::power::stats::V1_0::Status;
+
+// ChannelInfo
+static jclass class_CI;
+static jmethodID method_CI_init;
+static jfieldID field_CI_channelId;
+static jfieldID field_CI_channelName;
+
+// EnergyMeasurement
+static jclass class_EM;
+static jmethodID method_EM_init;
+static jfieldID field_EM_channelId;
+static jfieldID field_EM_timestampMs;
+static jfieldID field_EM_durationMs;
+static jfieldID field_EM_energyUWs;
+
+// StateInfo
+static jclass class_SI;
+static jmethodID method_SI_init;
+static jfieldID field_SI_stateId;
+static jfieldID field_SI_stateName;
+
+// PowerEntityInfo
+static jclass class_PEI;
+static jmethodID method_PEI_init;
+static jfieldID field_PEI_powerEntityId;
+static jfieldID field_PEI_powerEntityName;
+static jfieldID field_PEI_states;
+
+// StateResidency
+static jclass class_SR;
+static jmethodID method_SR_init;
+static jfieldID field_SR_stateId;
+static jfieldID field_SR_totalTimeInStateMs;
+static jfieldID field_SR_totalStateEntryCount;
+static jfieldID field_SR_lastEntryTimestampMs;
+
+// StateResidencyResult
+static jclass class_SRR;
+static jmethodID method_SRR_init;
+static jfieldID field_SRR_powerEntityId;
+static jfieldID field_SRR_stateResidencyData;
+
+namespace android {
+
+static std::mutex gPowerStatsHalMutex;
+static sp<android::hardware::power::stats::V1_0::IPowerStats> gPowerStatsHalV1_0_ptr = nullptr;
+
+static void deinitPowerStats() {
+    gPowerStatsHalV1_0_ptr = nullptr;
+}
+
+struct PowerStatsHalDeathRecipient : virtual public hardware::hidl_death_recipient {
+    virtual void serviceDied(uint64_t cookie,
+                             const wp<android::hidl::base::V1_0::IBase> &who) override {
+        // The HAL just died. Reset all handles to HAL services.
+        std::lock_guard<std::mutex> lock(gPowerStatsHalMutex);
+        deinitPowerStats();
+    }
+};
+
+sp<PowerStatsHalDeathRecipient> gPowerStatsHalDeathRecipient = new PowerStatsHalDeathRecipient();
+
+static bool connectToPowerStatsHal() {
+    if (gPowerStatsHalV1_0_ptr == nullptr) {
+        gPowerStatsHalV1_0_ptr = android::hardware::power::stats::V1_0::IPowerStats::getService();
+
+        if (gPowerStatsHalV1_0_ptr == nullptr) {
+            ALOGE("Unable to get power.stats HAL service.");
+            return false;
+        }
+
+        // Link death recipient to power.stats service handle
+        hardware::Return<bool> linked =
+                gPowerStatsHalV1_0_ptr->linkToDeath(gPowerStatsHalDeathRecipient, 0);
+        if (!linked.isOk()) {
+            ALOGE("Transaction error in linking to power.stats HAL death: %s",
+                  linked.description().c_str());
+            deinitPowerStats();
+            return false;
+        } else if (!linked) {
+            ALOGW("Unable to link to power.stats HAL death notifications");
+            return false;
+        }
+    }
+    return true;
+}
+
+static bool checkResult(const Return<void> &ret, const char *function) {
+    if (!ret.isOk()) {
+        ALOGE("%s failed: requested HAL service not available. Description: %s", function,
+              ret.description().c_str());
+        if (ret.isDeadObject()) {
+            deinitPowerStats();
+        }
+        return false;
+    }
+    return true;
+}
+
+static jobjectArray nativeGetPowerEntityInfo(JNIEnv *env, jclass clazz) {
+    std::lock_guard<std::mutex> lock(gPowerStatsHalMutex);
+
+    if (!connectToPowerStatsHal()) {
+        ALOGE("nativeGetPowerEntityInfo failed to connect to power.stats HAL");
+        return nullptr;
+    }
+
+    jobjectArray powerEntityInfoArray = nullptr;
+    Return<void> ret = gPowerStatsHalV1_0_ptr->getPowerEntityInfo(
+            [&env, &powerEntityInfoArray](auto infos, auto status) {
+                if (status != Status::SUCCESS) {
+                    ALOGE("Error getting power entity info");
+                } else {
+                    powerEntityInfoArray = env->NewObjectArray(infos.size(), class_PEI, nullptr);
+                    for (int i = 0; i < infos.size(); i++) {
+                        jstring powerEntityName =
+                                env->NewStringUTF(infos[i].powerEntityName.c_str());
+                        jobject powerEntityInfo = env->NewObject(class_PEI, method_PEI_init);
+                        env->SetIntField(powerEntityInfo, field_PEI_powerEntityId,
+                                         infos[i].powerEntityId);
+                        env->SetObjectField(powerEntityInfo, field_PEI_powerEntityName,
+                                            powerEntityName);
+                        env->SetObjectArrayElement(powerEntityInfoArray, i, powerEntityInfo);
+                        env->DeleteLocalRef(powerEntityName);
+                        env->DeleteLocalRef(powerEntityInfo);
+                    }
+                }
+            });
+    if (!checkResult(ret, __func__)) {
+        return nullptr;
+    }
+
+    ret = gPowerStatsHalV1_0_ptr->getPowerEntityStateInfo(
+            {}, [&env, &powerEntityInfoArray](auto infos, auto status) {
+                if (status != Status::SUCCESS) {
+                    ALOGE("Error getting power entity state info");
+                } else {
+                    for (int i = 0; i < infos.size(); i++) {
+                        jobjectArray stateInfoArray =
+                                env->NewObjectArray(infos[i].states.size(), class_SI, nullptr);
+                        for (int j = 0; j < infos[i].states.size(); j++) {
+                            jstring powerEntityStateName = env->NewStringUTF(
+                                    infos[i].states[j].powerEntityStateName.c_str());
+                            jobject stateInfo = env->NewObject(class_SI, method_SI_init);
+                            env->SetIntField(stateInfo, field_SI_stateId,
+                                             infos[i].states[j].powerEntityStateId);
+                            env->SetObjectField(stateInfo, field_SI_stateName,
+                                                powerEntityStateName);
+                            env->SetObjectArrayElement(stateInfoArray, j, stateInfo);
+                            env->DeleteLocalRef(powerEntityStateName);
+                            env->DeleteLocalRef(stateInfo);
+                        }
+
+                        for (int j = 0; j < env->GetArrayLength(powerEntityInfoArray); j++) {
+                            jobject powerEntityInfo =
+                                    env->GetObjectArrayElement(powerEntityInfoArray, j);
+                            if (env->GetIntField(powerEntityInfo, field_PEI_powerEntityId) ==
+                                infos[i].powerEntityId) {
+                                env->SetObjectField(powerEntityInfo, field_PEI_states,
+                                                    stateInfoArray);
+                                env->SetObjectArrayElement(powerEntityInfoArray, j,
+                                                           powerEntityInfo);
+                                break;
+                            }
+                        }
+                    }
+                }
+            });
+    if (!checkResult(ret, __func__)) {
+        return nullptr;
+    }
+
+    return powerEntityInfoArray;
+}
+
+static jobjectArray nativeGetStateResidency(JNIEnv *env, jclass clazz, jintArray powerEntityIds) {
+    std::lock_guard<std::mutex> lock(gPowerStatsHalMutex);
+
+    if (!connectToPowerStatsHal()) {
+        ALOGE("nativeGetStateResidency failed to connect to power.stats HAL");
+        return nullptr;
+    }
+
+    size_t powerEntityIdCount = env->GetArrayLength(powerEntityIds);
+    hidl_vec<uint32_t> powerEntityIdVector(powerEntityIdCount);
+
+    jint *powerEntityIdElements = env->GetIntArrayElements(powerEntityIds, 0);
+    for (int i = 0; i < powerEntityIdCount; i++) {
+        powerEntityIdVector[i] = powerEntityIdElements[i];
+    }
+    env->ReleaseIntArrayElements(powerEntityIds, powerEntityIdElements, 0);
+
+    jobjectArray stateResidencyResultArray = nullptr;
+    Return<void> ret = gPowerStatsHalV1_0_ptr->getPowerEntityStateResidencyData(
+            powerEntityIdVector, [&env, &stateResidencyResultArray](auto results, auto status) {
+                if (status != Status::SUCCESS) {
+                    ALOGE("Error getting power entity state residency data");
+                } else {
+                    stateResidencyResultArray =
+                            env->NewObjectArray(results.size(), class_SRR, nullptr);
+                    for (int i = 0; i < results.size(); i++) {
+                        jobjectArray stateResidencyArray =
+                                env->NewObjectArray(results[i].stateResidencyData.size(), class_SR,
+                                                    nullptr);
+                        for (int j = 0; j < results[i].stateResidencyData.size(); j++) {
+                            jobject stateResidency = env->NewObject(class_SR, method_SR_init);
+                            env->SetIntField(stateResidency, field_SR_stateId,
+                                             results[i].stateResidencyData[j].powerEntityStateId);
+                            env->SetLongField(stateResidency, field_SR_totalTimeInStateMs,
+                                              results[i].stateResidencyData[j].totalTimeInStateMs);
+                            env->SetLongField(stateResidency, field_SR_totalStateEntryCount,
+                                              results[i]
+                                                      .stateResidencyData[j]
+                                                      .totalStateEntryCount);
+                            env->SetLongField(stateResidency, field_SR_lastEntryTimestampMs,
+                                              results[i]
+                                                      .stateResidencyData[j]
+                                                      .lastEntryTimestampMs);
+                            env->SetObjectArrayElement(stateResidencyArray, j, stateResidency);
+                            env->DeleteLocalRef(stateResidency);
+                        }
+                        jobject stateResidencyResult = env->NewObject(class_SRR, method_SRR_init);
+                        env->SetIntField(stateResidencyResult, field_SRR_powerEntityId,
+                                         results[i].powerEntityId);
+                        env->SetObjectField(stateResidencyResult, field_SRR_stateResidencyData,
+                                            stateResidencyArray);
+                        env->SetObjectArrayElement(stateResidencyResultArray, i,
+                                                   stateResidencyResult);
+                        env->DeleteLocalRef(stateResidencyResult);
+                    }
+                }
+            });
+    if (!checkResult(ret, __func__)) {
+        return nullptr;
+    }
+
+    return stateResidencyResultArray;
+}
+
+static jobjectArray nativeGetEnergyMeterInfo(JNIEnv *env, jclass clazz) {
+    std::lock_guard<std::mutex> lock(gPowerStatsHalMutex);
+
+    if (!connectToPowerStatsHal()) {
+        ALOGE("nativeGetEnergyMeterInfo failed to connect to power.stats HAL");
+        return nullptr;
+    }
+
+    jobjectArray channelInfoArray = nullptr;
+    Return<void> ret = gPowerStatsHalV1_0_ptr->getRailInfo(
+            [&env, &channelInfoArray](auto railInfo, auto status) {
+                if (status != Status::SUCCESS) {
+                    ALOGW("Error getting rail info");
+                } else {
+                    channelInfoArray = env->NewObjectArray(railInfo.size(), class_CI, nullptr);
+                    for (int i = 0; i < railInfo.size(); i++) {
+                        jstring channelName = env->NewStringUTF(railInfo[i].railName.c_str());
+                        jobject channelInfo = env->NewObject(class_CI, method_CI_init);
+                        env->SetIntField(channelInfo, field_CI_channelId, railInfo[i].index);
+                        env->SetObjectField(channelInfo, field_CI_channelName, channelName);
+                        env->SetObjectArrayElement(channelInfoArray, i, channelInfo);
+                        env->DeleteLocalRef(channelName);
+                        env->DeleteLocalRef(channelInfo);
+                    }
+                }
+            });
+
+    if (!checkResult(ret, __func__)) {
+        ALOGE("getRailInfo failed");
+        return nullptr;
+    }
+
+    return channelInfoArray;
+}
+
+static jobjectArray nativeReadEnergyMeters(JNIEnv *env, jclass clazz, jintArray channelIds) {
+    std::lock_guard<std::mutex> lock(gPowerStatsHalMutex);
+
+    if (!connectToPowerStatsHal()) {
+        ALOGE("nativeGetEnergy failed to connect to power.stats HAL");
+    }
+
+    size_t channelIdCount = env->GetArrayLength(channelIds);
+    hidl_vec<uint32_t> channelIdVector(channelIdCount);
+
+    jint *channelIdElements = env->GetIntArrayElements(channelIds, 0);
+    for (int i = 0; i < channelIdCount; i++) {
+        channelIdVector[i] = channelIdElements[i];
+    }
+    env->ReleaseIntArrayElements(channelIds, channelIdElements, 0);
+
+    jobjectArray energyMeasurementArray = nullptr;
+    Return<void> ret =
+            gPowerStatsHalV1_0_ptr
+                    ->getEnergyData(channelIdVector,
+                                    [&env, &energyMeasurementArray](auto energyData, auto status) {
+                                        if (status != Status::SUCCESS) {
+                                            ALOGW("Error getting energy data");
+                                        } else {
+                                            energyMeasurementArray =
+                                                    env->NewObjectArray(energyData.size(), class_EM,
+                                                                        nullptr);
+                                            for (int i = 0; i < energyData.size(); i++) {
+                                                jobject energyMeasurement =
+                                                        env->NewObject(class_EM, method_EM_init);
+                                                env->SetIntField(energyMeasurement,
+                                                                 field_EM_channelId,
+                                                                 energyData[i].index);
+                                                env->SetLongField(energyMeasurement,
+                                                                  field_EM_timestampMs,
+                                                                  energyData[i].timestamp);
+                                                env->SetLongField(energyMeasurement,
+                                                                  field_EM_durationMs, -1);
+                                                env->SetLongField(energyMeasurement,
+                                                                  field_EM_energyUWs,
+                                                                  energyData[i].energy);
+                                                env->SetObjectArrayElement(energyMeasurementArray,
+                                                                           i, energyMeasurement);
+                                                env->DeleteLocalRef(energyMeasurement);
+                                            }
+                                        }
+                                    });
+
+    if (!checkResult(ret, __func__)) {
+        ALOGE("getEnergyData failed");
+        return nullptr;
+    }
+
+    return energyMeasurementArray;
+}
+
+static jboolean nativeInit(JNIEnv *env, jclass clazz) {
+    std::lock_guard<std::mutex> lock(gPowerStatsHalMutex);
+
+    // ChannelInfo
+    jclass temp = env->FindClass("android/hardware/power/stats/ChannelInfo");
+    class_CI = (jclass)env->NewGlobalRef(temp);
+    method_CI_init = env->GetMethodID(class_CI, "<init>", "()V");
+    field_CI_channelId = env->GetFieldID(class_CI, "channelId", "I");
+    field_CI_channelName = env->GetFieldID(class_CI, "channelName", "Ljava/lang/String;");
+
+    // EnergyMeasurement
+    temp = env->FindClass("android/hardware/power/stats/EnergyMeasurement");
+    class_EM = (jclass)env->NewGlobalRef(temp);
+    method_EM_init = env->GetMethodID(class_EM, "<init>", "()V");
+    field_EM_channelId = env->GetFieldID(class_EM, "channelId", "I");
+    field_EM_timestampMs = env->GetFieldID(class_EM, "timestampMs", "J");
+    field_EM_durationMs = env->GetFieldID(class_EM, "durationMs", "J");
+    field_EM_energyUWs = env->GetFieldID(class_EM, "energyUWs", "J");
+
+    // StateInfo
+    temp = env->FindClass("android/hardware/power/stats/StateInfo");
+    class_SI = (jclass)env->NewGlobalRef(temp);
+    method_SI_init = env->GetMethodID(class_SI, "<init>", "()V");
+    field_SI_stateId = env->GetFieldID(class_SI, "stateId", "I");
+    field_SI_stateName = env->GetFieldID(class_SI, "stateName", "Ljava/lang/String;");
+
+    // PowerEntityInfo
+    temp = env->FindClass("android/hardware/power/stats/PowerEntityInfo");
+    class_PEI = (jclass)env->NewGlobalRef(temp);
+    method_PEI_init = env->GetMethodID(class_PEI, "<init>", "()V");
+    field_PEI_powerEntityId = env->GetFieldID(class_PEI, "powerEntityId", "I");
+    field_PEI_powerEntityName = env->GetFieldID(class_PEI, "powerEntityName", "Ljava/lang/String;");
+    field_PEI_states =
+            env->GetFieldID(class_PEI, "states", "[Landroid/hardware/power/stats/StateInfo;");
+
+    // StateResidency
+    temp = env->FindClass("android/hardware/power/stats/StateResidency");
+    class_SR = (jclass)env->NewGlobalRef(temp);
+    method_SR_init = env->GetMethodID(class_SR, "<init>", "()V");
+    field_SR_stateId = env->GetFieldID(class_SR, "stateId", "I");
+    field_SR_totalTimeInStateMs = env->GetFieldID(class_SR, "totalTimeInStateMs", "J");
+    field_SR_totalStateEntryCount = env->GetFieldID(class_SR, "totalStateEntryCount", "J");
+    field_SR_lastEntryTimestampMs = env->GetFieldID(class_SR, "lastEntryTimestampMs", "J");
+
+    // StateResidencyResult
+    temp = env->FindClass("android/hardware/power/stats/StateResidencyResult");
+    class_SRR = (jclass)env->NewGlobalRef(temp);
+    method_SRR_init = env->GetMethodID(class_SRR, "<init>", "()V");
+    field_SRR_powerEntityId = env->GetFieldID(class_SRR, "powerEntityId", "I");
+    field_SRR_stateResidencyData =
+            env->GetFieldID(class_SRR, "stateResidencyData",
+                            "[Landroid/hardware/power/stats/StateResidency;");
+
+    if (!connectToPowerStatsHal()) {
+        ALOGE("nativeInit failed to connect to power.stats HAL");
+        return false;
+    }
+
+    return true;
+}
+
+static const JNINativeMethod method_table[] = {
+        {"nativeInit", "()Z", (void *)nativeInit},
+        {"nativeGetPowerEntityInfo", "()[Landroid/hardware/power/stats/PowerEntityInfo;",
+         (void *)nativeGetPowerEntityInfo},
+        {"nativeGetStateResidency", "([I)[Landroid/hardware/power/stats/StateResidencyResult;",
+         (void *)nativeGetStateResidency},
+        {"nativeGetEnergyMeterInfo", "()[Landroid/hardware/power/stats/ChannelInfo;",
+         (void *)nativeGetEnergyMeterInfo},
+        {"nativeReadEnergyMeters", "([I)[Landroid/hardware/power/stats/EnergyMeasurement;",
+         (void *)nativeReadEnergyMeters},
+};
+
+int register_android_server_PowerStatsService(JNIEnv *env) {
+    return jniRegisterNativeMethods(env,
+                                    "com/android/server/powerstats/"
+                                    "PowerStatsHALWrapper$PowerStatsHAL10WrapperImpl",
+                                    method_table, NELEM(method_table));
+}
+
+}; // namespace android
diff --git a/services/core/jni/onload.cpp b/services/core/jni/onload.cpp
index 5a0d08a..85ef394 100644
--- a/services/core/jni/onload.cpp
+++ b/services/core/jni/onload.cpp
@@ -29,6 +29,7 @@
 int register_android_server_InputManager(JNIEnv* env);
 int register_android_server_LightsService(JNIEnv* env);
 int register_android_server_PowerManagerService(JNIEnv* env);
+int register_android_server_PowerStatsService(JNIEnv* env);
 int register_android_server_storage_AppFuse(JNIEnv* env);
 int register_android_server_SerialService(JNIEnv* env);
 int register_android_server_SystemServer(JNIEnv* env);
@@ -82,6 +83,7 @@
     register_android_server_broadcastradio_BroadcastRadioService(env);
     register_android_server_broadcastradio_Tuner(vm, env);
     register_android_server_PowerManagerService(env);
+    register_android_server_PowerStatsService(env);
     register_android_server_SerialService(env);
     register_android_server_InputManager(env);
     register_android_server_LightsService(env);
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyData.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyData.java
index c766ca0..7ec5ff0 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyData.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyData.java
@@ -413,7 +413,6 @@
                 policy.mPermissionPolicy = permissionPolicy;
             }
 
-            parser.next();
             int outerDepth = parser.getDepth();
             policy.mLockTaskPackages.clear();
             policy.mAdminList.clear();
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 38eb373..0e0fe4c 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -199,7 +199,6 @@
 import android.media.IAudioService;
 import android.net.ConnectivityManager;
 import android.net.IIpConnectivityMetrics;
-import android.net.NetworkUtils;
 import android.net.ProxyInfo;
 import android.net.Uri;
 import android.net.metrics.IpConnectivityLog;
@@ -270,6 +269,7 @@
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
+import com.android.internal.net.NetworkUtilsInternal;
 import com.android.internal.notification.SystemNotificationChannels;
 import com.android.internal.os.BackgroundThread;
 import com.android.internal.statusbar.IStatusBarService;
@@ -1025,23 +1025,6 @@
         mSafetyChecker = new OneTimeSafetyChecker(this, operation, safe);
     }
 
-    // TODO(b/175392542): remove if not needed by ManagedProvisioning app anymore
-    @Override
-    public void factoryReset(String reason) {
-        Preconditions.checkCallAuthorization(
-                hasCallingOrSelfPermission(permission.MASTER_CLEAR));
-        Slog.w(LOG_TAG, "factoryReset(): " + reason);
-        final long identity = Binder.clearCallingIdentity();
-        try {
-            FactoryResetter.newBuilder(mContext).setReason(reason).build().factoryReset();
-        } catch (IOException e) {
-            // Shouldn't happen.
-            Slog.wtf(LOG_TAG, "Could not factory reset", e);
-        } finally {
-            Binder.restoreCallingIdentity(identity);
-        }
-    }
-
     /**
      * Unit test will subclass it to inject mocks.
      */
@@ -6175,6 +6158,7 @@
                 (admin != null) || hasCallingOrSelfPermission(permission.MASTER_CLEAR),
                 "No active admin for user %d and caller %d does not hold MASTER_CLEAR permission",
                 caller.getUserId(), caller.getUid());
+        checkCanExecuteOrThrowUnsafe(DevicePolicyManager.OPERATION_WIPE_DATA);
 
         if (TextUtils.isEmpty(wipeReasonForUser)) {
             if (calledByProfileOwnerOnOrgOwnedDevice && !calledOnParentInstance) {
@@ -9812,6 +9796,7 @@
         Objects.requireNonNull(who, "ComponentName is null");
         final CallerIdentity caller = getCallerIdentity(who);
         Preconditions.checkCallAuthorization(isProfileOwner(caller) || isDeviceOwner(caller));
+        checkCanExecuteOrThrowUnsafe(DevicePolicyManager.OPERATION_LOGOUT_USER);
 
         final int callingUserId = caller.getUserId();
         synchronized (getLockObject()) {
@@ -9997,6 +9982,7 @@
                     throw new SecurityException("Profile owner cannot set user restriction " + key);
                 }
             }
+            checkCanExecuteOrThrowUnsafe(DevicePolicyManager.OPERATION_SET_USER_RESTRICTION);
 
             // Save the restriction to ActiveAdmin.
             final Bundle restrictions = activeAdmin.ensureUserRestrictions();
@@ -11780,13 +11766,8 @@
         }
 
         @Override
-        public ComponentName getProfileOwnerAsUser(@UserIdInt int userId) {
-            return DevicePolicyManagerService.this.getProfileOwnerAsUser(userId);
-        }
-
-        @Override
-        public int getDeviceOwnerUserId() {
-            return DevicePolicyManagerService.this.getDeviceOwnerUserId();
+        public ComponentName getProfileOwnerAsUser(int userHandle) {
+            return DevicePolicyManagerService.this.getProfileOwnerAsUser(userHandle);
         }
 
         @Override
@@ -14638,7 +14619,7 @@
                 return PRIVATE_DNS_SET_NO_ERROR;
             case PRIVATE_DNS_MODE_PROVIDER_HOSTNAME:
                 if (TextUtils.isEmpty(privateDnsHost)
-                        || !NetworkUtils.isWeaklyValidatedHostname(privateDnsHost)) {
+                        || !NetworkUtilsInternal.isWeaklyValidatedHostname(privateDnsHost)) {
                     throw new IllegalArgumentException(
                             String.format("Provided hostname %s is not valid", privateDnsHost));
                 }
diff --git a/services/tests/mockingservicestests/src/com/android/server/appop/AppOpsUpgradeTest.java b/services/tests/mockingservicestests/src/com/android/server/appop/AppOpsUpgradeTest.java
index 9f895c6..99693d2 100644
--- a/services/tests/mockingservicestests/src/com/android/server/appop/AppOpsUpgradeTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/appop/AppOpsUpgradeTest.java
@@ -36,7 +36,6 @@
 import android.util.Log;
 import android.util.SparseArray;
 import android.util.TypedXmlPullParser;
-import android.util.TypedXmlSerializer;
 import android.util.Xml;
 
 import androidx.test.InstrumentationRegistry;
@@ -53,7 +52,6 @@
 import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
-import java.nio.charset.StandardCharsets;
 
 /**
  * Tests app ops version upgrades
@@ -183,8 +181,7 @@
 
         boolean parse() {
             try (FileInputStream stream = new FileInputStream(mFile)) {
-                TypedXmlPullParser parser = Xml.newFastPullParser();
-                parser.setInput(stream, StandardCharsets.UTF_8.name());
+                TypedXmlPullParser parser = Xml.resolvePullParser(stream);
                 int type;
                 while ((type = parser.next()) != XmlPullParser.START_TAG
                         && type != XmlPullParser.END_DOCUMENT) {
diff --git a/services/tests/mockingservicestests/src/com/android/server/location/OWNERS b/services/tests/mockingservicestests/src/com/android/server/location/OWNERS
new file mode 100644
index 0000000..696a0c2
--- /dev/null
+++ b/services/tests/mockingservicestests/src/com/android/server/location/OWNERS
@@ -0,0 +1 @@
+file:/location/java/android/location/OWNERS
diff --git a/services/tests/mockingservicestests/src/com/android/server/location/gnss/GnssManagerServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/location/gnss/GnssManagerServiceTest.java
index 98fd1c9..2b21cc5 100644
--- a/services/tests/mockingservicestests/src/com/android/server/location/gnss/GnssManagerServiceTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/location/gnss/GnssManagerServiceTest.java
@@ -43,9 +43,9 @@
 import android.location.GnssAntennaInfo.SphericalCorrections;
 import android.location.GnssClock;
 import android.location.GnssMeasurementCorrections;
+import android.location.GnssMeasurementRequest;
 import android.location.GnssMeasurementsEvent;
 import android.location.GnssNavigationMessage;
-import android.location.GnssRequest;
 import android.location.GnssSingleSatCorrection;
 import android.location.IGnssAntennaInfoListener;
 import android.location.IGnssMeasurementsListener;
@@ -403,7 +403,7 @@
 
         assertThrows(SecurityException.class,
                 () -> mGnssManagerService.addGnssMeasurementsListener(
-                        new GnssRequest.Builder().build(), mockGnssMeasurementsListener,
+                        new GnssMeasurementRequest.Builder().build(), mockGnssMeasurementsListener,
                         TEST_PACKAGE, null));
 
         mTestGnssMeasurementsProvider.onMeasurementsAvailable(gnssMeasurementsEvent);
@@ -422,7 +422,7 @@
         enableLocationPermissions();
 
         mGnssManagerService.addGnssMeasurementsListener(
-                new GnssRequest.Builder().build(),
+                new GnssMeasurementRequest.Builder().build(),
                 mockGnssMeasurementsListener,
                 TEST_PACKAGE, null);
 
@@ -470,7 +470,8 @@
 
         enableLocationPermissions();
 
-        mGnssManagerService.addGnssMeasurementsListener(new GnssRequest.Builder().build(),
+        mGnssManagerService.addGnssMeasurementsListener(
+                new GnssMeasurementRequest.Builder().build(),
                 mockGnssMeasurementsListener,
                 TEST_PACKAGE, null);
 
@@ -494,7 +495,8 @@
 
         enableLocationPermissions();
 
-        mGnssManagerService.addGnssMeasurementsListener(new GnssRequest.Builder().build(),
+        mGnssManagerService.addGnssMeasurementsListener(
+                new GnssMeasurementRequest.Builder().build(),
                 mockGnssMeasurementsListener,
                 TEST_PACKAGE, null);
 
diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/MockSystem.kt b/services/tests/mockingservicestests/src/com/android/server/pm/MockSystem.kt
index edae08a3..015eead 100644
--- a/services/tests/mockingservicestests/src/com/android/server/pm/MockSystem.kt
+++ b/services/tests/mockingservicestests/src/com/android/server/pm/MockSystem.kt
@@ -68,12 +68,12 @@
 import com.android.server.testutils.mock
 import com.android.server.testutils.nullable
 import com.android.server.testutils.whenever
+import com.android.server.utils.WatchedArrayMap
 import org.junit.Assert
 import org.junit.rules.TestRule
 import org.junit.runner.Description
 import org.junit.runners.model.Statement
 import org.mockito.AdditionalMatchers.or
-import org.mockito.invocation.InvocationOnMock
 import org.mockito.quality.Strictness
 import java.io.File
 import java.io.IOException
@@ -114,7 +114,7 @@
     private val mPreExistingSettings = ArrayMap<String, PackageSetting>()
 
     /** The active map simulating the in memory storage of Settings  */
-    private val mSettingsMap = ArrayMap<String, PackageSetting>()
+    private val mSettingsMap = WatchedArrayMap<String, PackageSetting>()
 
     init {
         val apply = ExtendedMockito.mockitoSession()
@@ -268,7 +268,7 @@
         wheneverStatic { Environment.getPackageCacheDirectory() }.thenReturn(packageCacheDirectory)
         wheneverStatic { SystemProperties.digestOf("ro.build.fingerprint") }.thenReturn("cacheName")
         wheneverStatic { Environment.getRootDirectory() }.thenReturn(rootDirectory)
-        wheneverStatic { SystemServerInitThreadPool.submit(any(Runnable::class.java), anyString())}
+        wheneverStatic { SystemServerInitThreadPool.submit(any(Runnable::class.java), anyString()) }
                 .thenAnswer { FutureTask<Any?>(it.getArgument(0), null) }
 
         wheneverStatic { Environment.getDataDirectory() }.thenReturn(dataAppDirectory.parentFile)
diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/OWNERS b/services/tests/mockingservicestests/src/com/android/server/pm/OWNERS
new file mode 100644
index 0000000..d825dfd
--- /dev/null
+++ b/services/tests/mockingservicestests/src/com/android/server/pm/OWNERS
@@ -0,0 +1 @@
+include /services/core/java/com/android/server/pm/OWNERS
diff --git a/services/tests/servicestests/src/com/android/server/VibratorServiceTest.java b/services/tests/servicestests/src/com/android/server/VibratorServiceTest.java
index 68adacd..32ca7b5 100644
--- a/services/tests/servicestests/src/com/android/server/VibratorServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/VibratorServiceTest.java
@@ -172,6 +172,7 @@
 
     @After
     public void tearDown() throws Exception {
+        InputManager.clearInstance();
         LocalServices.removeServiceForTest(PackageManagerInternal.class);
         LocalServices.removeServiceForTest(PowerManagerInternal.class);
     }
@@ -838,7 +839,7 @@
 
     private InputDevice createInputDeviceWithVibrator(int id) {
         return new InputDevice(id, 0, 0, "name", 0, 0, "description", false, 0, 0,
-                null, /* hasVibrator= */ true, false, false);
+                null, /* hasVibrator= */ true, false, false, false /* hasSensor */);
     }
 
     private static <T> void addLocalServiceMock(Class<T> clazz, T mock) {
diff --git a/services/tests/servicestests/src/com/android/server/audio/OWNERS b/services/tests/servicestests/src/com/android/server/audio/OWNERS
new file mode 100644
index 0000000..894a1f5
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/audio/OWNERS
@@ -0,0 +1 @@
+include /services/core/java/com/android/server/audio/OWNERS
diff --git a/services/tests/servicestests/src/com/android/server/compat/CompatConfigTest.java b/services/tests/servicestests/src/com/android/server/compat/CompatConfigTest.java
index e588370..8c63bfc 100644
--- a/services/tests/servicestests/src/com/android/server/compat/CompatConfigTest.java
+++ b/services/tests/servicestests/src/com/android/server/compat/CompatConfigTest.java
@@ -190,6 +190,22 @@
     }
 
     @Test
+    public void testIsChangeEnabledForInvalidApp() throws Exception {
+        final long disabledChangeId = 1234L;
+        final long enabledChangeId = 1235L;
+        final long targetSdkChangeId = 1236L;
+        CompatConfig compatConfig = CompatConfigBuilder.create(mBuildClassifier, mContext)
+                .addEnabledChangeWithId(enabledChangeId)
+                .addDisabledChangeWithId(disabledChangeId)
+                .addEnableSinceSdkChangeWithId(42, targetSdkChangeId)
+                .build();
+
+        assertThat(compatConfig.isChangeEnabled(enabledChangeId, null)).isTrue();
+        assertThat(compatConfig.isChangeEnabled(disabledChangeId, null)).isFalse();
+        assertThat(compatConfig.isChangeEnabled(targetSdkChangeId, null)).isTrue();
+    }
+
+    @Test
     public void testPreventAddOverride() throws Exception {
         final long changeId = 1234L;
         CompatConfig compatConfig = CompatConfigBuilder.create(mBuildClassifier, mContext)
diff --git a/services/tests/servicestests/src/com/android/server/compat/PlatformCompatTest.java b/services/tests/servicestests/src/com/android/server/compat/PlatformCompatTest.java
index 64014ba..1d3b643 100644
--- a/services/tests/servicestests/src/com/android/server/compat/PlatformCompatTest.java
+++ b/services/tests/servicestests/src/com/android/server/compat/PlatformCompatTest.java
@@ -107,18 +107,20 @@
         mCompatConfig = CompatConfigBuilder.create(mBuildClassifier, mContext)
                 .addEnabledChangeWithId(1L)
                 .addDisabledChangeWithIdAndName(2L, "change2")
-                .addEnableAfterSdkChangeWithIdAndDescription(Build.VERSION_CODES.O, 3L, "desc")
-                .addEnableAfterSdkChangeWithId(Build.VERSION_CODES.P, 4L)
-                .addEnableAfterSdkChangeWithId(Build.VERSION_CODES.Q, 5L)
-                .addEnableAfterSdkChangeWithId(Build.VERSION_CODES.R, 6L)
+                .addEnableSinceSdkChangeWithIdAndDescription(Build.VERSION_CODES.O, 3L, "desc")
+                .addEnableSinceSdkChangeWithId(Build.VERSION_CODES.P, 4L)
+                .addEnableSinceSdkChangeWithId(Build.VERSION_CODES.Q, 5L)
+                .addEnableSinceSdkChangeWithId(Build.VERSION_CODES.R, 6L)
                 .addLoggingOnlyChangeWithId(7L)
                 .build();
         mPlatformCompat = new PlatformCompat(mContext, mCompatConfig);
         assertThat(mPlatformCompat.listUIChanges()).asList().containsExactly(
                 new CompatibilityChangeInfo(1L, "", -1, -1, false, false, ""),
                 new CompatibilityChangeInfo(2L, "change2", -1, -1, true, false, ""),
-                new CompatibilityChangeInfo(4L, "", Build.VERSION_CODES.P, -1, false, false, ""),
-                new CompatibilityChangeInfo(5L, "", Build.VERSION_CODES.Q, -1, false, false, ""));
+                new CompatibilityChangeInfo(5L, "", /*enableAfter*/ -1,
+                        /*enableSince*/ Build.VERSION_CODES.Q, false, false, ""),
+                new CompatibilityChangeInfo(6L, "", /*enableAfter*/ -1,
+                        /*enableSince*/ Build.VERSION_CODES.R, false, false, ""));
     }
 
     @Test
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/TransferOwnershipMetadataManagerTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/TransferOwnershipMetadataManagerTest.java
index 07ea855..2d76537 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/TransferOwnershipMetadataManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/TransferOwnershipMetadataManagerTest.java
@@ -37,6 +37,7 @@
 
 import org.junit.After;
 import org.junit.Before;
+import org.junit.Ignore;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
@@ -83,6 +84,7 @@
     }
 
     @Test
+    @Ignore
     public void testFileContentValid() {
         TransferOwnershipMetadataManager paramsManager = getOwnerTransferParams();
         assertThat(paramsManager.saveMetadataFile(TEST_PARAMS)).isTrue();
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/FakeHdmiCecConfig.java b/services/tests/servicestests/src/com/android/server/hdmi/FakeHdmiCecConfig.java
index 227e8c7..e5bcedb 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/FakeHdmiCecConfig.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/FakeHdmiCecConfig.java
@@ -77,6 +77,15 @@
                     + "    </allowed-values>"
                     + "    <default-value int-value=\"1\" />"
                     + "  </setting>"
+                    + "  <setting name=\"hdmi_cec_enabled\""
+                    + "           value-type=\"int\""
+                    + "           user-configurable=\"true\">"
+                    + "    <allowed-values>"
+                    + "      <value int-value=\"0\" />"
+                    + "      <value int-value=\"1\" />"
+                    + "    </allowed-values>"
+                    + "    <default-value int-value=\"1\" />"
+                    + "  </setting>"
                     + "</cec-settings>";
 
     FakeHdmiCecConfig(@NonNull Context context) {
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDevicePlaybackTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDevicePlaybackTest.java
index f7d52b6..7aea4ff 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDevicePlaybackTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDevicePlaybackTest.java
@@ -1334,4 +1334,31 @@
         assertThat(mNativeWrapper.getResultMessages()).contains(userControlReleased);
         assertThat(mStandby).isFalse();
     }
+
+    @Test
+    public void shouldHandleTvPowerKey_CecDisabled() {
+        mHdmiCecLocalDevicePlayback.mService.getHdmiCecConfig().setIntValue(
+                HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_ENABLED,
+                HdmiControlManager.HDMI_CEC_CONTROL_DISABLED);
+        assertThat(mHdmiControlService.shouldHandleTvPowerKey()).isFalse();
+    }
+
+    @Test
+    public void shouldHandleTvPowerKey_PowerControlModeNone() {
+        mHdmiCecLocalDevicePlayback.mService.getHdmiCecConfig().setStringValue(
+                HdmiControlManager.CEC_SETTING_NAME_POWER_CONTROL_MODE,
+                HdmiControlManager.POWER_CONTROL_MODE_NONE);
+        assertThat(mHdmiControlService.shouldHandleTvPowerKey()).isFalse();
+    }
+
+    @Test
+    public void shouldHandleTvPowerKey_CecEnabled_PowerControlModeTv() {
+        mHdmiCecLocalDevicePlayback.mService.getHdmiCecConfig().setIntValue(
+                HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_ENABLED,
+                HdmiControlManager.HDMI_CEC_CONTROL_ENABLED);
+        mHdmiCecLocalDevicePlayback.mService.getHdmiCecConfig().setStringValue(
+                HdmiControlManager.CEC_SETTING_NAME_POWER_CONTROL_MODE,
+                HdmiControlManager.POWER_CONTROL_MODE_TV);
+        assertThat(mHdmiControlService.shouldHandleTvPowerKey()).isTrue();
+    }
 }
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTvTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTvTest.java
index d24b376..81f55d8 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTvTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTvTest.java
@@ -192,4 +192,15 @@
         assertThat(mHdmiControlService.getActiveSource().getPhysicalAddress()).isEqualTo(
                 externalDevice.getPhysicalAddress());
     }
+
+    @Test
+    public void shouldHandleTvPowerKey_CecEnabled_PowerControlModeTv() {
+        mHdmiCecLocalDeviceTv.mService.getHdmiCecConfig().setIntValue(
+                HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_ENABLED,
+                HdmiControlManager.HDMI_CEC_CONTROL_ENABLED);
+        mHdmiCecLocalDeviceTv.mService.getHdmiCecConfig().setStringValue(
+                HdmiControlManager.CEC_SETTING_NAME_POWER_CONTROL_MODE,
+                HdmiControlManager.POWER_CONTROL_MODE_TV);
+        assertThat(mHdmiControlService.shouldHandleTvPowerKey()).isFalse();
+    }
 }
diff --git a/services/tests/servicestests/src/com/android/server/om/OverlayManagerSettingsTests.java b/services/tests/servicestests/src/com/android/server/om/OverlayManagerSettingsTests.java
index 20f9b70..e3e7768 100644
--- a/services/tests/servicestests/src/com/android/server/om/OverlayManagerSettingsTests.java
+++ b/services/tests/servicestests/src/com/android/server/om/OverlayManagerSettingsTests.java
@@ -28,7 +28,6 @@
 import android.content.om.OverlayInfo;
 import android.text.TextUtils;
 import android.util.TypedXmlPullParser;
-import android.util.TypedXmlSerializer;
 import android.util.Xml;
 
 import androidx.test.runner.AndroidJUnit4;
@@ -40,7 +39,7 @@
 
 import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
-import java.io.StringReader;
+import java.io.InputStream;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Map;
@@ -287,7 +286,7 @@
     public void testPersistEmpty() throws Exception {
         ByteArrayOutputStream os = new ByteArrayOutputStream();
         mSettings.persist(os);
-        String xml = new String(os.toByteArray(), "utf-8");
+        ByteArrayInputStream xml = new ByteArrayInputStream(os.toByteArray());
 
         assertEquals(1, countXmlTags(xml, "overlays"));
         assertEquals(0, countXmlTags(xml, "item"));
@@ -300,7 +299,7 @@
 
         ByteArrayOutputStream os = new ByteArrayOutputStream();
         mSettings.persist(os);
-        final String xml = new String(os.toByteArray(), "utf-8");
+        ByteArrayInputStream xml = new ByteArrayInputStream(os.toByteArray());
 
         assertEquals(1, countXmlTags(xml, "overlays"));
         assertEquals(2, countXmlTags(xml, "item"));
@@ -319,7 +318,7 @@
 
         ByteArrayOutputStream os = new ByteArrayOutputStream();
         mSettings.persist(os);
-        String xml = new String(os.toByteArray(), "utf-8");
+        ByteArrayInputStream xml = new ByteArrayInputStream(os.toByteArray());
 
         assertEquals(1, countXmlTags(xml, "overlays"));
         assertEquals(2, countXmlTags(xml, "item"));
@@ -338,7 +337,7 @@
 
         ByteArrayOutputStream os = new ByteArrayOutputStream();
         mSettings.persist(os);
-        String xml = new String(os.toByteArray(), "utf-8");
+        ByteArrayInputStream xml = new ByteArrayInputStream(os.toByteArray());
 
         assertEquals(1, countXmlAttributesWhere(xml, "item", "isEnabled", "true"));
     }
@@ -391,8 +390,7 @@
 
         ByteArrayOutputStream os = new ByteArrayOutputStream();
         mSettings.persist(os);
-        String xml = new String(os.toByteArray(), "utf-8");
-        ByteArrayInputStream is = new ByteArrayInputStream(xml.getBytes("utf-8"));
+        ByteArrayInputStream is = new ByteArrayInputStream(os.toByteArray());
         OverlayManagerSettings newSettings = new OverlayManagerSettings();
         newSettings.restore(is);
 
@@ -403,10 +401,10 @@
         assertEquals(OVERLAY_B1, b);
     }
 
-    private int countXmlTags(String xml, String tagToLookFor) throws Exception {
+    private int countXmlTags(InputStream in, String tagToLookFor) throws Exception {
+        in.reset();
         int count = 0;
-        TypedXmlPullParser parser = Xml.newFastPullParser();
-        parser.setInput(new StringReader(xml));
+        TypedXmlPullParser parser = Xml.resolvePullParser(in);
         int event = parser.getEventType();
         while (event != XmlPullParser.END_DOCUMENT) {
             if (event == XmlPullParser.START_TAG && tagToLookFor.equals(parser.getName())) {
@@ -417,11 +415,11 @@
         return count;
     }
 
-    private int countXmlAttributesWhere(String xml, String tag, String attr, String value)
+    private int countXmlAttributesWhere(InputStream in, String tag, String attr, String value)
             throws Exception {
+        in.reset();
         int count = 0;
-        TypedXmlPullParser parser = Xml.newFastPullParser();
-        parser.setInput(new StringReader(xml));
+        TypedXmlPullParser parser = Xml.resolvePullParser(in);
         int event = parser.getEventType();
         while (event != XmlPullParser.END_DOCUMENT) {
             if (event == XmlPullParser.START_TAG && tag.equals(parser.getName())) {
diff --git a/services/tests/servicestests/src/com/android/server/pm/AppsFilterTest.java b/services/tests/servicestests/src/com/android/server/pm/AppsFilterTest.java
index eec7d12..205548c 100644
--- a/services/tests/servicestests/src/com/android/server/pm/AppsFilterTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/AppsFilterTest.java
@@ -52,6 +52,7 @@
 import com.android.server.pm.parsing.pkg.AndroidPackage;
 import com.android.server.pm.parsing.pkg.PackageImpl;
 import com.android.server.pm.parsing.pkg.ParsedPackage;
+import com.android.server.utils.WatchableTester;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -884,6 +885,104 @@
                 contains(hasProviderAppId, queriesProviderAppId));
     }
 
+    @Test
+    public void testOnChangeReport() throws Exception {
+        final AppsFilter appsFilter =
+                new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null,
+                        mMockExecutor);
+        final WatchableTester watcher = new WatchableTester(appsFilter, "onChange");
+        watcher.register();
+        simulateAddBasicAndroid(appsFilter);
+        watcher.verifyChangeReported("addBasic");
+        appsFilter.onSystemReady();
+        watcher.verifyChangeReported("systemReady");
+
+        final int systemAppId = Process.FIRST_APPLICATION_UID - 1;
+        final int seesNothingAppId = Process.FIRST_APPLICATION_UID;
+        final int hasProviderAppId = Process.FIRST_APPLICATION_UID + 1;
+        final int queriesProviderAppId = Process.FIRST_APPLICATION_UID + 2;
+
+        PackageSetting system = simulateAddPackage(appsFilter, pkg("some.system.pkg"), systemAppId);
+        watcher.verifyChangeReported("addPackage");
+        PackageSetting seesNothing = simulateAddPackage(appsFilter, pkg("com.some.package"),
+                seesNothingAppId);
+        watcher.verifyChangeReported("addPackage");
+        PackageSetting hasProvider = simulateAddPackage(appsFilter,
+                pkgWithProvider("com.some.other.package", "com.some.authority"), hasProviderAppId);
+        watcher.verifyChangeReported("addPackage");
+        PackageSetting queriesProvider = simulateAddPackage(appsFilter,
+                pkgQueriesProvider("com.yet.some.other.package", "com.some.authority"),
+                queriesProviderAppId);
+        watcher.verifyChangeReported("addPackage");
+
+        final SparseArray<int[]> systemFilter =
+                appsFilter.getVisibilityAllowList(system, USER_ARRAY, mExisting);
+        assertThat(toList(systemFilter.get(SYSTEM_USER)),
+                contains(seesNothingAppId, hasProviderAppId, queriesProviderAppId));
+        watcher.verifyNoChangeReported("get");
+
+        final SparseArray<int[]> seesNothingFilter =
+                appsFilter.getVisibilityAllowList(seesNothing, USER_ARRAY, mExisting);
+        assertThat(toList(seesNothingFilter.get(SYSTEM_USER)),
+                contains(seesNothingAppId));
+        assertThat(toList(seesNothingFilter.get(SECONDARY_USER)),
+                contains(seesNothingAppId));
+        watcher.verifyNoChangeReported("get");
+
+        final SparseArray<int[]> hasProviderFilter =
+                appsFilter.getVisibilityAllowList(hasProvider, USER_ARRAY, mExisting);
+        assertThat(toList(hasProviderFilter.get(SYSTEM_USER)),
+                contains(hasProviderAppId, queriesProviderAppId));
+        watcher.verifyNoChangeReported("get");
+
+        SparseArray<int[]> queriesProviderFilter =
+                appsFilter.getVisibilityAllowList(queriesProvider, USER_ARRAY, mExisting);
+        assertThat(toList(queriesProviderFilter.get(SYSTEM_USER)),
+                contains(queriesProviderAppId));
+        watcher.verifyNoChangeReported("get");
+
+        // provider read
+        appsFilter.grantImplicitAccess(hasProviderAppId, queriesProviderAppId);
+        watcher.verifyChangeReported("grantImplicitAccess");
+
+        // ensure implicit access is included in the filter
+        queriesProviderFilter =
+                appsFilter.getVisibilityAllowList(queriesProvider, USER_ARRAY, mExisting);
+        assertThat(toList(queriesProviderFilter.get(SYSTEM_USER)),
+                contains(hasProviderAppId, queriesProviderAppId));
+        watcher.verifyNoChangeReported("get");
+
+        // remove a package
+        appsFilter.removePackage(seesNothing);
+        watcher.verifyChangeReported("removePackage");
+    }
+
+    @Test
+    public void testOnChangeReportedFilter() throws Exception {
+        final AppsFilter appsFilter =
+                new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null,
+                        mMockExecutor);
+        simulateAddBasicAndroid(appsFilter);
+        appsFilter.onSystemReady();
+        final WatchableTester watcher = new WatchableTester(appsFilter, "onChange filter");
+        watcher.register();
+
+        PackageSetting target = simulateAddPackage(appsFilter, pkg("com.some.package"),
+                DUMMY_TARGET_APPID);
+        PackageSetting instrumentation = simulateAddPackage(appsFilter,
+                pkgWithInstrumentation("com.some.other.package", "com.some.package"),
+                DUMMY_CALLING_APPID);
+        watcher.verifyChangeReported("addPackage");
+
+        assertFalse(
+                appsFilter.shouldFilterApplication(DUMMY_CALLING_APPID, instrumentation, target,
+                        SYSTEM_USER));
+        assertFalse(
+                appsFilter.shouldFilterApplication(DUMMY_TARGET_APPID, target, instrumentation,
+                        SYSTEM_USER));
+        watcher.verifyNoChangeReported("shouldFilterApplication");
+    }
+
     private List<Integer> toList(int[] array) {
         ArrayList<Integer> ret = new ArrayList<>(array.length);
         for (int i = 0; i < array.length; i++) {
diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java b/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java
index 4b90a5c..282047a 100644
--- a/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java
@@ -62,6 +62,7 @@
 import com.android.server.pm.parsing.pkg.PackageImpl;
 import com.android.server.pm.parsing.pkg.ParsedPackage;
 import com.android.server.pm.permission.LegacyPermissionDataProvider;
+import com.android.server.utils.WatchableTester;
 
 import com.google.common.truth.Truth;
 
@@ -178,6 +179,12 @@
         PackageSetting ps = settings.getPackageLPr(PACKAGE_NAME_2);
         assertThat(ps.getEnabled(0), is(COMPONENT_ENABLED_STATE_DISABLED_USER));
         assertThat(ps.getEnabled(1), is(COMPONENT_ENABLED_STATE_DEFAULT));
+
+        // Verify that the snapshot passes the same test
+        Settings snapshot = settings.snapshot();
+        ps = snapshot.getPackageLPr(PACKAGE_NAME_2);
+        assertThat(ps.getEnabled(0), is(COMPONENT_ENABLED_STATE_DISABLED_USER));
+        assertThat(ps.getEnabled(1), is(COMPONENT_ENABLED_STATE_DEFAULT));
     }
 
     private static PersistableBundle createPersistableBundle(String packageName, long longVal,
@@ -197,21 +204,41 @@
         final Context context = InstrumentationRegistry.getTargetContext();
         final Settings settingsUnderTest = new Settings(context.getFilesDir(), null, null,
                 lock);
+        final WatchableTester watcher =
+                new WatchableTester(settingsUnderTest, "noSuspendingPackage");
+        watcher.register();
         settingsUnderTest.mPackages.put(PACKAGE_NAME_1, createPackageSetting(PACKAGE_NAME_1));
+        watcher.verifyChangeReported("put package 1");
+        // Collect a snapshot at the midway point (package 2 has not been added)
+        final Settings snapshot = settingsUnderTest.snapshot();
+        watcher.verifyNoChangeReported("snapshot");
         settingsUnderTest.mPackages.put(PACKAGE_NAME_2, createPackageSetting(PACKAGE_NAME_2));
+        watcher.verifyChangeReported("put package 2");
         settingsUnderTest.readPackageRestrictionsLPr(0);
 
-        final PackageSetting ps1 = settingsUnderTest.mPackages.get(PACKAGE_NAME_1);
-        final PackageUserState packageUserState1 = ps1.readUserState(0);
+        PackageSetting ps1 = settingsUnderTest.mPackages.get(PACKAGE_NAME_1);
+        PackageUserState packageUserState1 = ps1.readUserState(0);
         assertThat(packageUserState1.suspended, is(true));
         assertThat(packageUserState1.suspendParams.size(), is(1));
         assertThat(packageUserState1.suspendParams.keyAt(0), is("android"));
         assertThat(packageUserState1.suspendParams.valueAt(0), is(nullValue()));
 
-        final PackageSetting ps2 = settingsUnderTest.mPackages.get(PACKAGE_NAME_2);
-        final PackageUserState packageUserState2 = ps2.readUserState(0);
+        // Verify that the snapshot returns the same answers
+        ps1 = snapshot.mPackages.get(PACKAGE_NAME_1);
+        packageUserState1 = ps1.readUserState(0);
+        assertThat(packageUserState1.suspended, is(true));
+        assertThat(packageUserState1.suspendParams.size(), is(1));
+        assertThat(packageUserState1.suspendParams.keyAt(0), is("android"));
+        assertThat(packageUserState1.suspendParams.valueAt(0), is(nullValue()));
+
+        PackageSetting ps2 = settingsUnderTest.mPackages.get(PACKAGE_NAME_2);
+        PackageUserState packageUserState2 = ps2.readUserState(0);
         assertThat(packageUserState2.suspended, is(false));
         assertThat(packageUserState2.suspendParams, is(nullValue()));
+
+        // Verify that the snapshot returns different answers
+        ps2 = snapshot.mPackages.get(PACKAGE_NAME_2);
+        assertTrue(ps2 == null);
     }
 
     @Test
@@ -221,15 +248,23 @@
         final Context context = InstrumentationRegistry.getTargetContext();
         final Settings settingsUnderTest = new Settings(context.getFilesDir(), null, null,
                 lock);
+        final WatchableTester watcher =
+                new WatchableTester(settingsUnderTest, "noSuspendParamsMap");
+        watcher.register();
         settingsUnderTest.mPackages.put(PACKAGE_NAME_1, createPackageSetting(PACKAGE_NAME_1));
+        watcher.verifyChangeReported("put package 1");
         settingsUnderTest.readPackageRestrictionsLPr(0);
+        watcher.verifyChangeReported("readPackageRestrictions");
 
         final PackageSetting ps1 = settingsUnderTest.mPackages.get(PACKAGE_NAME_1);
+        watcher.verifyNoChangeReported("get package 1");
         final PackageUserState packageUserState1 = ps1.readUserState(0);
+        watcher.verifyNoChangeReported("readUserState");
         assertThat(packageUserState1.suspended, is(true));
         assertThat(packageUserState1.suspendParams.size(), is(1));
         assertThat(packageUserState1.suspendParams.keyAt(0), is(PACKAGE_NAME_3));
         final PackageUserState.SuspendParams params = packageUserState1.suspendParams.valueAt(0);
+        watcher.verifyNoChangeReported("fetch user state");
         assertThat(params, is(notNullValue()));
         assertThat(params.appExtras.size(), is(1));
         assertThat(params.appExtras.getString("app_extra_string"), is("value"));
@@ -249,6 +284,8 @@
         final Context context = InstrumentationRegistry.getTargetContext();
         final Settings settingsUnderTest = new Settings(context.getFilesDir(), null, null,
                 new Object());
+        final WatchableTester watcher = new WatchableTester(settingsUnderTest, "suspendInfo");
+        watcher.register();
         final PackageSetting ps1 = createPackageSetting(PACKAGE_NAME_1);
         final PackageSetting ps2 = createPackageSetting(PACKAGE_NAME_2);
         final PackageSetting ps3 = createPackageSetting(PACKAGE_NAME_3);
@@ -283,33 +320,46 @@
         ps1.addOrUpdateSuspension("suspendingPackage2", dialogInfo2, appExtras2, launcherExtras2,
                 0);
         settingsUnderTest.mPackages.put(PACKAGE_NAME_1, ps1);
+        watcher.verifyChangeReported("put package 1");
 
         ps2.addOrUpdateSuspension("suspendingPackage3", null, appExtras1, null, 0);
         settingsUnderTest.mPackages.put(PACKAGE_NAME_2, ps2);
+        watcher.verifyChangeReported("put package 2");
 
         ps3.removeSuspension("irrelevant", 0);
         settingsUnderTest.mPackages.put(PACKAGE_NAME_3, ps3);
+        watcher.verifyChangeReported("put package 3");
 
         settingsUnderTest.writePackageRestrictionsLPr(0);
+        watcher.verifyChangeReported("writePackageRestrictions");
 
         settingsUnderTest.mPackages.clear();
+        watcher.verifyChangeReported("clear packages");
         settingsUnderTest.mPackages.put(PACKAGE_NAME_1, createPackageSetting(PACKAGE_NAME_1));
+        watcher.verifyChangeReported("put package 1");
         settingsUnderTest.mPackages.put(PACKAGE_NAME_2, createPackageSetting(PACKAGE_NAME_2));
+        watcher.verifyChangeReported("put package 2");
         settingsUnderTest.mPackages.put(PACKAGE_NAME_3, createPackageSetting(PACKAGE_NAME_3));
+        watcher.verifyChangeReported("put package 3");
         // now read and verify
         settingsUnderTest.readPackageRestrictionsLPr(0);
+        watcher.verifyChangeReported("readPackageRestrictions");
         final PackageUserState readPus1 = settingsUnderTest.mPackages.get(PACKAGE_NAME_1)
                 .readUserState(0);
+        watcher.verifyNoChangeReported("package get 1");
         assertThat(readPus1.suspended, is(true));
         assertThat(readPus1.suspendParams.size(), is(2));
+        watcher.verifyNoChangeReported("read package param");
 
         assertThat(readPus1.suspendParams.keyAt(0), is("suspendingPackage1"));
         final PackageUserState.SuspendParams params11 = readPus1.suspendParams.valueAt(0);
+        watcher.verifyNoChangeReported("read package param");
         assertThat(params11, is(notNullValue()));
         assertThat(params11.dialogInfo, is(dialogInfo1));
         assertThat(BaseBundle.kindofEquals(params11.appExtras, appExtras1), is(true));
         assertThat(BaseBundle.kindofEquals(params11.launcherExtras, launcherExtras1),
                 is(true));
+        watcher.verifyNoChangeReported("read package param");
 
         assertThat(readPus1.suspendParams.keyAt(1), is("suspendingPackage2"));
         final PackageUserState.SuspendParams params12 = readPus1.suspendParams.valueAt(1);
@@ -318,6 +368,7 @@
         assertThat(BaseBundle.kindofEquals(params12.appExtras, appExtras2), is(true));
         assertThat(BaseBundle.kindofEquals(params12.launcherExtras, launcherExtras2),
                 is(true));
+        watcher.verifyNoChangeReported("read package param");
 
         final PackageUserState readPus2 = settingsUnderTest.mPackages.get(PACKAGE_NAME_2)
                 .readUserState(0);
@@ -329,11 +380,13 @@
         assertThat(params21.dialogInfo, is(nullValue()));
         assertThat(BaseBundle.kindofEquals(params21.appExtras, appExtras1), is(true));
         assertThat(params21.launcherExtras, is(nullValue()));
+        watcher.verifyNoChangeReported("read package param");
 
         final PackageUserState readPus3 = settingsUnderTest.mPackages.get(PACKAGE_NAME_3)
                 .readUserState(0);
         assertThat(readPus3.suspended, is(false));
         assertThat(readPus3.suspendParams, is(nullValue()));
+        watcher.verifyNoChangeReported("package get 3");
     }
 
     @Test
@@ -467,14 +520,23 @@
         final Object lock = new Object();
         Settings settings = new Settings(context.getFilesDir(),
                 mRuntimePermissionsPersistence, mPermissionDataProvider, lock);
+        final WatchableTester watcher = new WatchableTester(settings, "testEnableDisable");
+        watcher.register();
         assertThat(settings.readLPw(createFakeUsers()), is(true));
+        watcher.verifyChangeReported("readLPw");
 
         // Enable/Disable a package
         PackageSetting ps = settings.getPackageLPr(PACKAGE_NAME_1);
+        watcher.verifyNoChangeReported("getPackageLPr");
+        assertThat(ps.getEnabled(0), is(not(COMPONENT_ENABLED_STATE_DISABLED)));
+        assertThat(ps.getEnabled(1), is(not(COMPONENT_ENABLED_STATE_ENABLED)));
         ps.setEnabled(COMPONENT_ENABLED_STATE_DISABLED, 0, null);
+        watcher.verifyChangeReported("setEnabled DISABLED");
         ps.setEnabled(COMPONENT_ENABLED_STATE_ENABLED, 1, null);
+        watcher.verifyChangeReported("setEnabled ENABLED");
         assertThat(ps.getEnabled(0), is(COMPONENT_ENABLED_STATE_DISABLED));
         assertThat(ps.getEnabled(1), is(COMPONENT_ENABLED_STATE_ENABLED));
+        watcher.verifyNoChangeReported("getEnabled");
 
         // Enable/Disable a component
         ArraySet<String> components = new ArraySet<String>();
@@ -1152,7 +1214,8 @@
 
     private void verifyKeySetMetaData(Settings settings)
             throws ReflectiveOperationException, IllegalAccessException {
-        ArrayMap<String, PackageSetting> packages = settings.mPackages;
+        ArrayMap<String, PackageSetting> packages =
+                settings.mPackages.untrackedMap();
         KeySetManagerService ksms = settings.mKeySetManagerService;
 
         /* verify keyset and public key ref counts */
diff --git a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest4.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest4.java
index 583c3d4..7546c43 100644
--- a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest4.java
+++ b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest4.java
@@ -25,8 +25,16 @@
 import android.os.Bundle;
 import android.os.PersistableBundle;
 import android.test.suitebuilder.annotation.SmallTest;
+import android.util.Xml;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Assume;
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
 @SmallTest
+@RunWith(AndroidJUnit4.class)
 public class ShortcutManagerTest4 extends BaseShortcutManagerTest {
 
     private static Bundle sIntentExtras = makeBundle(
@@ -99,7 +107,10 @@
             "x2", "value{?}"
     );
 
+    @Test
     public void testPersistingWeirdCharacters() {
+        Assume.assumeFalse(Xml.ENABLE_BINARY_DEFAULT);
+
         final Intent intent = new Intent(Intent.ACTION_MAIN)
                 .putExtras(sIntentExtras);
 
diff --git a/services/tests/servicestests/src/com/android/server/powerstats/PowerStatsServiceTest.java b/services/tests/servicestests/src/com/android/server/powerstats/PowerStatsServiceTest.java
index b26d1efe..08d4caa 100644
--- a/services/tests/servicestests/src/com/android/server/powerstats/PowerStatsServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/powerstats/PowerStatsServiceTest.java
@@ -209,7 +209,7 @@
         }
 
         @Override
-        public boolean initialize() {
+        public boolean isInitialized() {
             return true;
         }
     }
diff --git a/services/tests/servicestests/src/com/android/server/vibrator/InputDeviceDelegateTest.java b/services/tests/servicestests/src/com/android/server/vibrator/InputDeviceDelegateTest.java
index fa8e367..ac93ff6 100644
--- a/services/tests/servicestests/src/com/android/server/vibrator/InputDeviceDelegateTest.java
+++ b/services/tests/servicestests/src/com/android/server/vibrator/InputDeviceDelegateTest.java
@@ -44,6 +44,7 @@
 
 import androidx.test.InstrumentationRegistry;
 
+import org.junit.After;
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
@@ -89,6 +90,11 @@
                 mContextSpy, new Handler(mTestLooper.getLooper()));
     }
 
+    @After
+    public void tearDown() throws Exception {
+        InputManager.clearInstance();
+    }
+
     @Test
     public void onInputDeviceAdded_withSettingsDisabled_ignoresNewDevice() throws Exception {
         when(mIInputManagerMock.getInputDeviceIds()).thenReturn(new int[0]);
@@ -286,6 +292,6 @@
 
     private InputDevice createInputDevice(int id, boolean hasVibrator) {
         return new InputDevice(id, 0, 0, "name", 0, 0, "description", false, 0, 0,
-                null, hasVibrator, false, false);
+                null, hasVibrator, false, false, false /* hasSensor */);
     }
 }
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 f7c655f..a18bce7 100755
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -111,9 +111,9 @@
 import android.content.ComponentName;
 import android.content.ContentUris;
 import android.content.Context;
-import android.content.IIntentSender;
 import android.content.Intent;
 import android.content.IntentFilter;
+import android.content.IIntentSender;
 import android.content.pm.ActivityInfo;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.IPackageManager;
@@ -1501,6 +1501,20 @@
     }
 
     @Test
+    public void testCancelImmediatelyAfterEnqueueNotifiesListeners_ForegroundServiceFlag()
+            throws Exception {
+        final StatusBarNotification sbn = generateNotificationRecord(null).getSbn();
+        sbn.getNotification().flags =
+                Notification.FLAG_ONGOING_EVENT | FLAG_FOREGROUND_SERVICE;
+        mBinderService.enqueueNotificationWithTag(PKG, PKG, "tag",
+                sbn.getId(), sbn.getNotification(), sbn.getUserId());
+        mBinderService.cancelNotificationWithTag(PKG, PKG, "tag", sbn.getId(), sbn.getUserId());
+        waitForIdle();
+        verify(mListeners, times(1)).notifyPostedLocked(any(), any());
+        verify(mListeners, times(1)).notifyRemovedLocked(any(), anyInt(), any());
+    }
+
+    @Test
     public void testUserInitiatedClearAll_noLeak() throws Exception {
         final NotificationRecord n = generateNotificationRecord(
                 mTestNotificationChannel, 1, "group", true);
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityDisplayTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityDisplayTests.java
index 466b861..801a27d 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityDisplayTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityDisplayTests.java
@@ -248,7 +248,7 @@
         int topPosition = taskDisplayArea.getRootTaskCount() - 1;
         // Ensure the new alwaysOnTop stack is put below the pinned stack, but on top of the
         // existing alwaysOnTop stack.
-        assertEquals(topPosition - 1, taskDisplayArea.getIndexOf(anotherAlwaysOnTopStack));
+        assertEquals(topPosition - 1, taskDisplayArea.getTaskIndexOf(anotherAlwaysOnTopStack));
 
         final Task nonAlwaysOnTopStack = taskDisplayArea.createRootTask(
                 WINDOWING_MODE_FREEFORM, ACTIVITY_TYPE_STANDARD, true /* onTop */);
@@ -256,7 +256,7 @@
         topPosition = taskDisplayArea.getRootTaskCount() - 1;
         // Ensure the non-alwaysOnTop stack is put below the three alwaysOnTop stacks, but above the
         // existing other non-alwaysOnTop stacks.
-        assertEquals(topPosition - 3, taskDisplayArea.getIndexOf(nonAlwaysOnTopStack));
+        assertEquals(topPosition - 3, taskDisplayArea.getTaskIndexOf(nonAlwaysOnTopStack));
 
         anotherAlwaysOnTopStack.setAlwaysOnTop(false);
         taskDisplayArea.positionChildAt(POSITION_TOP, anotherAlwaysOnTopStack,
@@ -264,16 +264,16 @@
         assertFalse(anotherAlwaysOnTopStack.isAlwaysOnTop());
         // Ensure, when always on top is turned off for a stack, the stack is put just below all
         // other always on top stacks.
-        assertEquals(topPosition - 2, taskDisplayArea.getIndexOf(anotherAlwaysOnTopStack));
+        assertEquals(topPosition - 2, taskDisplayArea.getTaskIndexOf(anotherAlwaysOnTopStack));
         anotherAlwaysOnTopStack.setAlwaysOnTop(true);
 
         // Ensure always on top state changes properly when windowing mode changes.
         anotherAlwaysOnTopStack.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
         assertFalse(anotherAlwaysOnTopStack.isAlwaysOnTop());
-        assertEquals(topPosition - 2, taskDisplayArea.getIndexOf(anotherAlwaysOnTopStack));
+        assertEquals(topPosition - 2, taskDisplayArea.getTaskIndexOf(anotherAlwaysOnTopStack));
         anotherAlwaysOnTopStack.setWindowingMode(WINDOWING_MODE_FREEFORM);
         assertTrue(anotherAlwaysOnTopStack.isAlwaysOnTop());
-        assertEquals(topPosition - 1, taskDisplayArea.getIndexOf(anotherAlwaysOnTopStack));
+        assertEquals(topPosition - 1, taskDisplayArea.getTaskIndexOf(anotherAlwaysOnTopStack));
 
         final Task dreamStack = taskDisplayArea.createRootTask(
                 WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_DREAM, true /* onTop */);
@@ -282,7 +282,7 @@
         topPosition = taskDisplayArea.getRootTaskCount() - 1;
         // Ensure dream shows above all activities, including PiP
         assertEquals(dreamStack, taskDisplayArea.getTopRootTask());
-        assertEquals(topPosition - 1, taskDisplayArea.getIndexOf(pinnedStack));
+        assertEquals(topPosition - 1, taskDisplayArea.getTaskIndexOf(pinnedStack));
 
         final Task assistStack = taskDisplayArea.createRootTask(
                 WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_ASSISTANT, true /* onTop */);
@@ -295,7 +295,7 @@
         final boolean isAssistantOnTop = mContext.getResources()
                 .getBoolean(com.android.internal.R.bool.config_assistantOnTopOfDream);
         assertEquals(isAssistantOnTop ? topPosition : topPosition - 4,
-                taskDisplayArea.getIndexOf(assistStack));
+                taskDisplayArea.getTaskIndexOf(assistStack));
     }
 
     @Test
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
index 2d71d7f..95a1b61 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
@@ -75,7 +75,6 @@
 import static org.mockito.Mockito.clearInvocations;
 import static org.mockito.Mockito.never;
 
-import android.window.TaskSnapshot;
 import android.app.ActivityOptions;
 import android.app.WindowConfiguration;
 import android.app.servertransaction.ActivityConfigurationChangeItem;
@@ -102,6 +101,7 @@
 import android.view.RemoteAnimationTarget;
 import android.view.WindowManager;
 import android.view.WindowManagerGlobal;
+import android.window.TaskSnapshot;
 
 import androidx.test.filters.MediumTest;
 
@@ -1662,7 +1662,8 @@
                     any() /* requestedVisibility */, any() /* outFrame */,
                     any() /* outDisplayCutout */, any() /* outInputChannel */,
                     any() /* outInsetsState */, any() /* outActiveControls */);
-            TaskSnapshotSurface.create(mAtm.mWindowManager, activity, snapshot);
+            mAtm.mWindowManager.mStartingSurfaceController
+                    .createTaskSnapshotSurface(activity, snapshot);
         } catch (RemoteException ignored) {
         } finally {
             reset(session);
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java
index 5504460..8ea95ae 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java
@@ -167,7 +167,7 @@
                 null /* task */);
 
         // Assert that stack is at the bottom.
-        assertEquals(0, mDefaultTaskDisplayArea.getIndexOf(primarySplitScreen));
+        assertEquals(0, mDefaultTaskDisplayArea.getTaskIndexOf(primarySplitScreen));
 
         // Ensure no longer in splitscreen.
         assertEquals(WINDOWING_MODE_FULLSCREEN, primarySplitScreen.getWindowingMode());
@@ -748,10 +748,10 @@
         doReturn(false).when(fullscreenStack).isTranslucent(any());
 
         // Ensure that we don't move the home stack if it is already behind the top fullscreen stack
-        int homeStackIndex = mDefaultTaskDisplayArea.getIndexOf(homeStack);
+        int homeStackIndex = mDefaultTaskDisplayArea.getTaskIndexOf(homeStack);
         assertEquals(fullscreenStack, getRootTaskAbove(homeStack));
         mDefaultTaskDisplayArea.moveRootTaskBehindBottomMostVisibleRootTask(homeStack);
-        assertEquals(homeStackIndex, mDefaultTaskDisplayArea.getIndexOf(homeStack));
+        assertEquals(homeStackIndex, mDefaultTaskDisplayArea.getTaskIndexOf(homeStack));
     }
 
     @Test
@@ -766,10 +766,10 @@
         doReturn(true).when(fullscreenStack).isTranslucent(any());
 
         // Ensure that we don't move the home stack if it is already behind the top fullscreen stack
-        int homeStackIndex = mDefaultTaskDisplayArea.getIndexOf(homeStack);
+        int homeStackIndex = mDefaultTaskDisplayArea.getTaskIndexOf(homeStack);
         assertEquals(fullscreenStack, getRootTaskAbove(homeStack));
         mDefaultTaskDisplayArea.moveRootTaskBehindBottomMostVisibleRootTask(homeStack);
-        assertEquals(homeStackIndex, mDefaultTaskDisplayArea.getIndexOf(homeStack));
+        assertEquals(homeStackIndex, mDefaultTaskDisplayArea.getTaskIndexOf(homeStack));
     }
 
     @Test
@@ -784,10 +784,10 @@
         doReturn(false).when(fullscreenStack).isTranslucent(any());
 
         // Ensure we don't move the home stack if it is already on top
-        int homeStackIndex = mDefaultTaskDisplayArea.getIndexOf(homeStack);
+        int homeStackIndex = mDefaultTaskDisplayArea.getTaskIndexOf(homeStack);
         assertNull(getRootTaskAbove(homeStack));
         mDefaultTaskDisplayArea.moveRootTaskBehindBottomMostVisibleRootTask(homeStack);
-        assertEquals(homeStackIndex, mDefaultTaskDisplayArea.getIndexOf(homeStack));
+        assertEquals(homeStackIndex, mDefaultTaskDisplayArea.getTaskIndexOf(homeStack));
     }
 
     @Test
@@ -853,9 +853,9 @@
         doReturn(false).when(fullscreenStack2).isTranslucent(any());
 
         // Ensure we don't move the home stack behind itself
-        int homeStackIndex = mDefaultTaskDisplayArea.getIndexOf(homeStack);
+        int homeStackIndex = mDefaultTaskDisplayArea.getTaskIndexOf(homeStack);
         mDefaultTaskDisplayArea.moveRootTaskBehindRootTask(homeStack, homeStack);
-        assertEquals(homeStackIndex, mDefaultTaskDisplayArea.getIndexOf(homeStack));
+        assertEquals(homeStackIndex, mDefaultTaskDisplayArea.getTaskIndexOf(homeStack));
     }
 
     @Test
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
index 76e98ab..cde866b 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
@@ -512,8 +512,8 @@
     }
 
     private void assertNoTasks(DisplayContent display) {
-        display.forAllRootTasks(stack -> {
-            assertFalse(stack.hasChild());
+        display.forAllRootTasks(rootTask -> {
+            assertFalse(rootTask.hasChild());
         });
     }
 
diff --git a/services/tests/wmtests/src/com/android/server/wm/DimmerTests.java b/services/tests/wmtests/src/com/android/server/wm/DimmerTests.java
index f7beb74..3beb7f2 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DimmerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DimmerTests.java
@@ -199,7 +199,7 @@
         mHost.addChild(child, 0);
 
         final float alpha = 0.8f;
-        mDimmer.dimBelow(mTransaction, child, alpha);
+        mDimmer.dimBelow(mTransaction, child, alpha, 0);
         SurfaceControl dimLayer = getDimLayer();
 
         assertNotNull("Dimmer should have created a surface", dimLayer);
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayAreaOrganizerTest.java b/services/tests/wmtests/src/com/android/server/wm/DisplayAreaOrganizerTest.java
index 1198ee2..5597be9 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayAreaOrganizerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayAreaOrganizerTest.java
@@ -17,6 +17,7 @@
 package com.android.server.wm;
 
 import static android.view.Display.DEFAULT_DISPLAY;
+import static android.window.DisplayAreaOrganizer.FEATURE_DEFAULT_TASK_CONTAINER;
 import static android.window.DisplayAreaOrganizer.FEATURE_ROOT;
 import static android.window.DisplayAreaOrganizer.FEATURE_RUNTIME_TASK_CONTAINER_FIRST;
 import static android.window.DisplayAreaOrganizer.FEATURE_VENDOR_FIRST;
@@ -117,7 +118,7 @@
     }
 
     @Test
-    public void testCreateTaskDisplayArea() {
+    public void testCreateTaskDisplayArea_topBelowRoot() {
         final String newTdaName = "testTda";
         final IDisplayAreaOrganizer organizer = createMockOrganizer(new Binder());
         final DisplayAreaAppearedInfo tdaInfo = mOrganizerController.createTaskDisplayArea(
@@ -142,6 +143,30 @@
     }
 
     @Test
+    public void testCreateTaskDisplayArea_topBelowAnotherTaskDisplayArea() {
+        final String newTdaName = "testTda";
+        final TaskDisplayArea parentTda = mDisplayContent.getDefaultTaskDisplayArea();
+        final IDisplayAreaOrganizer organizer = createMockOrganizer(new Binder());
+        final DisplayAreaAppearedInfo tdaInfo = mOrganizerController.createTaskDisplayArea(
+                organizer, DEFAULT_DISPLAY, FEATURE_DEFAULT_TASK_CONTAINER, newTdaName);
+
+        final WindowContainer wc = parentTda.getChildAt(parentTda.getChildCount() - 1);
+
+        // A new TaskDisplayArea is created on the top.
+        assertThat(wc).isInstanceOf(TaskDisplayArea.class);
+        assertThat(tdaInfo.getDisplayAreaInfo().displayId).isEqualTo(DEFAULT_DISPLAY);
+        assertThat(tdaInfo.getDisplayAreaInfo().token)
+                .isEqualTo(wc.mRemoteToken.toWindowContainerToken());
+
+        final TaskDisplayArea tda = wc.asTaskDisplayArea();
+
+        assertThat(tda.getName()).isEqualTo(newTdaName);
+        assertThat(tda.mFeatureId).isEqualTo(tdaInfo.getDisplayAreaInfo().featureId);
+        assertThat(tda.mCreatedByOrganizer).isTrue();
+        assertThat(tda.mOrganizer).isEqualTo(organizer);
+    }
+
+    @Test
     public void testCreateTaskDisplayArea_incrementalTdaFeatureId() {
         final String newTdaName = "testTda";
         final IDisplayAreaOrganizer organizer = createMockOrganizer(new Binder());
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayAreaPolicyBuilderTest.java b/services/tests/wmtests/src/com/android/server/wm/DisplayAreaPolicyBuilderTest.java
index fb585ed..b33bb7b 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayAreaPolicyBuilderTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayAreaPolicyBuilderTest.java
@@ -41,7 +41,6 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
-import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
 import static org.testng.Assert.assertThrows;
@@ -102,7 +101,6 @@
         mRoot = new SurfacelessDisplayAreaRoot(mWms);
         mImeContainer = new DisplayArea.Tokens(mWms, ABOVE_TASKS, "ImeContainer");
         mDisplayContent = mock(DisplayContent.class);
-        doReturn(true).when(mDisplayContent).isTrusted();
         mDefaultTaskDisplayArea = new TaskDisplayArea(mDisplayContent, mWms, "Tasks",
                 FEATURE_DEFAULT_TASK_CONTAINER);
         mTaskDisplayAreaList = new ArrayList<>();
@@ -702,7 +700,7 @@
     private Map<DisplayArea<?>, Set<Integer>> calculateZSets(
             DisplayAreaPolicyBuilder.Result policy,
             DisplayArea.Tokens ime,
-            DisplayArea<Task> tasks) {
+            TaskDisplayArea taskDisplayArea) {
         Map<DisplayArea<?>, Set<Integer>> zSets = new HashMap<>();
         int[] types = {TYPE_STATUS_BAR, TYPE_NAVIGATION_BAR, TYPE_PRESENTATION,
                 TYPE_APPLICATION_OVERLAY};
@@ -710,7 +708,7 @@
             WindowToken token = tokenOfType(type);
             recordLayer(policy.findAreaForToken(token), token.getWindowLayerFromType(), zSets);
         }
-        recordLayer(tasks, APPLICATION_LAYER, zSets);
+        recordLayer(taskDisplayArea, APPLICATION_LAYER, zSets);
         recordLayer(ime, mPolicy.getWindowLayerFromTypeLw(TYPE_INPUT_METHOD), zSets);
         return zSets;
     }
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayAreaPolicyTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayAreaPolicyTests.java
index d451180..496b2b7 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayAreaPolicyTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayAreaPolicyTests.java
@@ -22,18 +22,15 @@
 import static android.window.DisplayAreaOrganizer.FEATURE_VENDOR_FIRST;
 
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
 import static com.android.server.wm.DisplayArea.Type.ABOVE_TASKS;
 import static com.android.server.wm.WindowContainer.POSITION_BOTTOM;
 import static com.android.server.wm.WindowContainer.POSITION_TOP;
 
 import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
 import static org.mockito.Mockito.mock;
 
 import android.platform.test.annotations.Presubmit;
-import android.util.Pair;
-import android.view.Display;
-import android.view.DisplayInfo;
 
 import androidx.test.filters.SmallTest;
 
@@ -41,8 +38,9 @@
 
 import com.google.android.collect.Lists;
 
+import org.junit.Before;
+import org.junit.Rule;
 import org.junit.Test;
-import org.junit.runner.RunWith;
 
 import java.util.ArrayList;
 import java.util.Collections;
@@ -56,65 +54,78 @@
  */
 @SmallTest
 @Presubmit
-@RunWith(WindowTestRunner.class)
-public class DisplayAreaPolicyTests extends WindowTestsBase {
+public class DisplayAreaPolicyTests {
+
+    @Rule
+    public final SystemServicesTestRule mSystemServices = new SystemServicesTestRule();
+
+    private DisplayAreaPolicyBuilder.Result mPolicy;
+    private TaskDisplayArea mTaskDisplayArea1;
+    private TaskDisplayArea mTaskDisplayArea2;
+    private RootDisplayArea mRoot;
+
+    @Before
+    public void setUp() throws Exception {
+        WindowManagerService wms = mSystemServices.getWindowManagerService();
+        mRoot = new SurfacelessDisplayAreaRoot(wms);
+        spyOn(mRoot);
+        DisplayArea.Tokens ime = new DisplayArea.Tokens(wms, ABOVE_TASKS, "Ime");
+        DisplayContent displayContent = mock(DisplayContent.class);
+        doReturn(true).when(displayContent).isTrusted();
+        mTaskDisplayArea1 = new TaskDisplayArea(displayContent, wms, "Tasks1",
+                FEATURE_DEFAULT_TASK_CONTAINER);
+        mTaskDisplayArea2 = new TaskDisplayArea(displayContent, wms, "Tasks2",
+                FEATURE_VENDOR_FIRST);
+        List<TaskDisplayArea> taskDisplayAreaList = new ArrayList<>();
+        taskDisplayAreaList.add(mTaskDisplayArea1);
+        taskDisplayAreaList.add(mTaskDisplayArea2);
+
+        mPolicy = new DisplayAreaPolicyBuilder()
+                .setRootHierarchy(new DisplayAreaPolicyBuilder.HierarchyBuilder(mRoot)
+                        .setImeContainer(ime)
+                        .setTaskDisplayAreas(taskDisplayAreaList))
+                .build(wms);
+    }
 
     @Test
     public void testGetDefaultTaskDisplayArea() {
-        final Pair<DisplayAreaPolicy, List<TaskDisplayArea>> result =
-                createPolicyWith2TaskDisplayAreas();
-        final DisplayAreaPolicy policy = result.first;
-        final TaskDisplayArea taskDisplayArea1 = result.second.get(0);
-        assertEquals(taskDisplayArea1, policy.getDefaultTaskDisplayArea());
+        assertEquals(mTaskDisplayArea1, mPolicy.getDefaultTaskDisplayArea());
     }
 
     @Test
     public void testTaskDisplayArea_taskPositionChanged_updatesTaskDisplayAreaPosition() {
-        final Pair<DisplayAreaPolicy, List<TaskDisplayArea>> result =
-                createPolicyWith2TaskDisplayAreas();
-        final DisplayAreaPolicy policy = result.first;
-        final TaskDisplayArea taskDisplayArea1 = result.second.get(0);
-        final TaskDisplayArea taskDisplayArea2 = result.second.get(1);
-        final Task stack1 = taskDisplayArea1.createRootTask(
+        final Task stack1 = mTaskDisplayArea1.createRootTask(
                 WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */);
-        final Task stack2 = taskDisplayArea2.createRootTask(
+        final Task stack2 = mTaskDisplayArea2.createRootTask(
                 WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */);
 
         // Initial order
-        assertTaskDisplayAreasOrder(policy, taskDisplayArea1, taskDisplayArea2);
+        assertTaskDisplayAreasOrder(mPolicy, mTaskDisplayArea1, mTaskDisplayArea2);
 
         // Move stack in tda1 to top
         stack1.getParent().positionChildAt(POSITION_TOP, stack1, true /* includingParents */);
 
-        assertTaskDisplayAreasOrder(policy, taskDisplayArea2, taskDisplayArea1);
+        assertTaskDisplayAreasOrder(mPolicy, mTaskDisplayArea2, mTaskDisplayArea1);
 
         // Move stack in tda2 to top, but not including parents
         stack2.getParent().positionChildAt(POSITION_TOP, stack2, false /* includingParents */);
 
-        assertTaskDisplayAreasOrder(policy, taskDisplayArea2, taskDisplayArea1);
+        assertTaskDisplayAreasOrder(mPolicy, mTaskDisplayArea2, mTaskDisplayArea1);
 
         // Move stack in tda1 to bottom
         stack1.getParent().positionChildAt(POSITION_BOTTOM, stack1, true /* includingParents */);
 
-        assertTaskDisplayAreasOrder(policy, taskDisplayArea1, taskDisplayArea2);
+        assertTaskDisplayAreasOrder(mPolicy, mTaskDisplayArea1, mTaskDisplayArea2);
 
         // Move stack in tda2 to bottom, but not including parents
         stack2.getParent().positionChildAt(POSITION_BOTTOM, stack2, false /* includingParents */);
 
-        assertTaskDisplayAreasOrder(policy, taskDisplayArea1, taskDisplayArea2);
-    }
-
-    @Test
-    public void testEmptyFeaturesOnUntrustedDisplay() {
-        final DisplayInfo info = new DisplayInfo(mDisplayInfo);
-        info.flags &= ~Display.FLAG_TRUSTED;
-        final DisplayContent untrustedDisplay = new TestDisplayContent.Builder(mAtm, info).build();
-        assertTrue(untrustedDisplay.mFeatures.isEmpty());
+        assertTaskDisplayAreasOrder(mPolicy, mTaskDisplayArea1, mTaskDisplayArea2);
     }
 
     @Test
     public void testDisplayAreaGroup_taskPositionChanged_updatesDisplayAreaGroupPosition() {
-        final WindowManagerService wms = mWm;
+        final WindowManagerService wms = mSystemServices.getWindowManagerService();
         final DisplayContent displayContent = mock(DisplayContent.class);
         doReturn(true).when(displayContent).isTrusted();
         final RootDisplayArea root = new SurfacelessDisplayAreaRoot(wms);
@@ -192,24 +203,4 @@
         }, false /* traverseTopToBottom */);
         assertEquals(expectOrder, actualOrder);
     }
-
-    private Pair<DisplayAreaPolicy, List<TaskDisplayArea>> createPolicyWith2TaskDisplayAreas() {
-        final SurfacelessDisplayAreaRoot root = new SurfacelessDisplayAreaRoot(mWm);
-        final DisplayArea.Tokens ime = new DisplayArea.Tokens(mWm, ABOVE_TASKS, "Ime");
-        final DisplayContent displayContent = mock(DisplayContent.class);
-        doReturn(true).when(displayContent).isTrusted();
-        final TaskDisplayArea taskDisplayArea1 = new TaskDisplayArea(displayContent, mWm, "Tasks1",
-                FEATURE_DEFAULT_TASK_CONTAINER);
-        final TaskDisplayArea taskDisplayArea2 = new TaskDisplayArea(displayContent, mWm, "Tasks2",
-                FEATURE_VENDOR_FIRST);
-        final List<TaskDisplayArea> taskDisplayAreaList = new ArrayList<>();
-        taskDisplayAreaList.add(taskDisplayArea1);
-        taskDisplayAreaList.add(taskDisplayArea2);
-
-        return Pair.create(new DisplayAreaPolicyBuilder()
-                .setRootHierarchy(new DisplayAreaPolicyBuilder.HierarchyBuilder(root)
-                        .setImeContainer(ime)
-                        .setTaskDisplayAreas(taskDisplayAreaList))
-                .build(mWm), taskDisplayAreaList);
-    }
 }
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
index b451d9f..69b8ccf 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
@@ -50,6 +50,7 @@
 import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR;
 import static android.view.WindowManager.LayoutParams.TYPE_VOICE_INTERACTION;
 import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
+import static android.window.DisplayAreaOrganizer.FEATURE_WINDOWED_MAGNIFICATION;
 
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.any;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyBoolean;
@@ -106,6 +107,7 @@
 import android.view.InsetsState;
 import android.view.MotionEvent;
 import android.view.Surface;
+import android.view.SurfaceControl;
 import android.view.SurfaceControl.Transaction;
 import android.view.WindowManager;
 
@@ -1534,6 +1536,22 @@
     }
 
     @Test
+    public void testValidWindowingLayer() {
+        final SurfaceControl windowingLayer = mDisplayContent.getWindowingLayer();
+        assertNotNull(windowingLayer);
+
+        final List<DisplayArea<?>> windowedMagnificationAreas =
+                mDisplayContent.mDisplayAreaPolicy.getDisplayAreas(FEATURE_WINDOWED_MAGNIFICATION);
+        if (windowedMagnificationAreas != null) {
+            assertEquals("There should be only one DisplayArea for FEATURE_WINDOWED_MAGNIFICATION",
+                    1, windowedMagnificationAreas.size());
+            assertEquals(windowedMagnificationAreas.get(0).mSurfaceControl, windowingLayer);
+        } else {
+            assertNotEquals(mDisplayContent.mSurfaceControl, windowingLayer);
+        }
+    }
+
+    @Test
     public void testFindScrollCaptureTargetWindow_behindWindow() {
         DisplayContent display = createNewDisplay();
         Task stack = createTaskStackOnDisplay(display);
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayWindowSettingsProviderTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayWindowSettingsProviderTests.java
index 7c4f7db..33e8fc0 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayWindowSettingsProviderTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayWindowSettingsProviderTests.java
@@ -312,8 +312,7 @@
     private String getStoredDisplayAttributeValue(TestStorage storage, String attr)
             throws Exception {
         try (InputStream stream = storage.openRead()) {
-            TypedXmlPullParser parser = Xml.newFastPullParser();
-            parser.setInput(stream, StandardCharsets.UTF_8.name());
+            TypedXmlPullParser parser = Xml.resolvePullParser(stream);
             int type;
             while ((type = parser.next()) != XmlPullParser.START_TAG
                     && type != XmlPullParser.END_DOCUMENT) {
diff --git a/services/tests/wmtests/src/com/android/server/wm/StubTransaction.java b/services/tests/wmtests/src/com/android/server/wm/StubTransaction.java
index ecbfac8..eff6919 100644
--- a/services/tests/wmtests/src/com/android/server/wm/StubTransaction.java
+++ b/services/tests/wmtests/src/com/android/server/wm/StubTransaction.java
@@ -136,6 +136,11 @@
     }
 
     @Override
+    public SurfaceControl.Transaction setBackgroundBlurRadius(SurfaceControl sc, int radius) {
+        return this;
+    }
+
+    @Override
     public SurfaceControl.Transaction setLayerStack(SurfaceControl sc, int layerStack) {
         return this;
     }
diff --git a/services/tests/wmtests/src/com/android/server/wm/TestIWindow.java b/services/tests/wmtests/src/com/android/server/wm/TestIWindow.java
index b78d6bb..001afe3 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TestIWindow.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TestIWindow.java
@@ -116,10 +116,6 @@
     }
 
     @Override
-    public void dispatchPointerCaptureChanged(boolean hasCapture) {
-    }
-
-    @Override
     public void requestScrollCapture(IScrollCaptureCallbacks callbacks) throws RemoteException {
     }
 
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java
index 6b9993a..b7101c8 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java
@@ -74,13 +74,12 @@
 import android.view.SurfaceControl;
 import android.window.ITaskOrganizer;
 import android.window.IWindowContainerTransactionCallback;
+import android.window.StartingWindowInfo;
 import android.window.TaskAppearedInfo;
 import android.window.WindowContainerTransaction;
 
 import androidx.test.filters.SmallTest;
 
-import com.android.server.wm.TaskOrganizerController.PendingTaskEvent;
-
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -151,14 +150,10 @@
         final ITaskOrganizer organizer = registerMockOrganizer();
         final Task stack = createStack();
         final Task task = createTask(stack);
-        // Ensure events dispatch to organizer.
-        mWm.mAtmService.mTaskOrganizerController.dispatchPendingEvents();
 
         verify(organizer).onTaskAppeared(any(RunningTaskInfo.class), any(SurfaceControl.class));
 
         stack.removeImmediately();
-        // Ensure events dispatch to organizer.
-        mWm.mAtmService.mTaskOrganizerController.dispatchPendingEvents();
         verify(organizer).onTaskVanished(any());
     }
 
@@ -167,21 +162,15 @@
         final ITaskOrganizer organizer = registerMockOrganizer();
         final Task stack = createStack();
         final Task task = createTask(stack, false);
-        // Ensure events dispatch to organizer.
-        mWm.mAtmService.mTaskOrganizerController.dispatchPendingEvents();
 
         verify(organizer, never())
                 .onTaskAppeared(any(RunningTaskInfo.class), any(SurfaceControl.class));
         stack.setHasBeenVisible(true);
-        // Ensure events dispatch to organizer.
-        mWm.mAtmService.mTaskOrganizerController.dispatchPendingEvents();
         assertTrue(stack.getHasBeenVisible());
 
         verify(organizer).onTaskAppeared(any(RunningTaskInfo.class), any(SurfaceControl.class));
 
         stack.removeImmediately();
-        // Ensure events dispatch to organizer.
-        mWm.mAtmService.mTaskOrganizerController.dispatchPendingEvents();
         verify(organizer).onTaskVanished(any());
     }
 
@@ -206,16 +195,12 @@
         final ITaskOrganizer organizer = registerMockOrganizer();
         final Task stack = createStack();
         final Task task = createTask(stack, false /* fakeDraw */);
-        // Ensure events dispatch to organizer.
-        mWm.mAtmService.mTaskOrganizerController.dispatchPendingEvents();
 
         verify(organizer, never())
                 .onTaskAppeared(any(RunningTaskInfo.class), any(SurfaceControl.class));
         assertTrue(stack.isOrganized());
 
         mWm.mAtmService.mTaskOrganizerController.unregisterTaskOrganizer(organizer);
-        // Ensure events dispatch to organizer.
-        mWm.mAtmService.mTaskOrganizerController.dispatchPendingEvents();
         assertTaskVanished(organizer, false /* expectVanished */, stack);
         assertFalse(stack.isOrganized());
     }
@@ -225,16 +210,11 @@
         final ITaskOrganizer organizer = registerMockOrganizer();
         final Task stack = createStack();
         final Task task = createTask(stack);
-        // Ensure events dispatch to organizer.
-        mWm.mAtmService.mTaskOrganizerController.dispatchPendingEvents();
 
         verify(organizer).onTaskAppeared(any(RunningTaskInfo.class), any(SurfaceControl.class));
         assertTrue(stack.isOrganized());
 
         stack.setTaskOrganizer(null);
-        // Ensure events dispatch to organizer.
-        mWm.mAtmService.mTaskOrganizerController.dispatchPendingEvents();
-
         verify(organizer).onTaskVanished(any());
         assertFalse(stack.isOrganized());
     }
@@ -244,16 +224,11 @@
         final ITaskOrganizer organizer = registerMockOrganizer();
         final Task stack = createStack();
         final Task task = createTask(stack);
-        // Ensure events dispatch to organizer.
-        mWm.mAtmService.mTaskOrganizerController.dispatchPendingEvents();
 
         verify(organizer).onTaskAppeared(any(RunningTaskInfo.class), any(SurfaceControl.class));
         assertTrue(stack.isOrganized());
 
         mWm.mAtmService.mTaskOrganizerController.unregisterTaskOrganizer(organizer);
-        // Ensure events dispatch to organizer.
-        mWm.mAtmService.mTaskOrganizerController.dispatchPendingEvents();
-
         assertTaskVanished(organizer, true /* expectVanished */, stack);
         assertFalse(stack.isOrganized());
     }
@@ -268,8 +243,6 @@
         final Task task3 = createTask(stack3);
         final ArrayList<TaskAppearedInfo> existingTasks = new ArrayList<>();
         final ITaskOrganizer organizer = registerMockOrganizer(existingTasks);
-        // Ensure events dispatch to organizer.
-        mWm.mAtmService.mTaskOrganizerController.dispatchPendingEvents();
 
         // verify that tasks are returned and taskAppeared is not called
         assertContainsTasks(existingTasks, stack, stack2, stack3);
@@ -281,8 +254,6 @@
         // Now we replace the registration and verify the new organizer receives existing tasks
         final ArrayList<TaskAppearedInfo> existingTasks2 = new ArrayList<>();
         final ITaskOrganizer organizer2 = registerMockOrganizer(existingTasks2);
-        // Ensure events dispatch to organizer.
-        mWm.mAtmService.mTaskOrganizerController.dispatchPendingEvents();
         assertContainsTasks(existingTasks2, stack, stack2, stack3);
         verify(organizer2, times(0)).onTaskAppeared(any(RunningTaskInfo.class),
                 any(SurfaceControl.class));
@@ -294,8 +265,6 @@
         // Now we unregister the second one, the first one should automatically be reregistered
         // so we verify that it's now seeing changes.
         mWm.mAtmService.mTaskOrganizerController.unregisterTaskOrganizer(organizer2);
-        // Ensure events dispatch to organizer.
-        mWm.mAtmService.mTaskOrganizerController.dispatchPendingEvents();
         verify(organizer, times(3))
                 .onTaskAppeared(any(RunningTaskInfo.class), any(SurfaceControl.class));
         assertTaskVanished(organizer2, true /* expectVanished */, stack, stack2, stack3);
@@ -538,12 +507,12 @@
     public void testTileAddRemoveChild() {
         ITaskOrganizer listener = new ITaskOrganizer.Stub() {
             @Override
-            public void addStartingWindow(ActivityManager.RunningTaskInfo info, IBinder appToken) {
+            public void addStartingWindow(StartingWindowInfo info, IBinder appToken) {
 
             }
 
             @Override
-            public void removeStartingWindow(ActivityManager.RunningTaskInfo info) { }
+            public void removeStartingWindow(int taskId) { }
 
             @Override
             public void onTaskAppeared(RunningTaskInfo taskInfo, SurfaceControl leash) { }
@@ -603,12 +572,12 @@
         final boolean[] called = {false};
         ITaskOrganizer listener = new ITaskOrganizer.Stub() {
             @Override
-            public void addStartingWindow(ActivityManager.RunningTaskInfo info, IBinder appToken) {
+            public void addStartingWindow(StartingWindowInfo info, IBinder appToken) {
 
             }
 
             @Override
-            public void removeStartingWindow(ActivityManager.RunningTaskInfo info) { }
+            public void removeStartingWindow(int taskId) { }
 
             @Override
             public void onTaskAppeared(RunningTaskInfo taskInfo, SurfaceControl leash) { }
@@ -674,12 +643,12 @@
         final ArrayMap<IBinder, RunningTaskInfo> lastReportedTiles = new ArrayMap<>();
         ITaskOrganizer listener = new ITaskOrganizer.Stub() {
             @Override
-            public void addStartingWindow(ActivityManager.RunningTaskInfo info, IBinder appToken) {
+            public void addStartingWindow(StartingWindowInfo info, IBinder appToken) {
 
             }
 
             @Override
-            public void removeStartingWindow(ActivityManager.RunningTaskInfo info) { }
+            public void removeStartingWindow(int taskId) { }
 
             @Override
             public void onTaskAppeared(RunningTaskInfo taskInfo, SurfaceControl leash) { }
@@ -818,9 +787,9 @@
         RunningTaskInfo mInfo;
 
         @Override
-        public void addStartingWindow(ActivityManager.RunningTaskInfo info, IBinder appToken) { }
+        public void addStartingWindow(StartingWindowInfo info, IBinder appToken) { }
         @Override
-        public void removeStartingWindow(ActivityManager.RunningTaskInfo info) { }
+        public void removeStartingWindow(int taskId) { }
         @Override
         public void onTaskAppeared(RunningTaskInfo info, SurfaceControl leash) {
             mInfo = info;
@@ -887,8 +856,6 @@
                 .setAspectRatio(new Rational(3, 4)).build();
         mWm.mAtmService.mActivityClientController.setPictureInPictureParams(record.token, p2);
         waitUntilHandlersIdle();
-        // Ensure events dispatch to organizer.
-        mWm.mAtmService.mTaskOrganizerController.dispatchPendingEvents();
         assertNotNull(o.mChangedInfo);
         assertNotNull(o.mChangedInfo.pictureInPictureParams);
         final Rational ratio = o.mChangedInfo.pictureInPictureParams.getAspectRatioRational();
@@ -928,24 +895,16 @@
         stack.setTaskOrganizer(organizer);
         // setHasBeenVisible was already called once by the set-up code.
         stack.setHasBeenVisible(true);
-        // Ensure events dispatch to organizer.
-        mWm.mAtmService.mTaskOrganizerController.dispatchPendingEvents();
         verify(organizer, times(1))
                 .onTaskAppeared(any(RunningTaskInfo.class), any(SurfaceControl.class));
 
         stack.setTaskOrganizer(null);
-        // Ensure events dispatch to organizer.
-        mWm.mAtmService.mTaskOrganizerController.dispatchPendingEvents();
         verify(organizer, times(1)).onTaskVanished(any());
         stack.setTaskOrganizer(organizer);
-        // Ensure events dispatch to organizer.
-        mWm.mAtmService.mTaskOrganizerController.dispatchPendingEvents();
         verify(organizer, times(2))
                 .onTaskAppeared(any(RunningTaskInfo.class), any(SurfaceControl.class));
 
         stack.removeImmediately();
-        // Ensure events dispatch to organizer.
-        mWm.mAtmService.mTaskOrganizerController.dispatchPendingEvents();
         verify(organizer, times(2)).onTaskVanished(any());
     }
 
@@ -964,8 +923,6 @@
 
         // Verify a back pressed does not call the organizer
         mWm.mAtmService.mActivityClientController.onBackPressedOnTaskRoot(activity.token);
-        // Ensure events dispatch to organizer.
-        mWm.mAtmService.mTaskOrganizerController.dispatchPendingEvents();
         verify(organizer, never()).onBackPressedOnTaskRoot(any());
 
         // Enable intercepting back
@@ -974,8 +931,6 @@
 
         // Verify now that the back press does call the organizer
         mWm.mAtmService.mActivityClientController.onBackPressedOnTaskRoot(activity.token);
-        // Ensure events dispatch to organizer.
-        mWm.mAtmService.mTaskOrganizerController.dispatchPendingEvents();
         verify(organizer, times(1)).onBackPressedOnTaskRoot(any());
 
         // Disable intercepting back
@@ -984,8 +939,6 @@
 
         // Verify now that the back press no longer calls the organizer
         mWm.mAtmService.mActivityClientController.onBackPressedOnTaskRoot(activity.token);
-        // Ensure events dispatch to organizer.
-        mWm.mAtmService.mTaskOrganizerController.dispatchPendingEvents();
         verify(organizer, times(1)).onBackPressedOnTaskRoot(any());
     }
 
@@ -1066,151 +1019,6 @@
         assertTrue(task2.isOrganized());
     }
 
-    @Test
-    public void testAppearDeferThenInfoChange() {
-        final ITaskOrganizer organizer = registerMockOrganizer();
-        final Task stack = createStack();
-
-        // Assume layout defer
-        mWm.mWindowPlacerLocked.deferLayout();
-
-        final Task task = createTask(stack);
-        final ActivityRecord record = createActivityRecord(stack.mDisplayContent, task);
-
-        stack.setWindowingMode(WINDOWING_MODE_MULTI_WINDOW);
-        record.setTaskDescription(new ActivityManager.TaskDescription("TestDescription"));
-        waitUntilHandlersIdle();
-
-        ArrayList<PendingTaskEvent> pendingEvents = getTaskPendingEvent(stack);
-        assertEquals(1, pendingEvents.size());
-        assertEquals(PendingTaskEvent.EVENT_APPEARED, pendingEvents.get(0).mEventType);
-        assertEquals("TestDescription",
-                pendingEvents.get(0).mTask.getTaskInfo().taskDescription.getLabel());
-    }
-
-    @Test
-    public void testAppearDeferThenVanish() {
-        final ITaskOrganizer organizer = registerMockOrganizer();
-        final Task stack = createStack();
-
-        // Assume layout defer
-        mWm.mWindowPlacerLocked.deferLayout();
-
-        final Task task = createTask(stack);
-
-        stack.removeImmediately();
-        waitUntilHandlersIdle();
-
-        ArrayList<PendingTaskEvent> pendingEvents = getTaskPendingEvent(stack);
-        assertEquals(0, pendingEvents.size());
-    }
-
-    @Test
-    public void testInfoChangeDeferMultiple() {
-        final ITaskOrganizer organizer = registerMockOrganizer();
-        final Task stack = createStack();
-        final Task task = createTask(stack);
-        final ActivityRecord record = createActivityRecord(stack.mDisplayContent, task);
-
-        // Assume layout defer
-        mWm.mWindowPlacerLocked.deferLayout();
-
-        stack.setWindowingMode(WINDOWING_MODE_MULTI_WINDOW);
-        record.setTaskDescription(new ActivityManager.TaskDescription("TestDescription"));
-        waitUntilHandlersIdle();
-
-        ArrayList<PendingTaskEvent> pendingEvents = getTaskPendingEvent(stack);
-        assertEquals(1, pendingEvents.size());
-        assertEquals(PendingTaskEvent.EVENT_INFO_CHANGED, pendingEvents.get(0).mEventType);
-        assertEquals("TestDescription",
-                pendingEvents.get(0).mTask.getTaskInfo().taskDescription.getLabel());
-
-        record.setTaskDescription(new ActivityManager.TaskDescription("TestDescription2"));
-        waitUntilHandlersIdle();
-
-        pendingEvents = getTaskPendingEvent(stack);
-        assertEquals(1, pendingEvents.size());
-        assertEquals(PendingTaskEvent.EVENT_INFO_CHANGED, pendingEvents.get(0).mEventType);
-        assertEquals("TestDescription2",
-                pendingEvents.get(0).mTask.getTaskInfo().taskDescription.getLabel());
-    }
-
-    @Test
-    public void testInfoChangDeferThenVanish() {
-        final ITaskOrganizer organizer = registerMockOrganizer();
-        final Task stack = createStack();
-        final Task task = createTask(stack);
-        final ActivityRecord record = createActivityRecord(stack.mDisplayContent, task);
-
-        // Assume layout defer
-        mWm.mWindowPlacerLocked.deferLayout();
-
-        stack.setWindowingMode(WINDOWING_MODE_MULTI_WINDOW);
-        record.setTaskDescription(new ActivityManager.TaskDescription("TestDescription"));
-
-        stack.removeImmediately();
-        waitUntilHandlersIdle();
-
-        ArrayList<PendingTaskEvent> pendingEvents = getTaskPendingEvent(stack);
-        assertEquals(1, pendingEvents.size());
-        assertEquals(PendingTaskEvent.EVENT_VANISHED, pendingEvents.get(0).mEventType);
-        assertEquals("TestDescription",
-                pendingEvents.get(0).mTask.getTaskInfo().taskDescription.getLabel());
-    }
-
-    @Test
-    public void testVanishDeferThenInfoChange() {
-        final ITaskOrganizer organizer = registerMockOrganizer();
-        final Task stack = createStack();
-        final Task task = createTask(stack);
-        final ActivityRecord record = createActivityRecord(stack.mDisplayContent, task);
-
-        // Assume layout defer
-        mWm.mWindowPlacerLocked.deferLayout();
-
-        stack.removeImmediately();
-        stack.setWindowingMode(WINDOWING_MODE_MULTI_WINDOW);
-        waitUntilHandlersIdle();
-
-        ArrayList<PendingTaskEvent> pendingEvents = getTaskPendingEvent(stack);
-        assertEquals(1, pendingEvents.size());
-        assertEquals(PendingTaskEvent.EVENT_VANISHED, pendingEvents.get(0).mEventType);
-    }
-
-    @Test
-    public void testVanishDeferThenBackOnRoot() {
-        final ITaskOrganizer organizer = registerMockOrganizer();
-        final Task stack = createStack();
-        final Task task = createTask(stack);
-        final ActivityRecord record = createActivityRecord(stack.mDisplayContent, task);
-
-        // Assume layout defer
-        mWm.mWindowPlacerLocked.deferLayout();
-
-        stack.removeImmediately();
-        mWm.mAtmService.mActivityClientController.onBackPressedOnTaskRoot(record.token);
-        waitUntilHandlersIdle();
-
-        ArrayList<PendingTaskEvent> pendingEvents = getTaskPendingEvent(stack);
-        assertEquals(1, pendingEvents.size());
-        assertEquals(PendingTaskEvent.EVENT_VANISHED, pendingEvents.get(0).mEventType);
-    }
-
-    private ArrayList<PendingTaskEvent> getTaskPendingEvent(Task task) {
-        ArrayList<PendingTaskEvent> total =
-                mWm.mAtmService.mTaskOrganizerController.getPendingEventList();
-        ArrayList<PendingTaskEvent> result = new ArrayList();
-
-        for (int i = 0; i < total.size(); i++) {
-            PendingTaskEvent entry = total.get(i);
-            if (entry.mTask.mTaskId == task.mTaskId) {
-                result.add(entry);
-            }
-        }
-
-        return result;
-    }
-
     /**
      * Verifies that task vanished is called for a specific task.
      */
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
index 76f8207..592580a 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
@@ -739,6 +739,12 @@
         InputMonitor.setInputWindowInfoIfNeeded(transaction, sc, handleWrapper);
         verify(transaction, never()).setInputWindowInfo(any(), any());
 
+        // The rotated bounds have higher priority as the touchable region.
+        final Rect rotatedBounds = new Rect(0, 0, 123, 456);
+        doReturn(rotatedBounds).when(win.mToken).getFixedRotationTransformDisplayBounds();
+        mDisplayContent.getInputMonitor().populateInputWindowHandle(handleWrapper, win);
+        assertEquals(rotatedBounds, handle.touchableRegion.getBounds());
+
         // Populate as an overlay to disable the input of window.
         InputMonitor.populateOverlayInputInfo(handleWrapper, false /* isVisible */);
         // The overlay attributes should be set.
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
index e13a595..0d31d38 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
@@ -84,6 +84,7 @@
 import android.view.WindowManager;
 import android.view.WindowManager.DisplayImePolicy;
 import android.window.ITaskOrganizer;
+import android.window.StartingWindowInfo;
 
 import com.android.internal.util.ArrayUtils;
 import com.android.server.AttributeCache;
@@ -1090,10 +1091,10 @@
             mMoveToSecondaryOnEnter = move;
         }
         @Override
-        public void addStartingWindow(ActivityManager.RunningTaskInfo info, IBinder appToken) {
+        public void addStartingWindow(StartingWindowInfo info, IBinder appToken) {
         }
         @Override
-        public void removeStartingWindow(ActivityManager.RunningTaskInfo info) {
+        public void removeStartingWindow(int taskId) {
         }
         @Override
         public void onTaskAppeared(ActivityManager.RunningTaskInfo info, SurfaceControl leash) {
@@ -1121,9 +1122,9 @@
             mService.mTaskOrganizerController.setLaunchRoot(mDisplayId,
                     mSecondary.mRemoteToken.toWindowContainerToken());
             DisplayContent dc = mService.mRootWindowContainer.getDisplayContent(mDisplayId);
-            dc.forAllRootTasks(stack -> {
-                if (!WindowConfiguration.isSplitScreenWindowingMode(stack.getWindowingMode())) {
-                    stack.reparent(mSecondary, POSITION_BOTTOM);
+            dc.forAllRootTasks(rootTask -> {
+                if (!WindowConfiguration.isSplitScreenWindowingMode(rootTask.getWindowingMode())) {
+                    rootTask.reparent(mSecondary, POSITION_BOTTOM);
                 }
             });
         }
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index d645e86..56345c0 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -2050,7 +2050,13 @@
      * via {@link android.telecom.PhoneAccount#CAPABILITY_VIDEO_CALLING_RELIES_ON_PRESENCE}
      * and can choose to hide or show the video calling icon based on whether a contact supports
      * video.
+     *
+     * @deprecated No longer used in framework code, however it may still be used by applications
+     * that have not updated their code. This config should still be set to {@code true} if
+     * {@link Ims#KEY_RCS_BULK_CAPABILITY_EXCHANGE_BOOL} is set to {@code true} and
+     * {@link Ims#KEY_ENABLE_PRESENCE_CAPABILITY_EXCHANGE_BOOL} is set to {@code true}.
      */
+    @Deprecated
     public static final String KEY_USE_RCS_PRESENCE_BOOL = "use_rcs_presence_bool";
 
     /**
@@ -3866,13 +3872,51 @@
          * <p>
          * If this key's value is set to false, the procedure for RCS contact capability exchange
          * via SIP SUBSCRIBE/NOTIFY will also be disabled internally, and
-         * {@link #KEY_USE_RCS_PRESENCE_BOOL} must also be set to false to ensure apps do not
-         * improperly think that capability exchange via SIP PUBLISH is enabled.
+         * {@link Ims#KEY_ENABLE_PRESENCE_PUBLISH_BOOL} must also be set to false to ensure
+         * apps do not improperly think that capability exchange via SIP PUBLISH is enabled.
          * <p> The default value for this key is {@code false}.
          */
         public static final String KEY_ENABLE_PRESENCE_PUBLISH_BOOL =
                 KEY_PREFIX + "enable_presence_publish_bool";
 
+        /**
+         * Flag indicating whether or not this carrier supports the exchange of phone numbers with
+         * the carrier's RCS presence server in order to retrieve the RCS capabilities of requested
+         * contacts used in the RCS User Capability Exchange (UCE) procedure. See RCC.71, section 3
+         * for more information.
+         * <p>
+         * When presence is supported, the device uses the SIP SUBSCRIBE/NOTIFY procedure internally
+         * to retrieve the requested RCS capabilities. See
+         * {@link android.telephony.ims.RcsUceAdapter} for more information on how RCS capabilities
+         * can be retrieved from the carrier's network.
+         */
+        public static final String KEY_ENABLE_PRESENCE_CAPABILITY_EXCHANGE_BOOL =
+                KEY_PREFIX + "enable_presence_capability_exchange_bool";
+
+
+        /**
+         * Flag indicating whether or not the carrier expects the RCS UCE service to periodically
+         * refresh the RCS capabilities cache of the user's contacts as well as request the
+         * capabilities of call contacts when the SIM card is first inserted or when a new contact
+         * is added, removed, or modified. This corresponds to the RCC.07 A.19
+         * "DISABLE INITIAL ADDRESS BOOK SCAN" parameter.
+         * <p>
+         * If this flag is disabled, the capabilities cache will not be refreshed internally at all
+         * and will only be updated if the cached capabilities are stale when an application
+         * requests them.
+         */
+        public static final String KEY_RCS_BULK_CAPABILITY_EXCHANGE_BOOL =
+                KEY_PREFIX + "rcs_bulk_capability_exchange_bool";
+
+        /**
+         * Flag indicating whether or not the carrier supports capability exchange with a list of
+         * contacts. When {@code true}, the device will batch together multiple requests and
+         * construct a RLMI document in the SIP SUBSCRIBE request (see RFC 4662). If {@code false},
+         * the request will be split up into one SIP SUBSCRIBE request per contact.
+         */
+        public static final String KEY_ENABLE_PRESENCE_GROUP_SUBSCRIBE_BOOL =
+                KEY_PREFIX + "enable_presence_group_subscribe_bool";
+
         private Ims() {}
 
         private static PersistableBundle getDefaults() {
@@ -3880,6 +3924,9 @@
             defaults.putInt(KEY_WIFI_OFF_DEFERRING_TIME_MILLIS_INT, 4000);
             defaults.putBoolean(KEY_IMS_SINGLE_REGISTRATION_REQUIRED_BOOL, false);
             defaults.putBoolean(KEY_ENABLE_PRESENCE_PUBLISH_BOOL, false);
+            defaults.putBoolean(KEY_ENABLE_PRESENCE_CAPABILITY_EXCHANGE_BOOL, false);
+            defaults.putBoolean(KEY_RCS_BULK_CAPABILITY_EXCHANGE_BOOL, false);
+            defaults.putBoolean(KEY_ENABLE_PRESENCE_GROUP_SUBSCRIBE_BOOL, true);
             return defaults;
         }
     }
diff --git a/telephony/java/android/telephony/DataFailCause.java b/telephony/java/android/telephony/DataFailCause.java
index d502da9..99a77ae5 100644
--- a/telephony/java/android/telephony/DataFailCause.java
+++ b/telephony/java/android/telephony/DataFailCause.java
@@ -915,6 +915,8 @@
     public static final int IPV6_PREFIX_UNAVAILABLE = 0x8CA;
     /** System preference change back to SRAT during handoff */
     public static final int HANDOFF_PREFERENCE_CHANGED = 0x8CB;
+    /** Data call fail due to the slice not being allowed for the data call. */
+    public static final int SLICE_REJECTED = 0x8CC;
 
     //IKE error notifications message as specified in 3GPP TS 24.302 (Section 8.1.2.2).
 
@@ -985,7 +987,7 @@
      * the authentication failed.
      */
     public static final int IWLAN_IKEV2_AUTH_FAILURE = 0x4001;
-    /** IKE message timeout, tunnel setup failed due to no response from EPDG  */
+    /** IKE message timeout, tunnel setup failed due to no response from EPDG */
     public static final int IWLAN_IKEV2_MSG_TIMEOUT = 0x4002;
     /** IKE Certification validation failure  */
     public static final int IWLAN_IKEV2_CERT_INVALID = 0x4003;
@@ -1419,6 +1421,7 @@
         sFailCauseMap.put(VSNCP_RECONNECT_NOT_ALLOWED, "VSNCP_RECONNECT_NOT_ALLOWED");
         sFailCauseMap.put(IPV6_PREFIX_UNAVAILABLE, "IPV6_PREFIX_UNAVAILABLE");
         sFailCauseMap.put(HANDOFF_PREFERENCE_CHANGED, "HANDOFF_PREFERENCE_CHANGED");
+        sFailCauseMap.put(SLICE_REJECTED, "SLICE_REJECTED");
         sFailCauseMap.put(IWLAN_PDN_CONNECTION_REJECTION, "IWLAN_PDN_CONNECTION_REJECTION");
         sFailCauseMap.put(IWLAN_MAX_CONNECTION_REACHED, "IWLAN_MAX_CONNECTION_REACHED");
         sFailCauseMap.put(IWLAN_SEMANTIC_ERROR_IN_THE_TFT_OPERATION,
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 31a1249..d4565f3 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -8671,6 +8671,77 @@
         return Collections.EMPTY_LIST;
     }
 
+    /**
+     * Call composer status OFF from user setting.
+     */
+    public static final int CALL_COMPOSER_STATUS_OFF = 0;
+
+    /**
+     * Call composer status ON from user setting.
+     */
+    public static final int CALL_COMPOSER_STATUS_ON = 1;
+
+    /** @hide */
+    @IntDef(prefix = {"CALL_COMPOSER_STATUS_"},
+            value = {
+                CALL_COMPOSER_STATUS_ON,
+                CALL_COMPOSER_STATUS_OFF,
+            })
+    public @interface CallComposerStatus {}
+
+    /**
+     * Set the user-set status for enriched calling with call composer.
+     *
+     * @param status user-set status for enriched calling with call composer;
+     *               it must be a value of either {@link #CALL_COMPOSER_STATUS_ON}
+     *               or {@link #CALL_COMPOSER_STATUS_OFF}.
+     *
+     * <p>If this object has been created with {@link #createForSubscriptionId}, applies to the
+     * given subId. Otherwise, applies to {@link SubscriptionManager#getDefaultSubscriptionId()}
+     *
+     * @throws IllegalArgumentException if requested state is invalid.
+     * @throws SecurityException if the caller does not have the permission.
+     */
+    @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
+    public void setCallComposerStatus(@CallComposerStatus int status) {
+        if (status != CALL_COMPOSER_STATUS_ON && status != CALL_COMPOSER_STATUS_OFF) {
+            throw new IllegalArgumentException("requested status is invalid");
+        }
+        try {
+            ITelephony telephony = getITelephony();
+            if (telephony != null) {
+                telephony.setCallComposerStatus(getSubId(), status);
+            }
+        } catch (RemoteException ex) {
+            Log.e(TAG, "Error calling ITelephony#setCallComposerStatus", ex);
+            ex.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Get the user-set status for enriched calling with call composer.
+     *
+     * <p>If this object has been created with {@link #createForSubscriptionId}, applies to the
+     * given subId. Otherwise, applies to {@link SubscriptionManager#getDefaultSubscriptionId()}
+     *
+     * @throws SecurityException if the caller does not have the permission.
+     *
+     * @return the user-set status for enriched calling with call composer either
+     * {@link #CALL_COMPOSER_STATUS_ON} or {@link #CALL_COMPOSER_STATUS_OFF}.
+     */
+    @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+    public @CallComposerStatus int getCallComposerStatus() {
+        try {
+            ITelephony telephony = getITelephony();
+            if (telephony != null) {
+                return telephony.getCallComposerStatus(getSubId());
+            }
+        } catch (RemoteException ex) {
+            Log.e(TAG, "Error calling ITelephony#getCallComposerStatus", ex);
+            ex.rethrowFromSystemServer();
+        }
+        return CALL_COMPOSER_STATUS_OFF;
+    }
 
     /** @hide */
     @SystemApi
diff --git a/telephony/java/android/telephony/data/DataCallResponse.java b/telephony/java/android/telephony/data/DataCallResponse.java
index 556f2d5..e217e9a 100644
--- a/telephony/java/android/telephony/data/DataCallResponse.java
+++ b/telephony/java/android/telephony/data/DataCallResponse.java
@@ -137,6 +137,7 @@
     private final int mPduSessionId;
     private final Qos mDefaultQos;
     private final List<QosSession> mQosSessions;
+    private final SliceInfo mSliceInfo;
 
     /**
      * @param cause Data call fail cause. {@link DataFailCause#NONE} indicates no error.
@@ -187,6 +188,7 @@
         mPduSessionId = PDU_SESSION_ID_NOT_SET;
         mDefaultQos = null;
         mQosSessions = new ArrayList<>();
+        mSliceInfo = null;
     }
 
     private DataCallResponse(@DataFailureCause int cause, long suggestedRetryTime, int id,
@@ -195,7 +197,8 @@
             @Nullable List<InetAddress> dnsAddresses, @Nullable List<InetAddress> gatewayAddresses,
             @Nullable List<InetAddress> pcscfAddresses, int mtu, int mtuV4, int mtuV6,
             @HandoverFailureMode int handoverFailureMode, int pduSessionId,
-            @Nullable Qos defaultQos, @Nullable List<QosSession> qosSessions) {
+            @Nullable Qos defaultQos, @Nullable List<QosSession> qosSessions,
+            @Nullable SliceInfo sliceInfo) {
         mCause = cause;
         mSuggestedRetryTime = suggestedRetryTime;
         mId = id;
@@ -217,6 +220,7 @@
         mPduSessionId = pduSessionId;
         mDefaultQos = defaultQos;
         mQosSessions = qosSessions;
+        mSliceInfo = sliceInfo;
     }
 
     /** @hide */
@@ -244,6 +248,7 @@
         mDefaultQos = source.readParcelable(Qos.class.getClassLoader());
         mQosSessions = new ArrayList<>();
         source.readList(mQosSessions, QosSession.class.getClassLoader());
+        mSliceInfo = source.readParcelable(SliceInfo.class.getClassLoader());
     }
 
     /**
@@ -370,7 +375,7 @@
     }
 
     /**
-     * @return default QOS of the data call received from the network
+     * @return default QOS of the data connection received from the network
      *
      * @hide
      */
@@ -381,16 +386,24 @@
     }
 
     /**
-     * @return All the dedicated bearer QOS sessions of the data call received from the network
+     * @return All the dedicated bearer QOS sessions of the data connection received from the
+     * network.
      *
      * @hide
      */
-
     @NonNull
     public List<QosSession> getQosSessions() {
         return mQosSessions;
     }
 
+    /**
+     * @return The slice info related to this data connection.
+     */
+    @Nullable
+    public SliceInfo getSliceInfo() {
+        return mSliceInfo;
+    }
+
     @NonNull
     @Override
     public String toString() {
@@ -413,6 +426,7 @@
            .append(" pduSessionId=").append(getPduSessionId())
            .append(" defaultQos=").append(mDefaultQos)
            .append(" qosSessions=").append(mQosSessions)
+           .append(" sliceInfo=").append(mSliceInfo)
            .append("}");
         return sb.toString();
     }
@@ -456,7 +470,8 @@
                 && mHandoverFailureMode == other.mHandoverFailureMode
                 && mPduSessionId == other.mPduSessionId
                 && isQosSame
-                && isQosSessionsSame;
+                && isQosSessionsSame
+                && Objects.equals(mSliceInfo, other.mSliceInfo);
     }
 
     @Override
@@ -464,7 +479,7 @@
         return Objects.hash(mCause, mSuggestedRetryTime, mId, mLinkStatus, mProtocolType,
                 mInterfaceName, mAddresses, mDnsAddresses, mGatewayAddresses, mPcscfAddresses,
                 mMtu, mMtuV4, mMtuV6, mHandoverFailureMode, mPduSessionId, mDefaultQos,
-                mQosSessions);
+                mQosSessions, mSliceInfo);
     }
 
     @Override
@@ -499,6 +514,7 @@
             dest.writeParcelable(null, flags);
         }
         dest.writeList(mQosSessions);
+        dest.writeParcelable(mSliceInfo, flags);
     }
 
     public static final @android.annotation.NonNull Parcelable.Creator<DataCallResponse> CREATOR =
@@ -582,6 +598,8 @@
 
         private List<QosSession> mQosSessions = new ArrayList<>();
 
+        private SliceInfo mSliceInfo;
+
         /**
          * Default constructor for Builder.
          */
@@ -805,6 +823,21 @@
         }
 
         /**
+         * The Slice used for this data connection.
+         * <p/>
+         * If a handover occurs from EPDG to 5G,
+         * this is the {@link SliceInfo} used in {@link DataService#setupDataCall}.
+         *
+         * @param sliceInfo the slice info for the data call
+         *
+         * @return The same instance of the builder.
+         */
+        public @NonNull Builder setSliceInfo(@Nullable SliceInfo sliceInfo) {
+            mSliceInfo = sliceInfo;
+            return this;
+        }
+
+        /**
          * Build the DataCallResponse.
          *
          * @return the DataCallResponse object.
@@ -813,7 +846,7 @@
             return new DataCallResponse(mCause, mSuggestedRetryTime, mId, mLinkStatus,
                     mProtocolType, mInterfaceName, mAddresses, mDnsAddresses, mGatewayAddresses,
                     mPcscfAddresses, mMtu, mMtuV4, mMtuV6, mHandoverFailureMode, mPduSessionId,
-                    mDefaultQos, mQosSessions);
+                    mDefaultQos, mQosSessions, mSliceInfo);
         }
     }
 }
diff --git a/telephony/java/android/telephony/data/DataService.java b/telephony/java/android/telephony/data/DataService.java
index 2ec9651..03c2ef9 100644
--- a/telephony/java/android/telephony/data/DataService.java
+++ b/telephony/java/android/telephony/data/DataService.java
@@ -194,13 +194,19 @@
          *                     The standard range of values are 1-15 while 0 means no pdu session id
          *                     was attached to this call.  Reference: 3GPP TS 24.007 section
          *                     11.2.3.1b.
+         * @param sliceInfo used within the data connection when a handover occurs from EPDG to 5G.
+         *        The value is null unless the access network is
+         *        {@link android.telephony.AccessNetworkConstants.AccessNetworkType#NGRAN} and a
+         *        handover is occurring from EPDG to 5G.  If the slice passed is rejected, then
+         *        {@link DataCallResponse#getCause()} is
+         *        {@link android.telephony.DataFailCause#SLICE_REJECTED}.
          * @param callback The result callback for this request.
          */
         public void setupDataCall(int accessNetworkType, @NonNull DataProfile dataProfile,
                 boolean isRoaming, boolean allowRoaming,
                 @SetupDataReason int reason,
                 @Nullable LinkProperties linkProperties,
-                @IntRange(from = 0, to = 15) int pduSessionId,
+                @IntRange(from = 0, to = 15) int pduSessionId, @Nullable SliceInfo sliceInfo,
                 @NonNull DataServiceCallback callback) {
             /* Call the old version since the new version isn't supported */
             setupDataCall(accessNetworkType, dataProfile, isRoaming, allowRoaming, reason,
@@ -392,10 +398,11 @@
         public final int reason;
         public final LinkProperties linkProperties;
         public final int pduSessionId;
+        public final SliceInfo sliceInfo;
         public final IDataServiceCallback callback;
         SetupDataCallRequest(int accessNetworkType, DataProfile dataProfile, boolean isRoaming,
                              boolean allowRoaming, int reason, LinkProperties linkProperties,
-                             int pduSessionId, IDataServiceCallback callback) {
+                             int pduSessionId, SliceInfo sliceInfo, IDataServiceCallback callback) {
             this.accessNetworkType = accessNetworkType;
             this.dataProfile = dataProfile;
             this.isRoaming = isRoaming;
@@ -403,6 +410,7 @@
             this.linkProperties = linkProperties;
             this.reason = reason;
             this.pduSessionId = pduSessionId;
+            this.sliceInfo = sliceInfo;
             this.callback = callback;
         }
     }
@@ -513,6 +521,7 @@
                             setupDataCallRequest.dataProfile, setupDataCallRequest.isRoaming,
                             setupDataCallRequest.allowRoaming, setupDataCallRequest.reason,
                             setupDataCallRequest.linkProperties, setupDataCallRequest.pduSessionId,
+                            setupDataCallRequest.sliceInfo,
                             (setupDataCallRequest.callback != null)
                                     ? new DataServiceCallback(setupDataCallRequest.callback)
                                     : null);
@@ -676,10 +685,12 @@
         @Override
         public void setupDataCall(int slotIndex, int accessNetworkType, DataProfile dataProfile,
                 boolean isRoaming, boolean allowRoaming, int reason,
-                LinkProperties linkProperties, int pduSessionId, IDataServiceCallback callback) {
+                LinkProperties linkProperties, int pduSessionId, SliceInfo sliceInfo,
+                IDataServiceCallback callback) {
             mHandler.obtainMessage(DATA_SERVICE_REQUEST_SETUP_DATA_CALL, slotIndex, 0,
                     new SetupDataCallRequest(accessNetworkType, dataProfile, isRoaming,
-                            allowRoaming, reason, linkProperties, pduSessionId, callback))
+                            allowRoaming, reason, linkProperties, pduSessionId, sliceInfo,
+                            callback))
                     .sendToTarget();
         }
 
diff --git a/telephony/java/android/telephony/data/IDataService.aidl b/telephony/java/android/telephony/data/IDataService.aidl
index 3f1f033..e0b9a1a 100644
--- a/telephony/java/android/telephony/data/IDataService.aidl
+++ b/telephony/java/android/telephony/data/IDataService.aidl
@@ -19,6 +19,7 @@
 import android.net.LinkProperties;
 import android.telephony.data.DataProfile;
 import android.telephony.data.IDataServiceCallback;
+import android.telephony.data.SliceInfo;
 
 /**
  * {@hide}
@@ -29,7 +30,7 @@
     void removeDataServiceProvider(int slotId);
     void setupDataCall(int slotId, int accessNetwork, in DataProfile dataProfile, boolean isRoaming,
                        boolean allowRoaming, int reason, in LinkProperties linkProperties,
-                       int pduSessionId, IDataServiceCallback callback);
+                       int pduSessionId, in SliceInfo sliceInfo, IDataServiceCallback callback);
     void deactivateDataCall(int slotId, int cid, int reason, IDataServiceCallback callback);
     void setInitialAttachApn(int slotId, in DataProfile dataProfile, boolean isRoaming,
                              IDataServiceCallback callback);
diff --git a/telephony/java/android/telephony/data/SliceInfo.aidl b/telephony/java/android/telephony/data/SliceInfo.aidl
new file mode 100644
index 0000000..286ea5e
--- /dev/null
+++ b/telephony/java/android/telephony/data/SliceInfo.aidl
@@ -0,0 +1,20 @@
+/*
+ * Copyright 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.
+ */
+
+/** @hide */
+package android.telephony.data;
+
+parcelable SliceInfo;
diff --git a/telephony/java/android/telephony/data/SliceInfo.java b/telephony/java/android/telephony/data/SliceInfo.java
new file mode 100644
index 0000000..51857a7
--- /dev/null
+++ b/telephony/java/android/telephony/data/SliceInfo.java
@@ -0,0 +1,342 @@
+/*
+ * 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 android.telephony.data;
+
+import android.annotation.IntDef;
+import android.annotation.IntRange;
+import android.annotation.NonNull;
+import android.annotation.SuppressLint;
+import android.annotation.SystemApi;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.Objects;
+
+/**
+ * Represents a S-NSSAI as defined in 3GPP TS 24.501.
+ *
+ * @hide
+ */
+@SystemApi
+public final class SliceInfo implements Parcelable {
+    /**
+     * When set on a Slice Differentiator, this value indicates that there is no corresponding
+     * Slice.
+     */
+    public static final int SLICE_DIFFERENTIATOR_NO_SLICE = -1;
+
+    /**
+     *  Indicates that the service type is not present.
+     */
+    public static final int SLICE_SERVICE_TYPE_NONE = 0;
+
+    /**
+     *  Slice suitable for the handling of 5G enhanced Mobile Broadband.
+     */
+    public static final int SLICE_SERVICE_TYPE_EMBB = 1;
+
+    /**
+     * Slice suitable for the handling of ultra-reliable low latency communications.
+     */
+    public static final int SLICE_SERVICE_TYPE_URLLC = 2;
+
+    /**
+     * Slice suitable for the handling of massive IoT.
+     */
+    public static final int SLICE_SERVICE_TYPE_MIOT = 3;
+
+    /**
+     * The min acceptable value for a Slice Differentiator
+     */
+    @SuppressLint("MinMaxConstant")
+    public static final int MIN_SLICE_DIFFERENTIATOR = -1;
+
+    /**
+     * The max acceptable value for a Slice Differentiator
+     */
+    @SuppressLint("MinMaxConstant")
+    public static final int MAX_SLICE_DIFFERENTIATOR = 0xFFFFFE;
+
+    /** @hide */
+    @IntDef(prefix = { "SLICE_SERVICE_TYPE_" }, value = {
+            SLICE_SERVICE_TYPE_NONE,
+            SLICE_SERVICE_TYPE_EMBB,
+            SLICE_SERVICE_TYPE_URLLC,
+            SLICE_SERVICE_TYPE_MIOT,
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface SliceServiceType {}
+
+
+    @SliceServiceType
+    private final int mSliceServiceType;
+    @IntRange(from = MIN_SLICE_DIFFERENTIATOR, to = MAX_SLICE_DIFFERENTIATOR)
+    private final int mSliceDifferentiator;
+    @SliceServiceType
+    private final int mMappedHplmnSliceServiceType;
+    @IntRange(from = MIN_SLICE_DIFFERENTIATOR, to = MAX_SLICE_DIFFERENTIATOR)
+    private final int mMappedHplmnSliceDifferentiator;
+
+    private SliceInfo(@SliceServiceType int sliceServiceType,
+            int sliceDifferentiator, int mappedHplmnSliceServiceType,
+            int mappedHplmnSliceDifferentiator) {
+        mSliceServiceType = sliceServiceType;
+        mSliceDifferentiator = sliceDifferentiator;
+        mMappedHplmnSliceDifferentiator = mappedHplmnSliceDifferentiator;
+        mMappedHplmnSliceServiceType = mappedHplmnSliceServiceType;
+    }
+
+    /**
+     * The type of service provided by the slice.
+     * <p/>
+     * see: 3GPP TS 24.501 Section 9.11.2.8.
+     */
+    @SliceServiceType
+    public int getSliceServiceType() {
+        return mSliceServiceType;
+    }
+
+    /**
+     * Identifies the slice from others with the same Slice Service Type.
+     * <p/>
+     * Returns {@link #SLICE_DIFFERENTIATOR_NO_SLICE} if {@link #getSliceServiceType} returns
+     * {@link #SLICE_SERVICE_TYPE_NONE}.
+     * <p/>
+     * see: 3GPP TS 24.501 Section 9.11.2.8.
+     */
+    @IntRange(from = MIN_SLICE_DIFFERENTIATOR, to = MAX_SLICE_DIFFERENTIATOR)
+    public int getSliceDifferentiator() {
+        return mSliceDifferentiator;
+    }
+
+    /**
+     * Corresponds to a Slice Info (S-NSSAI) of the HPLMN.
+     * <p/>
+     * see: 3GPP TS 24.501 Section 9.11.2.8.
+     */
+    @SliceServiceType
+    public int getMappedHplmnSliceServiceType() {
+        return mMappedHplmnSliceServiceType;
+    }
+
+    /**
+     * This Slice Differentiator corresponds to a {@link SliceInfo} (S-NSSAI) of the HPLMN;
+     * {@link #getSliceDifferentiator()} is mapped to this value.
+     * <p/>
+     * Returns {@link #SLICE_DIFFERENTIATOR_NO_SLICE} if either of the following are true:
+     * <ul>
+     * <li>{@link #getSliceDifferentiator()} returns {@link #SLICE_DIFFERENTIATOR_NO_SLICE}</li>
+     * <li>{@link #getMappedHplmnSliceServiceType()} returns {@link #SLICE_SERVICE_TYPE_NONE}</li>
+     * </ul>
+     * <p/>
+     * see: 3GPP TS 24.501 Section 9.11.2.8.
+     */
+    @IntRange(from = MIN_SLICE_DIFFERENTIATOR, to = MAX_SLICE_DIFFERENTIATOR)
+    public int getMappedHplmnSliceDifferentiator() {
+        return mMappedHplmnSliceDifferentiator;
+    }
+
+    private SliceInfo(@NonNull Parcel in) {
+        mSliceServiceType = in.readInt();
+        mSliceDifferentiator = in.readInt();
+        mMappedHplmnSliceServiceType = in.readInt();
+        mMappedHplmnSliceDifferentiator = in.readInt();
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
+        dest.writeInt(mSliceServiceType);
+        dest.writeInt(mSliceDifferentiator);
+        dest.writeInt(mMappedHplmnSliceServiceType);
+        dest.writeInt(mMappedHplmnSliceDifferentiator);
+    }
+
+    public static final @android.annotation.NonNull Parcelable.Creator<SliceInfo> CREATOR =
+            new Parcelable.Creator<SliceInfo>() {
+                @Override
+                @NonNull
+                public SliceInfo createFromParcel(@NonNull Parcel source) {
+                    return new SliceInfo(source);
+                }
+
+                @Override
+                @NonNull
+                public SliceInfo[] newArray(int size) {
+                    return new SliceInfo[size];
+                }
+            };
+
+    @Override
+    public String toString() {
+        return "SliceInfo{"
+                + "mSliceServiceType=" + sliceServiceTypeToString(mSliceServiceType)
+                + ", mSliceDifferentiator=" + mSliceDifferentiator
+                + ", mMappedHplmnSliceServiceType="
+                + sliceServiceTypeToString(mMappedHplmnSliceServiceType)
+                + ", mMappedHplmnSliceDifferentiator=" + mMappedHplmnSliceDifferentiator
+                + '}';
+    }
+
+    private static String sliceServiceTypeToString(@SliceServiceType int sliceServiceType) {
+        switch(sliceServiceType) {
+            case SLICE_SERVICE_TYPE_NONE:
+                return "NONE";
+            case SLICE_SERVICE_TYPE_EMBB:
+                return "EMBB";
+            case SLICE_SERVICE_TYPE_URLLC:
+                return "URLLC";
+            case SLICE_SERVICE_TYPE_MIOT:
+                return "MIOT";
+            default:
+                return Integer.toString(sliceServiceType);
+        }
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+        SliceInfo sliceInfo = (SliceInfo) o;
+        return mSliceServiceType == sliceInfo.mSliceServiceType
+                && mSliceDifferentiator == sliceInfo.mSliceDifferentiator
+                && mMappedHplmnSliceServiceType == sliceInfo.mMappedHplmnSliceServiceType
+                && mMappedHplmnSliceDifferentiator == sliceInfo.mMappedHplmnSliceDifferentiator;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(mSliceServiceType, mSliceDifferentiator, mMappedHplmnSliceServiceType,
+                mMappedHplmnSliceDifferentiator);
+    }
+
+    /**
+     * Provides a convenient way to set the fields of a {@link SliceInfo} when creating a
+     * new instance.
+     *
+     * <p>The example below shows how you might create a new {@code SliceInfo}:
+     *
+     * <pre><code>
+     *
+     * SliceInfo response = new SliceInfo.Builder()
+     *     .setSliceServiceType(SLICE_SERVICE_TYPE_URLLC)
+     *     .build();
+     * </code></pre>
+     */
+    public static final class Builder {
+        @SliceServiceType
+        private int mSliceServiceType = SLICE_SERVICE_TYPE_NONE;
+        @IntRange(from = MIN_SLICE_DIFFERENTIATOR, to = MAX_SLICE_DIFFERENTIATOR)
+        private int mSliceDifferentiator = SLICE_DIFFERENTIATOR_NO_SLICE;
+        @SliceServiceType
+        private int mMappedHplmnSliceServiceType = SLICE_SERVICE_TYPE_NONE;
+        @IntRange(from = MIN_SLICE_DIFFERENTIATOR, to = MAX_SLICE_DIFFERENTIATOR)
+        private int mMappedHplmnSliceDifferentiator = SLICE_DIFFERENTIATOR_NO_SLICE;
+
+        /**
+         * Default constructor for Builder.
+         */
+        public Builder() {
+        }
+
+        /**
+         * Set the Slice Service Type.
+         *
+         * @return The same instance of the builder.
+         */
+        @NonNull
+        public Builder setSliceServiceType(@SliceServiceType int mSliceServiceType) {
+            this.mSliceServiceType = mSliceServiceType;
+            return this;
+        }
+
+        /**
+         * Set the Slice Differentiator.
+         * <p/>
+         * A value of {@link #SLICE_DIFFERENTIATOR_NO_SLICE} indicates that there is no
+         * corresponding Slice.
+         *
+         * @throws IllegalArgumentException if the parameter is not between
+         * {@link #MIN_SLICE_DIFFERENTIATOR} and {@link #MAX_SLICE_DIFFERENTIATOR}.
+         *
+         * @return The same instance of the builder.
+         */
+        @NonNull
+        public Builder setSliceDifferentiator(
+                @IntRange(from = MIN_SLICE_DIFFERENTIATOR, to = MAX_SLICE_DIFFERENTIATOR)
+                        int sliceDifferentiator) {
+            if (sliceDifferentiator < MIN_SLICE_DIFFERENTIATOR
+                    || sliceDifferentiator > MAX_SLICE_DIFFERENTIATOR) {
+                throw new IllegalArgumentException("The slice diffentiator value is out of range");
+            }
+            this.mSliceDifferentiator = sliceDifferentiator;
+            return this;
+        }
+
+        /**
+         * Set the HPLMN Slice Service Type.
+         *
+         * @return The same instance of the builder.
+         */
+        @NonNull
+        public Builder setMappedHplmnSliceServiceType(
+                @SliceServiceType int mappedHplmnSliceServiceType) {
+            this.mMappedHplmnSliceServiceType = mappedHplmnSliceServiceType;
+            return this;
+        }
+
+        /**
+         * Set the HPLMN Slice Differentiator.
+         * <p/>
+         * A value of {@link #SLICE_DIFFERENTIATOR_NO_SLICE} indicates that there is no
+         * corresponding Slice of the HPLMN.
+         *
+         * @throws IllegalArgumentException if the parameter is not between
+         * {@link #MIN_SLICE_DIFFERENTIATOR} and {@link #MAX_SLICE_DIFFERENTIATOR}.
+         *
+         * @return The same instance of the builder.
+         */
+        @NonNull
+        public Builder setMappedHplmnSliceDifferentiator(
+                @IntRange(from = MIN_SLICE_DIFFERENTIATOR, to = MAX_SLICE_DIFFERENTIATOR)
+                        int mappedHplmnSliceDifferentiator) {
+            if (mappedHplmnSliceDifferentiator < MIN_SLICE_DIFFERENTIATOR
+                    || mappedHplmnSliceDifferentiator > MAX_SLICE_DIFFERENTIATOR) {
+                throw new IllegalArgumentException("The slice diffentiator value is out of range");
+            }
+            this.mMappedHplmnSliceDifferentiator = mappedHplmnSliceDifferentiator;
+            return this;
+        }
+
+        /**
+         * Build the {@link SliceInfo}.
+         *
+         * @return the {@link SliceInfo} object.
+         */
+        @NonNull
+        public SliceInfo build() {
+            return new SliceInfo(this.mSliceServiceType, this.mSliceDifferentiator,
+                    this.mMappedHplmnSliceServiceType, this.mMappedHplmnSliceDifferentiator);
+        }
+    }
+}
diff --git a/telephony/java/android/telephony/ims/ImsRcsManager.java b/telephony/java/android/telephony/ims/ImsRcsManager.java
index 885ff9b..ad461c0 100644
--- a/telephony/java/android/telephony/ims/ImsRcsManager.java
+++ b/telephony/java/android/telephony/ims/ImsRcsManager.java
@@ -30,7 +30,6 @@
 import android.provider.Settings;
 import android.telephony.AccessNetworkConstants;
 import android.telephony.BinderCacheManager;
-import android.telephony.CarrierConfigManager;
 import android.telephony.TelephonyFrameworkInitializer;
 import android.telephony.ims.aidl.IImsCapabilityCallback;
 import android.telephony.ims.aidl.IImsRcsController;
@@ -62,9 +61,10 @@
      * been enabled by the user can be queried using {@link RcsUceAdapter#isUceSettingEnabled()}.
      * <p>
      * This intent will always be handled by the system, however the application should only send
-     * this Intent if the carrier supports RCS contact discovery, which can be queried using the key
-     * {@link CarrierConfigManager#KEY_USE_RCS_PRESENCE_BOOL}. Otherwise, the RCS contact discovery
-     * opt-in dialog will not be shown.
+     * this Intent if the carrier supports bulk RCS contact exchange, which will be true if either
+     * key {@link android.telephony.CarrierConfigManager.Ims#KEY_RCS_BULK_CAPABILITY_EXCHANGE_BOOL}
+     * or {@link android.telephony.CarrierConfigManager#KEY_USE_RCS_PRESENCE_BOOL} is set to true.
+     * Otherwise, the RCS contact discovery opt-in dialog will not be shown.
      * <p>
      * Input: A mandatory {@link Settings#EXTRA_SUB_ID} extra containing the subscription that the
      * setting will be be shown for.
@@ -396,6 +396,7 @@
      * rather the subscription is capable of this service over IMS.
      * @see #isAvailable(int)
      * @see android.telephony.CarrierConfigManager#KEY_USE_RCS_PRESENCE_BOOL
+     * @see android.telephony.CarrierConfigManager.Ims#KEY_ENABLE_PRESENCE_CAPABILITY_EXCHANGE_BOOL
      * @throws ImsException if the IMS service is not available when calling this method.
      * See {@link ImsException#getCode()} for more information on the error codes.
      * @hide
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index ff240a0..de4da38 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -128,6 +128,15 @@
      */
     boolean isRadioOnForSubscriberWithFeature(int subId, String callingPackage, String callingFeatureId);
 
+    /**
+     * Set the user-set status for enriched calling with call composer.
+     */
+    void setCallComposerStatus(int subId, int status);
+
+    /**
+     * Get the user-set status for enriched calling with call composer.
+     */
+    int getCallComposerStatus(int subId);
 
     /**
      * Supply a pin to unlock the SIM for particular subId.
diff --git a/test-mock/src/android/test/mock/MockContext.java b/test-mock/src/android/test/mock/MockContext.java
index cf3b03c..f7cebd1 100644
--- a/test-mock/src/android/test/mock/MockContext.java
+++ b/test-mock/src/android/test/mock/MockContext.java
@@ -817,6 +817,11 @@
     }
 
     @Override
+    public @NonNull Context createWindowContext(Display display, int type, Bundle options) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
     public boolean isRestricted() {
         throw new UnsupportedOperationException();
     }
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/CommonAssertions.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/CommonAssertions.kt
index bd7e8d7..e4db55e 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/CommonAssertions.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/CommonAssertions.kt
@@ -80,16 +80,39 @@
     }
 }
 
-fun WmAssertion.windowAlwaysVisible(
+fun WmAssertion.wallpaperWindowBecomesInvisible(
+    bugId: Int = 0,
+    enabled: Boolean = bugId == 0
+) {
+    all("wallpaperWindowBecomesInvisible", bugId, enabled) {
+        this.showsBelowAppWindow("Wallpaper")
+                .then()
+                .hidesBelowAppWindow("Wallpaper")
+    }
+}
+
+fun WmAssertion.appWindowAlwaysVisibleOnTop(
     packageName: String,
     bugId: Int = 0,
     enabled: Boolean = bugId == 0
 ) {
-    all("windowAlwaysVisible", bugId, enabled) {
+    all("appWindowAlwaysVisibleOnTop", bugId, enabled) {
         this.showsAppWindowOnTop(packageName)
     }
 }
 
+fun WmAssertion.appWindowBecomesVisible(
+    appName: String,
+    bugId: Int = 0,
+    enabled: Boolean = bugId == 0
+) {
+    all("appWindowBecomesVisible", bugId, enabled) {
+        this.hidesAppWindow(appName)
+                .then()
+                .showsAppWindow(appName)
+    }
+}
+
 @JvmOverloads
 fun LayersAssertion.noUncoveredRegions(
     beginRotation: Int,
@@ -214,6 +237,18 @@
     }
 }
 
+fun LayersAssertion.appLayerReplacesWallpaperLayer(
+    appName: String,
+    bugId: Int = 0,
+    enabled: Boolean = bugId == 0
+) {
+    all("appLayerReplacesWallpaperLayer", bugId, enabled) {
+        this.showsLayer("Wallpaper")
+                .then()
+                .replaceVisibleLayer("Wallpaper", appName)
+    }
+}
+
 fun LayersAssertion.wallpaperLayerReplacesAppLayer(
     testApp: IAppHelper,
     bugId: Int = 0,
@@ -236,6 +271,30 @@
     }
 }
 
+fun LayersAssertion.layerBecomesVisible(
+    packageName: String,
+    bugId: Int = 0,
+    enabled: Boolean = bugId == 0
+) {
+    all("layerBecomesVisible", bugId, enabled) {
+        this.hidesLayer(packageName)
+                .then()
+                .showsLayer(packageName)
+    }
+}
+
+fun LayersAssertion.layerBecomesInvisible(
+    packageName: String,
+    bugId: Int = 0,
+    enabled: Boolean = bugId == 0
+) {
+    all("layerBecomesInvisible", bugId, enabled) {
+        this.showsLayer(packageName)
+                .then()
+                .hidesLayer(packageName)
+    }
+}
+
 fun EventLogAssertion.focusChanges(
     vararg windows: String,
     bugId: Int = 0,
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CommonAssertions.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CommonAssertions.kt
index 5798624..aa34b5d 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CommonAssertions.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CommonAssertions.kt
@@ -65,6 +65,17 @@
     }
 }
 
+fun WmAssertion.imeWindowBecomesVisible(
+    bugId: Int = 0,
+    enabled: Boolean = bugId == 0
+) {
+    all("imeWindowBecomesVisible", bugId, enabled) {
+        this.hidesNonAppWindow(IME_WINDOW_TITLE)
+                .then()
+                .showsNonAppWindow(IME_WINDOW_TITLE)
+    }
+}
+
 fun WmAssertion.imeWindowBecomesInvisible(
     bugId: Int = 0,
     enabled: Boolean = bugId == 0
@@ -76,6 +87,18 @@
     }
 }
 
+fun WmAssertion.imeAppWindowBecomesVisible(
+    windowName: String,
+    bugId: Int = 0,
+    enabled: Boolean = bugId == 0
+) {
+    all("imeAppWindowBecomesVisible", bugId, enabled) {
+        this.hidesAppWindow(windowName)
+                .then()
+                .showsAppWindow(windowName)
+    }
+}
+
 fun WmAssertion.imeAppWindowBecomesInvisible(
     testApp: IAppHelper,
     bugId: Int = 0,
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowTest.kt
index 64a8f30..28a8bd3 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowTest.kt
@@ -33,6 +33,8 @@
 import com.android.server.wm.flicker.visibleWindowsShownMoreThanOneConsecutiveEntry
 import com.android.server.wm.flicker.visibleLayersShownMoreThanOneConsecutiveEntry
 import com.android.server.wm.flicker.noUncoveredRegions
+import com.android.server.wm.flicker.appWindowAlwaysVisibleOnTop
+import com.android.server.wm.flicker.layerAlwaysVisible
 import com.android.server.wm.flicker.repetitions
 import com.android.server.wm.flicker.startRotation
 import com.android.server.wm.flicker.statusBarLayerIsAlwaysVisible
@@ -56,8 +58,6 @@
     flickerSpec: Flicker
 ) : FlickerTestRunner(testName, flickerSpec) {
     companion object {
-        private const val IME_WINDOW_TITLE = "InputMethod"
-
         @Parameterized.Parameters(name = "{0}")
         @JvmStatic
         fun getParams(): List<Array<Any>> {
@@ -93,12 +93,8 @@
                             statusBarWindowIsAlwaysVisible()
                             visibleWindowsShownMoreThanOneConsecutiveEntry()
 
-                            all("imeWindowBecomesVisible") {
-                                this.skipUntilFirstAssertion()
-                                    .hidesNonAppWindow(IME_WINDOW_TITLE)
-                                    .then()
-                                    .showsNonAppWindow(IME_WINDOW_TITLE)
-                            }
+                            imeWindowBecomesVisible()
+                            appWindowAlwaysVisibleOnTop(testApp.`package`)
                         }
 
                         layersTrace {
@@ -110,6 +106,7 @@
                             visibleLayersShownMoreThanOneConsecutiveEntry()
 
                             imeLayerBecomesVisible()
+                            layerAlwaysVisible(testApp.`package`)
                         }
                     }
                 }
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ReOpenImeWindowTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ReOpenImeWindowTest.kt
index 7bd96f5..c7114da 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ReOpenImeWindowTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ReOpenImeWindowTest.kt
@@ -23,14 +23,27 @@
 import com.android.server.wm.flicker.Flicker
 import com.android.server.wm.flicker.FlickerTestRunner
 import com.android.server.wm.flicker.FlickerTestRunnerFactory
-import com.android.server.wm.flicker.helpers.buildTestTag
 import com.android.server.wm.flicker.helpers.ImeAppAutoFocusHelper
 import com.android.server.wm.flicker.helpers.reopenAppFromOverview
-import com.android.server.wm.flicker.helpers.hasWindow
+import com.android.server.wm.flicker.helpers.buildTestTag
 import com.android.server.wm.flicker.helpers.setRotation
 import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen
+import com.android.server.wm.flicker.navBarLayerIsAlwaysVisible
+import com.android.server.wm.flicker.navBarLayerRotatesAndScales
+import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible
+import com.android.server.wm.flicker.wallpaperWindowBecomesInvisible
+import com.android.server.wm.flicker.appLayerReplacesWallpaperLayer
+import com.android.server.wm.flicker.visibleWindowsShownMoreThanOneConsecutiveEntry
+import com.android.server.wm.flicker.visibleLayersShownMoreThanOneConsecutiveEntry
+import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper
+import com.android.server.wm.flicker.noUncoveredRegions
 import com.android.server.wm.flicker.repetitions
 import com.android.server.wm.flicker.startRotation
+import com.android.server.wm.flicker.endRotation
+import com.android.server.wm.flicker.statusBarLayerIsAlwaysVisible
+import com.android.server.wm.flicker.statusBarLayerRotatesScales
+import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible
+import com.android.server.wm.flicker.testapp.ActivityOptions
 import org.junit.FixMethodOrder
 import org.junit.runner.RunWith
 import org.junit.runners.MethodSorters
@@ -54,8 +67,9 @@
         fun getParams(): List<Array<Any>> {
             val instrumentation = InstrumentationRegistry.getInstrumentation()
             val testApp = ImeAppAutoFocusHelper(instrumentation)
+            val testAppComponentName = ActivityOptions.IME_ACTIVITY_AUTO_FOCUS_COMPONENT_NAME
 
-            return FlickerTestRunnerFactory(instrumentation, repetitions = 10)
+            return FlickerTestRunnerFactory(instrumentation, repetitions = 5)
                     .buildTest { configuration ->
                         withTestName { buildTestTag("reOpenImeAutoFocus", testApp, configuration) }
                         repeat { configuration.repetitions }
@@ -73,7 +87,7 @@
                         }
                         transitions {
                             device.reopenAppFromOverview()
-                            device.hasWindow(testApp.getPackage())
+                            WindowManagerStateHelper().waitForFullScreenApp(testAppComponentName)
                         }
                         teardown {
                             eachRun {
@@ -84,6 +98,35 @@
                                 this.setRotation(Surface.ROTATION_0)
                             }
                         }
+                        assertions {
+                            windowManagerTrace {
+                                navBarWindowIsAlwaysVisible()
+                                statusBarWindowIsAlwaysVisible()
+                                visibleWindowsShownMoreThanOneConsecutiveEntry()
+
+                                imeWindowBecomesVisible()
+                                imeAppWindowBecomesVisible(testAppComponentName.className)
+                                wallpaperWindowBecomesInvisible()
+                            }
+
+                            layersTrace {
+                                noUncoveredRegions(Surface.ROTATION_0, configuration.endRotation,
+                                        bugId = 141361128)
+                                navBarLayerRotatesAndScales(Surface.ROTATION_0,
+                                        configuration.endRotation)
+                                statusBarLayerRotatesScales(Surface.ROTATION_0,
+                                        configuration.endRotation)
+                                statusBarLayerIsAlwaysVisible(
+                                        enabled = Surface.ROTATION_0 == configuration.endRotation)
+                                navBarLayerIsAlwaysVisible(
+                                        enabled = Surface.ROTATION_0 == configuration.endRotation)
+                                visibleLayersShownMoreThanOneConsecutiveEntry(
+                                        enabled = Surface.ROTATION_0 == configuration.endRotation)
+
+                                imeLayerBecomesVisible()
+                                appLayerReplacesWallpaperLayer(testAppComponentName.className)
+                            }
+                        }
                     }
         }
     }
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/CommonAssertions.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/CommonAssertions.kt
index 72efdb1..71920f6 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/CommonAssertions.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/CommonAssertions.kt
@@ -17,20 +17,8 @@
 package com.android.server.wm.flicker.launch
 
 import android.platform.helpers.IAppHelper
-import com.android.server.wm.flicker.dsl.LayersAssertion
 import com.android.server.wm.flicker.dsl.WmAssertion
 
-fun WmAssertion.wallpaperWindowBecomesInvisible(
-    bugId: Int = 0,
-    enabled: Boolean = bugId == 0
-) {
-    all("wallpaperWindowBecomesInvisible", bugId, enabled) {
-        this.showsBelowAppWindow("Wallpaper")
-                .then()
-                .hidesBelowAppWindow("Wallpaper")
-    }
-}
-
 fun WmAssertion.appWindowReplacesLauncherAsTopWindow(
     testApp: IAppHelper,
     bugId: Int = 0,
@@ -41,16 +29,4 @@
                 .then()
                 .showsAppWindowOnTop("Snapshot", testApp.getPackage())
     }
-}
-
-fun LayersAssertion.appLayerReplacesWallpaperLayer(
-    testApp: IAppHelper,
-    bugId: Int = 0,
-    enabled: Boolean = bugId == 0
-) {
-    all("appLayerReplacesWallpaperLayer", bugId, enabled) {
-        this.showsLayer("Wallpaper")
-                .then()
-                .replaceVisibleLayer("Wallpaper", testApp.getPackage())
-    }
 }
\ No newline at end of file
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdTest.kt
index 686ddcb..d81c24d 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdTest.kt
@@ -40,6 +40,8 @@
 import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible
 import com.android.server.wm.flicker.visibleWindowsShownMoreThanOneConsecutiveEntry
 import com.android.server.wm.flicker.visibleLayersShownMoreThanOneConsecutiveEntry
+import com.android.server.wm.flicker.wallpaperWindowBecomesInvisible
+import com.android.server.wm.flicker.appLayerReplacesWallpaperLayer
 import org.junit.FixMethodOrder
 import org.junit.runner.RunWith
 import org.junit.runners.MethodSorters
@@ -107,7 +109,7 @@
                             statusBarLayerIsAlwaysVisible(enabled = false)
                             visibleLayersShownMoreThanOneConsecutiveEntry(bugId = 174541970)
 
-                            appLayerReplacesWallpaperLayer(testApp)
+                            appLayerReplacesWallpaperLayer(testApp.`package`)
                         }
 
                         eventLog {
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromOverviewTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromOverviewTest.kt
index 5aef314..1b682c0 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromOverviewTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromOverviewTest.kt
@@ -29,7 +29,6 @@
 import com.android.server.wm.flicker.visibleWindowsShownMoreThanOneConsecutiveEntry
 import com.android.server.wm.flicker.helpers.StandardAppHelper
 import com.android.server.wm.flicker.helpers.reopenAppFromOverview
-import com.android.server.wm.flicker.helpers.hasWindow
 import com.android.server.wm.flicker.helpers.buildTestTag
 import com.android.server.wm.flicker.helpers.setRotation
 import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen
@@ -42,6 +41,10 @@
 import com.android.server.wm.flicker.statusBarLayerIsAlwaysVisible
 import com.android.server.wm.flicker.statusBarLayerRotatesScales
 import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible
+import com.android.server.wm.flicker.wallpaperWindowBecomesInvisible
+import com.android.server.wm.flicker.appLayerReplacesWallpaperLayer
+import com.android.server.wm.flicker.testapp.ActivityOptions
+import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper
 import org.junit.FixMethodOrder
 import org.junit.runner.RunWith
 import org.junit.runners.MethodSorters
@@ -83,7 +86,9 @@
                         }
                         transitions {
                             device.reopenAppFromOverview()
-                            device.hasWindow(testApp.getPackage())
+                            WindowManagerStateHelper().waitForFullScreenApp(
+                                    ActivityOptions.SIMPLE_ACTIVITY_AUTO_FOCUS_COMPONENT_NAME
+                            )
                         }
                         teardown {
                             test {
@@ -115,7 +120,7 @@
                                 visibleLayersShownMoreThanOneConsecutiveEntry(
                                         enabled = Surface.ROTATION_0 == configuration.endRotation)
 
-                                appLayerReplacesWallpaperLayer(testApp)
+                                appLayerReplacesWallpaperLayer(testApp.`package`)
                             }
 
                             eventLog {
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppWarmTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppWarmTest.kt
index 9b4223a..3703d9c 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppWarmTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppWarmTest.kt
@@ -40,6 +40,8 @@
 import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible
 import com.android.server.wm.flicker.visibleWindowsShownMoreThanOneConsecutiveEntry
 import com.android.server.wm.flicker.visibleLayersShownMoreThanOneConsecutiveEntry
+import com.android.server.wm.flicker.wallpaperWindowBecomesInvisible
+import com.android.server.wm.flicker.appLayerReplacesWallpaperLayer
 import org.junit.FixMethodOrder
 import org.junit.runner.RunWith
 import org.junit.runners.MethodSorters
@@ -112,7 +114,7 @@
                             visibleLayersShownMoreThanOneConsecutiveEntry(
                                     enabled = Surface.ROTATION_0 == configuration.endRotation)
 
-                            appLayerReplacesWallpaperLayer(testApp)
+                            appLayerReplacesWallpaperLayer(testApp.`package`)
                         }
 
                         eventLog {
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTest.kt
index a1a7102..120354b 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTest.kt
@@ -30,7 +30,7 @@
 import com.android.server.wm.flicker.FlickerTestRunnerFactory
 import com.android.server.wm.flicker.endRotation
 import com.android.server.wm.flicker.focusDoesNotChange
-import com.android.server.wm.flicker.windowAlwaysVisible
+import com.android.server.wm.flicker.appWindowAlwaysVisibleOnTop
 import com.android.server.wm.flicker.layerAlwaysVisible
 import com.android.server.wm.flicker.helpers.WindowUtils
 import com.android.server.wm.flicker.helpers.buildTestTag
@@ -146,7 +146,7 @@
                         navBarWindowIsAlwaysVisible(bugId = 140855415)
                         statusBarWindowIsAlwaysVisible(bugId = 140855415)
                         visibleWindowsShownMoreThanOneConsecutiveEntry()
-                        windowAlwaysVisible(configuration.intentPackageName)
+                        appWindowAlwaysVisibleOnTop(configuration.intentPackageName)
                     }
 
                     layersTrace {
diff --git a/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ActivityOptions.java b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ActivityOptions.java
index 1899411..f167e95 100644
--- a/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ActivityOptions.java
+++ b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ActivityOptions.java
@@ -23,4 +23,10 @@
     public static final ComponentName SEAMLESS_ACTIVITY_COMPONENT_NAME =
             new ComponentName("com.android.server.wm.flicker.testapp",
                     "com.android.server.wm.flicker.testapp.SeamlessRotationActivity");
+    public static final ComponentName IME_ACTIVITY_AUTO_FOCUS_COMPONENT_NAME =
+            new ComponentName("com.android.server.wm.flicker.testapp",
+                    "com.android.server.wm.flicker.testapp.ImeActivityAutoFocus");
+    public static final ComponentName SIMPLE_ACTIVITY_AUTO_FOCUS_COMPONENT_NAME =
+            new ComponentName("com.android.server.wm.flicker.testapp",
+                    "com.android.server.wm.flicker.testapp.SimpleActivity");
 }
diff --git a/tests/net/common/java/android/net/NetworkProviderTest.kt b/tests/net/common/java/android/net/NetworkProviderTest.kt
index 77e9f12..bcc9072 100644
--- a/tests/net/common/java/android/net/NetworkProviderTest.kt
+++ b/tests/net/common/java/android/net/NetworkProviderTest.kt
@@ -29,6 +29,7 @@
 import com.android.net.module.util.ArrayTrackRecord
 import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo
 import com.android.testutils.DevSdkIgnoreRunner
+import com.android.testutils.isDevSdkInRange
 import org.junit.After
 import org.junit.Before
 import org.junit.Test
@@ -173,10 +174,12 @@
     @Test
     fun testDeclareNetworkRequestUnfulfillable() {
         val mockContext = mock(Context::class.java)
-        val provider = createNetworkProvider(mockContext)
-        // ConnectivityManager not required at creation time
-        verifyNoMoreInteractions(mockContext)
         doReturn(mCm).`when`(mockContext).getSystemService(Context.CONNECTIVITY_SERVICE)
+        val provider = createNetworkProvider(mockContext)
+        // ConnectivityManager not required at creation time after R
+        if (!isDevSdkInRange(0, Build.VERSION_CODES.R)) {
+            verifyNoMoreInteractions(mockContext)
+        }
 
         mCm.registerNetworkProvider(provider)
 
diff --git a/tests/net/java/android/net/NetworkUtilsTest.java b/tests/net/java/android/net/NetworkUtilsTest.java
index 3158cc8..7748288 100644
--- a/tests/net/java/android/net/NetworkUtilsTest.java
+++ b/tests/net/java/android/net/NetworkUtilsTest.java
@@ -16,24 +16,10 @@
 
 package android.net;
 
-import static android.system.OsConstants.AF_INET;
-import static android.system.OsConstants.AF_INET6;
-import static android.system.OsConstants.AF_UNIX;
-import static android.system.OsConstants.EPERM;
-import static android.system.OsConstants.SOCK_DGRAM;
-import static android.system.OsConstants.SOCK_STREAM;
-
 import static junit.framework.Assert.assertEquals;
 
-import static org.junit.Assert.fail;
-
-import android.system.ErrnoException;
-import android.system.Os;
-
 import androidx.test.runner.AndroidJUnit4;
 
-import libcore.io.IoUtils;
-
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
@@ -139,50 +125,4 @@
         assertEquals(BigInteger.valueOf(7l - 4 + 4 + 16 + 65536),
                 NetworkUtils.routedIPv6AddressCount(set));
     }
-
-    private static void expectSocketSuccess(String msg, int domain, int type) {
-        try {
-            IoUtils.closeQuietly(Os.socket(domain, type, 0));
-        } catch (ErrnoException e) {
-            fail(msg + e.getMessage());
-        }
-    }
-
-    private static void expectSocketPemissionError(String msg, int domain, int type) {
-        try {
-            IoUtils.closeQuietly(Os.socket(domain, type, 0));
-            fail(msg);
-        } catch (ErrnoException e) {
-            assertEquals(msg, e.errno, EPERM);
-        }
-    }
-
-    private static void expectHasNetworking() {
-        expectSocketSuccess("Creating a UNIX socket should not have thrown ErrnoException",
-                AF_UNIX, SOCK_STREAM);
-        expectSocketSuccess("Creating a AF_INET socket shouldn't have thrown ErrnoException",
-                AF_INET, SOCK_DGRAM);
-        expectSocketSuccess("Creating a AF_INET6 socket shouldn't have thrown ErrnoException",
-                AF_INET6, SOCK_DGRAM);
-    }
-
-    private static void expectNoNetworking() {
-        expectSocketSuccess("Creating a UNIX socket should not have thrown ErrnoException",
-                AF_UNIX, SOCK_STREAM);
-        expectSocketPemissionError(
-                "Creating a AF_INET socket should have thrown ErrnoException(EPERM)",
-                AF_INET, SOCK_DGRAM);
-        expectSocketPemissionError(
-                "Creating a AF_INET6 socket should have thrown ErrnoException(EPERM)",
-                AF_INET6, SOCK_DGRAM);
-    }
-
-    @Test
-    public void testSetAllowNetworkingForProcess() {
-        expectHasNetworking();
-        NetworkUtils.setAllowNetworkingForProcess(false);
-        expectNoNetworking();
-        NetworkUtils.setAllowNetworkingForProcess(true);
-        expectHasNetworking();
-    }
 }
diff --git a/tests/net/java/com/android/internal/net/NetworkUtilsInternalTest.java b/tests/net/java/com/android/internal/net/NetworkUtilsInternalTest.java
new file mode 100644
index 0000000..3cfecd5
--- /dev/null
+++ b/tests/net/java/com/android/internal/net/NetworkUtilsInternalTest.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.net;
+
+import static android.system.OsConstants.AF_INET;
+import static android.system.OsConstants.AF_INET6;
+import static android.system.OsConstants.AF_UNIX;
+import static android.system.OsConstants.EPERM;
+import static android.system.OsConstants.SOCK_DGRAM;
+import static android.system.OsConstants.SOCK_STREAM;
+
+import static junit.framework.Assert.assertEquals;
+
+import static org.junit.Assert.fail;
+
+import android.system.ErrnoException;
+import android.system.Os;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import libcore.io.IoUtils;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+@androidx.test.filters.SmallTest
+public class NetworkUtilsInternalTest {
+
+    private static void expectSocketSuccess(String msg, int domain, int type) {
+        try {
+            IoUtils.closeQuietly(Os.socket(domain, type, 0));
+        } catch (ErrnoException e) {
+            fail(msg + e.getMessage());
+        }
+    }
+
+    private static void expectSocketPemissionError(String msg, int domain, int type) {
+        try {
+            IoUtils.closeQuietly(Os.socket(domain, type, 0));
+            fail(msg);
+        } catch (ErrnoException e) {
+            assertEquals(msg, e.errno, EPERM);
+        }
+    }
+
+    private static void expectHasNetworking() {
+        expectSocketSuccess("Creating a UNIX socket should not have thrown ErrnoException",
+                AF_UNIX, SOCK_STREAM);
+        expectSocketSuccess("Creating a AF_INET socket shouldn't have thrown ErrnoException",
+                AF_INET, SOCK_DGRAM);
+        expectSocketSuccess("Creating a AF_INET6 socket shouldn't have thrown ErrnoException",
+                AF_INET6, SOCK_DGRAM);
+    }
+
+    private static void expectNoNetworking() {
+        expectSocketSuccess("Creating a UNIX socket should not have thrown ErrnoException",
+                AF_UNIX, SOCK_STREAM);
+        expectSocketPemissionError(
+                "Creating a AF_INET socket should have thrown ErrnoException(EPERM)",
+                AF_INET, SOCK_DGRAM);
+        expectSocketPemissionError(
+                "Creating a AF_INET6 socket should have thrown ErrnoException(EPERM)",
+                AF_INET6, SOCK_DGRAM);
+    }
+
+    @Test
+    public void testSetAllowNetworkingForProcess() {
+        expectHasNetworking();
+        NetworkUtilsInternal.setAllowNetworkingForProcess(false);
+        expectNoNetworking();
+        NetworkUtilsInternal.setAllowNetworkingForProcess(true);
+        expectHasNetworking();
+    }
+}
diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java
index 20b05b5..799b64e 100644
--- a/tests/net/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java
@@ -8109,7 +8109,16 @@
 
     @Test
     public void testDumpDoesNotCrash() {
-        StringWriter stringWriter = new StringWriter();
+        // Filing a couple requests prior to testing the dump.
+        final TestNetworkCallback genericNetworkCallback = new TestNetworkCallback();
+        final TestNetworkCallback wifiNetworkCallback = new TestNetworkCallback();
+        final NetworkRequest genericRequest = new NetworkRequest.Builder()
+                .clearCapabilities().build();
+        final NetworkRequest wifiRequest = new NetworkRequest.Builder()
+                .addTransportType(TRANSPORT_WIFI).build();
+        mCm.registerNetworkCallback(genericRequest, genericNetworkCallback);
+        mCm.registerNetworkCallback(wifiRequest, wifiNetworkCallback);
+        final StringWriter stringWriter = new StringWriter();
 
         mService.dump(new FileDescriptor(), new PrintWriter(stringWriter), new String[0]);
 
@@ -8131,11 +8140,11 @@
         mCm.registerNetworkCallback(wifiRequest, wifiNetworkCallback);
         mCm.registerNetworkCallback(cellRequest, cellNetworkCallback);
 
-        ConnectivityService.NetworkRequestInfo[] nriOutput = mService.requestsSortedById();
+        final ConnectivityService.NetworkRequestInfo[] nriOutput = mService.requestsSortedById();
 
         assertTrue(nriOutput.length > 1);
         for (int i = 0; i < nriOutput.length - 1; i++) {
-            boolean isRequestIdInOrder =
+            final boolean isRequestIdInOrder =
                     nriOutput[i].mRequests.get(0).requestId
                             < nriOutput[i + 1].mRequests.get(0).requestId;
             assertTrue(isRequestIdInOrder);
diff --git a/tests/net/java/com/android/server/NetworkManagementServiceTest.java b/tests/net/java/com/android/server/NetworkManagementServiceTest.java
index ea763d2..e150229 100644
--- a/tests/net/java/com/android/server/NetworkManagementServiceTest.java
+++ b/tests/net/java/com/android/server/NetworkManagementServiceTest.java
@@ -68,11 +68,12 @@
 @SmallTest
 public class NetworkManagementServiceTest {
     private NetworkManagementService mNMService;
-
     @Mock private Context mContext;
     @Mock private IBatteryStats.Stub mBatteryStatsService;
     @Mock private INetd.Stub mNetdService;
 
+    private static final int TEST_UID = 111;
+
     @NonNull
     @Captor
     private ArgumentCaptor<INetdUnsolicitedEventListener> mUnsolListenerCaptor;
@@ -165,14 +166,14 @@
         /**
          * Interface class activity.
          */
-        unsolListener.onInterfaceClassActivityChanged(true, 1, 1234, 0);
-        expectSoon(observer).interfaceClassDataActivityChanged("1", true, 1234);
+        unsolListener.onInterfaceClassActivityChanged(true, 1, 1234, TEST_UID);
+        expectSoon(observer).interfaceClassDataActivityChanged("1", true, 1234, TEST_UID);
 
-        unsolListener.onInterfaceClassActivityChanged(false, 9, 5678, 0);
-        expectSoon(observer).interfaceClassDataActivityChanged("9", false, 5678);
+        unsolListener.onInterfaceClassActivityChanged(false, 9, 5678, TEST_UID);
+        expectSoon(observer).interfaceClassDataActivityChanged("9", false, 5678, TEST_UID);
 
-        unsolListener.onInterfaceClassActivityChanged(false, 9, 4321, 0);
-        expectSoon(observer).interfaceClassDataActivityChanged("9", false, 4321);
+        unsolListener.onInterfaceClassActivityChanged(false, 9, 4321, TEST_UID);
+        expectSoon(observer).interfaceClassDataActivityChanged("9", false, 4321, TEST_UID);
 
         /**
          * IP address changes.
@@ -222,8 +223,6 @@
         assertFalse(mNMService.isFirewallEnabled());
     }
 
-    private static final int TEST_UID = 111;
-
     @Test
     public void testNetworkRestrictedDefault() {
         assertFalse(mNMService.isNetworkRestricted(TEST_UID));
diff --git a/tests/net/java/com/android/server/net/NetworkStatsCollectionTest.java b/tests/net/java/com/android/server/net/NetworkStatsCollectionTest.java
index fb0cfc0..89146f9 100644
--- a/tests/net/java/com/android/server/net/NetworkStatsCollectionTest.java
+++ b/tests/net/java/com/android/server/net/NetworkStatsCollectionTest.java
@@ -23,11 +23,11 @@
 import static android.net.NetworkStats.UID_ALL;
 import static android.net.NetworkStatsHistory.FIELD_ALL;
 import static android.net.NetworkTemplate.buildTemplateMobileAll;
-import static android.net.NetworkUtils.multiplySafeByRational;
 import static android.os.Process.myUid;
 import static android.text.format.DateUtils.HOUR_IN_MILLIS;
 import static android.text.format.DateUtils.MINUTE_IN_MILLIS;
 
+import static com.android.internal.net.NetworkUtilsInternal.multiplySafeByRational;
 import static com.android.testutils.MiscAsserts.assertThrows;
 
 import static org.junit.Assert.assertArrayEquals;
diff --git a/tests/vcn/java/android/net/vcn/VcnConfigTest.java b/tests/vcn/java/android/net/vcn/VcnConfigTest.java
new file mode 100644
index 0000000..77944de
--- /dev/null
+++ b/tests/vcn/java/android/net/vcn/VcnConfigTest.java
@@ -0,0 +1,83 @@
+/*
+ * 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 android.net.vcn;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+
+import android.os.Parcel;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.Collections;
+import java.util.Set;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class VcnConfigTest {
+    private static final Set<VcnGatewayConnectionConfig> GATEWAY_CONNECTION_CONFIGS =
+            Collections.singleton(VcnGatewayConnectionConfigTest.buildTestConfig());
+
+    // Public visibility for VcnManagementServiceTest
+    public static VcnConfig buildTestConfig() {
+        VcnConfig.Builder builder = new VcnConfig.Builder();
+
+        for (VcnGatewayConnectionConfig gatewayConnectionConfig : GATEWAY_CONNECTION_CONFIGS) {
+            builder.addGatewayConnectionConfig(gatewayConnectionConfig);
+        }
+
+        return builder.build();
+    }
+
+    @Test
+    public void testBuilderRequiresGatewayConnectionConfig() {
+        try {
+            new VcnConfig.Builder().build();
+            fail("Expected exception due to no VcnGatewayConnectionConfigs provided");
+        } catch (IllegalArgumentException e) {
+        }
+    }
+
+    @Test
+    public void testBuilderAndGetters() {
+        final VcnConfig config = buildTestConfig();
+
+        assertEquals(GATEWAY_CONNECTION_CONFIGS, config.getGatewayConnectionConfigs());
+    }
+
+    @Test
+    public void testPersistableBundle() {
+        final VcnConfig config = buildTestConfig();
+
+        assertEquals(config, new VcnConfig(config.toPersistableBundle()));
+    }
+
+    @Test
+    public void testParceling() {
+        final VcnConfig config = buildTestConfig();
+
+        Parcel parcel = Parcel.obtain();
+        config.writeToParcel(parcel, 0);
+        parcel.setDataPosition(0);
+
+        assertEquals(config, VcnConfig.CREATOR.createFromParcel(parcel));
+    }
+}
diff --git a/tests/vcn/java/android/net/vcn/VcnGatewayConnectionConfigTest.java b/tests/vcn/java/android/net/vcn/VcnGatewayConnectionConfigTest.java
new file mode 100644
index 0000000..e98b6ef
--- /dev/null
+++ b/tests/vcn/java/android/net/vcn/VcnGatewayConnectionConfigTest.java
@@ -0,0 +1,143 @@
+/*
+ * 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 android.net.vcn;
+
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+
+import android.net.NetworkCapabilities;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.concurrent.TimeUnit;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class VcnGatewayConnectionConfigTest {
+    private static final int[] EXPOSED_CAPS =
+            new int[] {
+                NetworkCapabilities.NET_CAPABILITY_INTERNET, NetworkCapabilities.NET_CAPABILITY_MMS
+            };
+    private static final int[] UNDERLYING_CAPS = new int[] {NetworkCapabilities.NET_CAPABILITY_DUN};
+    private static final long[] RETRY_INTERVALS_MS =
+            new long[] {
+                TimeUnit.SECONDS.toMillis(5),
+                TimeUnit.SECONDS.toMillis(30),
+                TimeUnit.MINUTES.toMillis(1),
+                TimeUnit.MINUTES.toMillis(5),
+                TimeUnit.MINUTES.toMillis(15),
+                TimeUnit.MINUTES.toMillis(30)
+            };
+    private static final int MAX_MTU = 1360;
+
+    // Package protected for use in VcnConfigTest
+    static VcnGatewayConnectionConfig buildTestConfig() {
+        final VcnGatewayConnectionConfig.Builder builder =
+                new VcnGatewayConnectionConfig.Builder()
+                        .setRetryInterval(RETRY_INTERVALS_MS)
+                        .setMaxMtu(MAX_MTU);
+
+        for (int caps : EXPOSED_CAPS) {
+            builder.addExposedCapability(caps);
+        }
+
+        for (int caps : UNDERLYING_CAPS) {
+            builder.addRequiredUnderlyingCapability(caps);
+        }
+
+        return builder.build();
+    }
+
+    @Test
+    public void testBuilderRequiresNonEmptyExposedCaps() {
+        try {
+            new VcnGatewayConnectionConfig.Builder()
+                    .addRequiredUnderlyingCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
+                    .build();
+
+            fail("Expected exception due to invalid exposed capabilities");
+        } catch (IllegalArgumentException e) {
+        }
+    }
+
+    @Test
+    public void testBuilderRequiresNonEmptyUnderlyingCaps() {
+        try {
+            new VcnGatewayConnectionConfig.Builder()
+                    .addExposedCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
+                    .build();
+
+            fail("Expected exception due to invalid required underlying capabilities");
+        } catch (IllegalArgumentException e) {
+        }
+    }
+
+    @Test
+    public void testBuilderRequiresNonNullRetryInterval() {
+        try {
+            new VcnGatewayConnectionConfig.Builder().setRetryInterval(null);
+            fail("Expected exception due to invalid retryIntervalMs");
+        } catch (IllegalArgumentException e) {
+        }
+    }
+
+    @Test
+    public void testBuilderRequiresNonEmptyRetryInterval() {
+        try {
+            new VcnGatewayConnectionConfig.Builder().setRetryInterval(new long[0]);
+            fail("Expected exception due to invalid retryIntervalMs");
+        } catch (IllegalArgumentException e) {
+        }
+    }
+
+    @Test
+    public void testBuilderRequiresValidMtu() {
+        try {
+            new VcnGatewayConnectionConfig.Builder()
+                    .setMaxMtu(VcnGatewayConnectionConfig.MIN_MTU_V6 - 1);
+            fail("Expected exception due to invalid mtu");
+        } catch (IllegalArgumentException e) {
+        }
+    }
+
+    @Test
+    public void testBuilderAndGetters() {
+        final VcnGatewayConnectionConfig config = buildTestConfig();
+
+        for (int cap : EXPOSED_CAPS) {
+            config.hasExposedCapability(cap);
+        }
+        for (int cap : UNDERLYING_CAPS) {
+            config.requiresUnderlyingCapability(cap);
+        }
+
+        assertArrayEquals(RETRY_INTERVALS_MS, config.getRetryIntervalsMs());
+        assertEquals(MAX_MTU, config.getMaxMtu());
+    }
+
+    @Test
+    public void testPersistableBundle() {
+        final VcnGatewayConnectionConfig config = buildTestConfig();
+
+        assertEquals(config, new VcnGatewayConnectionConfig(config.toPersistableBundle()));
+    }
+}
diff --git a/tests/vcn/java/com/android/server/VcnManagementServiceTest.java b/tests/vcn/java/com/android/server/VcnManagementServiceTest.java
index c91fdbf..1cc9532 100644
--- a/tests/vcn/java/com/android/server/VcnManagementServiceTest.java
+++ b/tests/vcn/java/com/android/server/VcnManagementServiceTest.java
@@ -16,42 +16,123 @@
 
 package com.android.server;
 
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
 import static org.mockito.Mockito.any;
 import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.eq;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.verify;
 
 import android.content.Context;
 import android.net.ConnectivityManager;
+import android.net.vcn.VcnConfig;
+import android.net.vcn.VcnConfigTest;
+import android.os.ParcelUuid;
+import android.os.PersistableBundle;
+import android.os.Process;
+import android.os.UserHandle;
 import android.os.test.TestLooper;
+import android.telephony.SubscriptionInfo;
+import android.telephony.SubscriptionManager;
+import android.telephony.TelephonyManager;
 
 import androidx.test.filters.SmallTest;
 import androidx.test.runner.AndroidJUnit4;
 
+import com.android.server.vcn.util.PersistableBundleUtils;
+
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
+import java.io.FileNotFoundException;
+import java.util.Collections;
+import java.util.Map;
+import java.util.UUID;
+
 /** Tests for {@link VcnManagementService}. */
 @RunWith(AndroidJUnit4.class)
 @SmallTest
 public class VcnManagementServiceTest {
+    private static final ParcelUuid TEST_UUID_1 = new ParcelUuid(new UUID(0, 0));
+    private static final ParcelUuid TEST_UUID_2 = new ParcelUuid(new UUID(1, 1));
+    private static final VcnConfig TEST_VCN_CONFIG = VcnConfigTest.buildTestConfig();
+    private static final Map<ParcelUuid, VcnConfig> TEST_VCN_CONFIG_MAP =
+            Collections.unmodifiableMap(Collections.singletonMap(TEST_UUID_1, TEST_VCN_CONFIG));
+
+    private static final SubscriptionInfo TEST_SUBSCRIPTION_INFO =
+            new SubscriptionInfo(
+                    1 /* id */,
+                    "" /* iccId */,
+                    0 /* simSlotIndex */,
+                    "Carrier" /* displayName */,
+                    "Carrier" /* carrierName */,
+                    0 /* nameSource */,
+                    255 /* iconTint */,
+                    "12345" /* number */,
+                    0 /* roaming */,
+                    null /* icon */,
+                    "0" /* mcc */,
+                    "0" /* mnc */,
+                    "0" /* countryIso */,
+                    false /* isEmbedded */,
+                    null /* nativeAccessRules */,
+                    null /* cardString */,
+                    false /* isOpportunistic */,
+                    TEST_UUID_1.toString() /* groupUUID */,
+                    0 /* carrierId */,
+                    0 /* profileClass */);
+
     private final Context mMockContext = mock(Context.class);
     private final VcnManagementService.Dependencies mMockDeps =
             mock(VcnManagementService.Dependencies.class);
     private final TestLooper mTestLooper = new TestLooper();
     private final ConnectivityManager mConnMgr = mock(ConnectivityManager.class);
+    private final TelephonyManager mTelMgr = mock(TelephonyManager.class);
+    private final SubscriptionManager mSubMgr = mock(SubscriptionManager.class);
     private final VcnManagementService mVcnMgmtSvc;
+    private final PersistableBundleUtils.LockingReadWriteHelper mConfigReadWriteHelper =
+            mock(PersistableBundleUtils.LockingReadWriteHelper.class);
 
-    public VcnManagementServiceTest() {
-        doReturn(Context.CONNECTIVITY_SERVICE)
-                .when(mMockContext)
-                .getSystemServiceName(ConnectivityManager.class);
-        doReturn(mConnMgr).when(mMockContext).getSystemService(Context.CONNECTIVITY_SERVICE);
+    public VcnManagementServiceTest() throws Exception {
+        setupSystemService(mConnMgr, Context.CONNECTIVITY_SERVICE, ConnectivityManager.class);
+        setupSystemService(mTelMgr, Context.TELEPHONY_SERVICE, TelephonyManager.class);
+        setupSystemService(
+                mSubMgr, Context.TELEPHONY_SUBSCRIPTION_SERVICE, SubscriptionManager.class);
 
         doReturn(mTestLooper.getLooper()).when(mMockDeps).getLooper();
+        doReturn(Process.FIRST_APPLICATION_UID).when(mMockDeps).getBinderCallingUid();
+        doReturn(mConfigReadWriteHelper)
+                .when(mMockDeps)
+                .newPersistableBundleLockingReadWriteHelper(any());
+
+        final PersistableBundle bundle =
+                PersistableBundleUtils.fromMap(
+                        TEST_VCN_CONFIG_MAP,
+                        PersistableBundleUtils::fromParcelUuid,
+                        VcnConfig::toPersistableBundle);
+        doReturn(bundle).when(mConfigReadWriteHelper).readFromDisk();
+
+        setupMockedCarrierPrivilege(true);
         mVcnMgmtSvc = new VcnManagementService(mMockContext, mMockDeps);
     }
 
+    private void setupSystemService(Object service, String name, Class<?> serviceClass) {
+        doReturn(name).when(mMockContext).getSystemServiceName(serviceClass);
+        doReturn(service).when(mMockContext).getSystemService(name);
+    }
+
+    private void setupMockedCarrierPrivilege(boolean isPrivileged) {
+        doReturn(Collections.singletonList(TEST_SUBSCRIPTION_INFO))
+                .when(mSubMgr)
+                .getSubscriptionsInGroup(any());
+        doReturn(isPrivileged)
+                .when(mTelMgr)
+                .hasCarrierPrivileges(eq(TEST_SUBSCRIPTION_INFO.getSubscriptionId()));
+    }
+
     @Test
     public void testSystemReady() throws Exception {
         mVcnMgmtSvc.systemReady();
@@ -59,4 +140,119 @@
         verify(mConnMgr)
                 .registerNetworkProvider(any(VcnManagementService.VcnNetworkProvider.class));
     }
+
+    @Test
+    public void testNonSystemServerRealConfigFileAccessPermission() throws Exception {
+        // Attempt to build a real instance of the dependencies, and verify we cannot write to the
+        // file.
+        VcnManagementService.Dependencies deps = new VcnManagementService.Dependencies();
+        PersistableBundleUtils.LockingReadWriteHelper configReadWriteHelper =
+                deps.newPersistableBundleLockingReadWriteHelper(
+                        VcnManagementService.VCN_CONFIG_FILE);
+
+        // Even tests should not be able to read/write configs from disk; SELinux policies restrict
+        // it to only the system server.
+        // Reading config should always return null since the file "does not exist", and writing
+        // should throw an IOException.
+        assertNull(configReadWriteHelper.readFromDisk());
+
+        try {
+            configReadWriteHelper.writeToDisk(new PersistableBundle());
+            fail("Expected IOException due to SELinux policy");
+        } catch (FileNotFoundException expected) {
+        }
+    }
+
+    @Test
+    public void testLoadVcnConfigsOnStartup() throws Exception {
+        mTestLooper.dispatchAll();
+
+        assertEquals(TEST_VCN_CONFIG_MAP, mVcnMgmtSvc.getConfigs());
+        verify(mConfigReadWriteHelper).readFromDisk();
+    }
+
+    @Test
+    public void testSetVcnConfigRequiresNonSystemServer() throws Exception {
+        doReturn(Process.SYSTEM_UID).when(mMockDeps).getBinderCallingUid();
+
+        try {
+            mVcnMgmtSvc.setVcnConfig(TEST_UUID_1, VcnConfigTest.buildTestConfig());
+            fail("Expected IllegalStateException exception for system server");
+        } catch (IllegalStateException expected) {
+        }
+    }
+
+    @Test
+    public void testSetVcnConfigRequiresSystemUser() throws Exception {
+        doReturn(UserHandle.getUid(UserHandle.MIN_SECONDARY_USER_ID, Process.FIRST_APPLICATION_UID))
+                .when(mMockDeps)
+                .getBinderCallingUid();
+
+        try {
+            mVcnMgmtSvc.setVcnConfig(TEST_UUID_1, VcnConfigTest.buildTestConfig());
+            fail("Expected security exception for non system user");
+        } catch (SecurityException expected) {
+        }
+    }
+
+    @Test
+    public void testSetVcnConfigRequiresCarrierPrivileges() throws Exception {
+        setupMockedCarrierPrivilege(false);
+
+        try {
+            mVcnMgmtSvc.setVcnConfig(TEST_UUID_1, VcnConfigTest.buildTestConfig());
+            fail("Expected security exception for missing carrier privileges");
+        } catch (SecurityException expected) {
+        }
+    }
+
+    @Test
+    public void testSetVcnConfig() throws Exception {
+        // Use a different UUID to simulate a new VCN config.
+        mVcnMgmtSvc.setVcnConfig(TEST_UUID_2, TEST_VCN_CONFIG);
+        assertEquals(TEST_VCN_CONFIG, mVcnMgmtSvc.getConfigs().get(TEST_UUID_2));
+        verify(mConfigReadWriteHelper).writeToDisk(any(PersistableBundle.class));
+    }
+
+    @Test
+    public void testClearVcnConfigRequiresNonSystemServer() throws Exception {
+        doReturn(Process.SYSTEM_UID).when(mMockDeps).getBinderCallingUid();
+
+        try {
+            mVcnMgmtSvc.clearVcnConfig(TEST_UUID_1);
+            fail("Expected IllegalStateException exception for system server");
+        } catch (IllegalStateException expected) {
+        }
+    }
+
+    @Test
+    public void testClearVcnConfigRequiresSystemUser() throws Exception {
+        doReturn(UserHandle.getUid(UserHandle.MIN_SECONDARY_USER_ID, Process.FIRST_APPLICATION_UID))
+                .when(mMockDeps)
+                .getBinderCallingUid();
+
+        try {
+            mVcnMgmtSvc.clearVcnConfig(TEST_UUID_1);
+            fail("Expected security exception for non system user");
+        } catch (SecurityException expected) {
+        }
+    }
+
+    @Test
+    public void testClearVcnConfigRequiresCarrierPrivileges() throws Exception {
+        setupMockedCarrierPrivilege(false);
+
+        try {
+            mVcnMgmtSvc.clearVcnConfig(TEST_UUID_1);
+            fail("Expected security exception for missing carrier privileges");
+        } catch (SecurityException expected) {
+        }
+    }
+
+    @Test
+    public void testClearVcnConfig() throws Exception {
+        mVcnMgmtSvc.clearVcnConfig(TEST_UUID_1);
+        assertTrue(mVcnMgmtSvc.getConfigs().isEmpty());
+        verify(mConfigReadWriteHelper).writeToDisk(any(PersistableBundle.class));
+    }
 }
diff --git a/tests/vcn/java/com/android/server/vcn/TelephonySubscriptionTrackerTest.java b/tests/vcn/java/com/android/server/vcn/TelephonySubscriptionTrackerTest.java
new file mode 100644
index 0000000..17b8f64
--- /dev/null
+++ b/tests/vcn/java/com/android/server/vcn/TelephonySubscriptionTrackerTest.java
@@ -0,0 +1,333 @@
+/*
+ * 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.server.vcn;
+
+import static android.telephony.CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED;
+import static android.telephony.CarrierConfigManager.EXTRA_SLOT_INDEX;
+import static android.telephony.CarrierConfigManager.EXTRA_SUBSCRIPTION_INDEX;
+import static android.telephony.SubscriptionManager.INVALID_SIM_SLOT_INDEX;
+import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID;
+
+import static com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionSnapshot;
+import static com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionTrackerCallback;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.argThat;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+
+import android.annotation.NonNull;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.os.Handler;
+import android.os.HandlerExecutor;
+import android.os.ParcelUuid;
+import android.os.test.TestLooper;
+import android.telephony.CarrierConfigManager;
+import android.telephony.SubscriptionInfo;
+import android.telephony.SubscriptionManager;
+import android.telephony.SubscriptionManager.OnSubscriptionsChangedListener;
+import android.util.ArraySet;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+import java.util.UUID;
+
+/** Tests for TelephonySubscriptionTracker */
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class TelephonySubscriptionTrackerTest {
+    private static final ParcelUuid TEST_PARCEL_UUID = new ParcelUuid(UUID.randomUUID());
+    private static final int TEST_SIM_SLOT_INDEX = 1;
+    private static final int TEST_SUBSCRIPTION_ID_1 = 2;
+    private static final SubscriptionInfo TEST_SUBINFO_1 = mock(SubscriptionInfo.class);
+    private static final int TEST_SUBSCRIPTION_ID_2 = 3;
+    private static final SubscriptionInfo TEST_SUBINFO_2 = mock(SubscriptionInfo.class);
+    private static final Map<Integer, ParcelUuid> TEST_SUBID_TO_GROUP_MAP;
+
+    static {
+        final Map<Integer, ParcelUuid> subIdToGroupMap = new HashMap<>();
+        subIdToGroupMap.put(TEST_SUBSCRIPTION_ID_1, TEST_PARCEL_UUID);
+        subIdToGroupMap.put(TEST_SUBSCRIPTION_ID_2, TEST_PARCEL_UUID);
+        TEST_SUBID_TO_GROUP_MAP = Collections.unmodifiableMap(subIdToGroupMap);
+    }
+
+    @NonNull private final Context mContext;
+    @NonNull private final TestLooper mTestLooper;
+    @NonNull private final Handler mHandler;
+    @NonNull private final TelephonySubscriptionTracker.Dependencies mDeps;
+
+    @NonNull private final SubscriptionManager mSubscriptionManager;
+    @NonNull private final CarrierConfigManager mCarrierConfigManager;
+
+    @NonNull private TelephonySubscriptionTrackerCallback mCallback;
+    @NonNull private TelephonySubscriptionTracker mTelephonySubscriptionTracker;
+
+    public TelephonySubscriptionTrackerTest() {
+        mContext = mock(Context.class);
+        mTestLooper = new TestLooper();
+        mHandler = new Handler(mTestLooper.getLooper());
+        mDeps = mock(TelephonySubscriptionTracker.Dependencies.class);
+
+        mSubscriptionManager = mock(SubscriptionManager.class);
+        mCarrierConfigManager = mock(CarrierConfigManager.class);
+
+        doReturn(Context.TELEPHONY_SUBSCRIPTION_SERVICE)
+                .when(mContext)
+                .getSystemServiceName(SubscriptionManager.class);
+        doReturn(mSubscriptionManager)
+                .when(mContext)
+                .getSystemService(Context.TELEPHONY_SUBSCRIPTION_SERVICE);
+
+        doReturn(Context.CARRIER_CONFIG_SERVICE)
+                .when(mContext)
+                .getSystemServiceName(CarrierConfigManager.class);
+        doReturn(mCarrierConfigManager)
+                .when(mContext)
+                .getSystemService(Context.CARRIER_CONFIG_SERVICE);
+
+        // subId 1, 2 are in same subGrp, only subId 1 is active
+        doReturn(TEST_PARCEL_UUID).when(TEST_SUBINFO_1).getGroupUuid();
+        doReturn(TEST_PARCEL_UUID).when(TEST_SUBINFO_2).getGroupUuid();
+        doReturn(TEST_SIM_SLOT_INDEX).when(TEST_SUBINFO_1).getSimSlotIndex();
+        doReturn(INVALID_SIM_SLOT_INDEX).when(TEST_SUBINFO_2).getSimSlotIndex();
+        doReturn(TEST_SUBSCRIPTION_ID_1).when(TEST_SUBINFO_1).getSubscriptionId();
+        doReturn(TEST_SUBSCRIPTION_ID_2).when(TEST_SUBINFO_2).getSubscriptionId();
+    }
+
+    @Before
+    public void setUp() throws Exception {
+        mCallback = mock(TelephonySubscriptionTrackerCallback.class);
+        mTelephonySubscriptionTracker =
+                new TelephonySubscriptionTracker(mContext, mHandler, mCallback, mDeps);
+        mTelephonySubscriptionTracker.register();
+
+        doReturn(true).when(mDeps).isConfigForIdentifiedCarrier(any());
+        doReturn(Arrays.asList(TEST_SUBINFO_1, TEST_SUBINFO_2))
+                .when(mSubscriptionManager)
+                .getAllSubscriptionInfoList();
+    }
+
+    private IntentFilter getIntentFilter() {
+        final ArgumentCaptor<IntentFilter> captor = ArgumentCaptor.forClass(IntentFilter.class);
+        verify(mContext).registerReceiver(any(), captor.capture(), any(), any());
+
+        return captor.getValue();
+    }
+
+    private OnSubscriptionsChangedListener getOnSubscriptionsChangedListener() {
+        final ArgumentCaptor<OnSubscriptionsChangedListener> captor =
+                ArgumentCaptor.forClass(OnSubscriptionsChangedListener.class);
+        verify(mSubscriptionManager).addOnSubscriptionsChangedListener(any(), captor.capture());
+
+        return captor.getValue();
+    }
+
+    private Intent buildTestBroadcastIntent(boolean hasValidSubscription) {
+        Intent intent = new Intent(ACTION_CARRIER_CONFIG_CHANGED);
+        intent.putExtra(EXTRA_SLOT_INDEX, TEST_SIM_SLOT_INDEX);
+        intent.putExtra(
+                EXTRA_SUBSCRIPTION_INDEX,
+                hasValidSubscription ? TEST_SUBSCRIPTION_ID_1 : INVALID_SUBSCRIPTION_ID);
+
+        return intent;
+    }
+
+    private TelephonySubscriptionSnapshot buildExpectedSnapshot(Set<ParcelUuid> activeSubGroups) {
+        return buildExpectedSnapshot(TEST_SUBID_TO_GROUP_MAP, activeSubGroups);
+    }
+
+    private TelephonySubscriptionSnapshot buildExpectedSnapshot(
+            Map<Integer, ParcelUuid> subIdToGroupMap, Set<ParcelUuid> activeSubGroups) {
+        return new TelephonySubscriptionSnapshot(subIdToGroupMap, activeSubGroups);
+    }
+
+    private void verifyNoActiveSubscriptions() {
+        verify(mCallback).onNewSnapshot(
+                argThat(snapshot -> snapshot.getActiveSubscriptionGroups().isEmpty()));
+    }
+
+    private void setupReadySubIds() {
+        mTelephonySubscriptionTracker.setReadySubIdsBySlotId(
+                Collections.singletonMap(TEST_SIM_SLOT_INDEX, TEST_SUBSCRIPTION_ID_1));
+    }
+
+    @Test
+    public void testRegister() throws Exception {
+        verify(mContext)
+                .registerReceiver(
+                        eq(mTelephonySubscriptionTracker),
+                        any(IntentFilter.class),
+                        any(),
+                        eq(mHandler));
+        final IntentFilter filter = getIntentFilter();
+        assertEquals(1, filter.countActions());
+        assertTrue(filter.hasAction(ACTION_CARRIER_CONFIG_CHANGED));
+
+        verify(mSubscriptionManager)
+                .addOnSubscriptionsChangedListener(any(HandlerExecutor.class), any());
+        assertNotNull(getOnSubscriptionsChangedListener());
+    }
+
+    @Test
+    public void testUnregister() throws Exception {
+        mTelephonySubscriptionTracker.unregister();
+
+        verify(mContext).unregisterReceiver(eq(mTelephonySubscriptionTracker));
+
+        final OnSubscriptionsChangedListener listener = getOnSubscriptionsChangedListener();
+        verify(mSubscriptionManager).removeOnSubscriptionsChangedListener(eq(listener));
+    }
+
+    @Test
+    public void testOnSubscriptionsChangedFired_NoReadySubIds() throws Exception {
+        final OnSubscriptionsChangedListener listener = getOnSubscriptionsChangedListener();
+        listener.onSubscriptionsChanged();
+        mTestLooper.dispatchAll();
+
+        verifyNoActiveSubscriptions();
+    }
+
+    @Test
+    public void testOnSubscriptionsChangedFired_WithReadySubIds() throws Exception {
+        setupReadySubIds();
+
+        final OnSubscriptionsChangedListener listener = getOnSubscriptionsChangedListener();
+        listener.onSubscriptionsChanged();
+        mTestLooper.dispatchAll();
+
+        final Set<ParcelUuid> activeSubGroups = Collections.singleton(TEST_PARCEL_UUID);
+        verify(mCallback).onNewSnapshot(eq(buildExpectedSnapshot(activeSubGroups)));
+    }
+
+    @Test
+    public void testReceiveBroadcast_ConfigReadyWithSubscriptions() throws Exception {
+        mTelephonySubscriptionTracker.onReceive(mContext, buildTestBroadcastIntent(true));
+        mTestLooper.dispatchAll();
+
+        final Set<ParcelUuid> activeSubGroups = Collections.singleton(TEST_PARCEL_UUID);
+        verify(mCallback).onNewSnapshot(eq(buildExpectedSnapshot(activeSubGroups)));
+    }
+
+    @Test
+    public void testReceiveBroadcast_ConfigReadyNoSubscriptions() throws Exception {
+        doReturn(new ArrayList<SubscriptionInfo>())
+                .when(mSubscriptionManager)
+                .getAllSubscriptionInfoList();
+
+        mTelephonySubscriptionTracker.onReceive(mContext, buildTestBroadcastIntent(true));
+        mTestLooper.dispatchAll();
+
+        // Expect an empty snapshot
+        verify(mCallback).onNewSnapshot(
+                eq(buildExpectedSnapshot(Collections.emptyMap(), Collections.emptySet())));
+    }
+
+    @Test
+    public void testReceiveBroadcast_SlotCleared() throws Exception {
+        setupReadySubIds();
+
+        mTelephonySubscriptionTracker.onReceive(mContext, buildTestBroadcastIntent(false));
+        mTestLooper.dispatchAll();
+
+        verifyNoActiveSubscriptions();
+        assertTrue(mTelephonySubscriptionTracker.getReadySubIdsBySlotId().isEmpty());
+    }
+
+    @Test
+    public void testReceiveBroadcast_ConfigNotReady() throws Exception {
+        doReturn(false).when(mDeps).isConfigForIdentifiedCarrier(any());
+
+        mTelephonySubscriptionTracker.onReceive(mContext, buildTestBroadcastIntent(true));
+        mTestLooper.dispatchAll();
+
+        // No interactions expected; config was not loaded
+        verifyNoMoreInteractions(mCallback);
+    }
+
+    @Test
+    public void testSubscriptionsClearedAfterValidTriggersCallbacks() throws Exception {
+        final Set<ParcelUuid> activeSubGroups = Collections.singleton(TEST_PARCEL_UUID);
+
+        mTelephonySubscriptionTracker.onReceive(mContext, buildTestBroadcastIntent(true));
+        mTestLooper.dispatchAll();
+        verify(mCallback).onNewSnapshot(eq(buildExpectedSnapshot(activeSubGroups)));
+        assertNotNull(
+                mTelephonySubscriptionTracker.getReadySubIdsBySlotId().get(TEST_SIM_SLOT_INDEX));
+
+        doReturn(Collections.emptyList()).when(mSubscriptionManager).getAllSubscriptionInfoList();
+        mTelephonySubscriptionTracker.onReceive(mContext, buildTestBroadcastIntent(true));
+        mTestLooper.dispatchAll();
+        verify(mCallback).onNewSnapshot(
+                eq(buildExpectedSnapshot(Collections.emptyMap(), Collections.emptySet())));
+    }
+
+    @Test
+    public void testSlotClearedAfterValidTriggersCallbacks() throws Exception {
+        final Set<ParcelUuid> activeSubGroups = Collections.singleton(TEST_PARCEL_UUID);
+
+        mTelephonySubscriptionTracker.onReceive(mContext, buildTestBroadcastIntent(true));
+        mTestLooper.dispatchAll();
+        verify(mCallback).onNewSnapshot(eq(buildExpectedSnapshot(activeSubGroups)));
+        assertNotNull(
+                mTelephonySubscriptionTracker.getReadySubIdsBySlotId().get(TEST_SIM_SLOT_INDEX));
+
+        mTelephonySubscriptionTracker.onReceive(mContext, buildTestBroadcastIntent(false));
+        mTestLooper.dispatchAll();
+        verify(mCallback).onNewSnapshot(eq(buildExpectedSnapshot(Collections.emptySet())));
+        assertNull(mTelephonySubscriptionTracker.getReadySubIdsBySlotId().get(TEST_SIM_SLOT_INDEX));
+    }
+
+    @Test
+    public void testTelephonySubscriptionSnapshotGetGroupForSubId() throws Exception {
+        final TelephonySubscriptionSnapshot snapshot =
+                new TelephonySubscriptionSnapshot(TEST_SUBID_TO_GROUP_MAP, Collections.emptySet());
+
+        assertEquals(TEST_PARCEL_UUID, snapshot.getGroupForSubId(TEST_SUBSCRIPTION_ID_1));
+        assertEquals(TEST_PARCEL_UUID, snapshot.getGroupForSubId(TEST_SUBSCRIPTION_ID_2));
+    }
+
+    @Test
+    public void testTelephonySubscriptionSnapshotGetAllSubIdsInGroup() throws Exception {
+        final TelephonySubscriptionSnapshot snapshot =
+                new TelephonySubscriptionSnapshot(TEST_SUBID_TO_GROUP_MAP, Collections.emptySet());
+
+        assertEquals(
+                new ArraySet<>(Arrays.asList(TEST_SUBSCRIPTION_ID_1, TEST_SUBSCRIPTION_ID_2)),
+                snapshot.getAllSubIdsInGroup(TEST_PARCEL_UUID));
+    }
+}
diff --git a/tools/aapt2/util/Util.cpp b/tools/aapt2/util/Util.cpp
index 28330db..d7a8e6f 100644
--- a/tools/aapt2/util/Util.cpp
+++ b/tools/aapt2/util/Util.cpp
@@ -548,14 +548,14 @@
 }
 
 StringPiece16 GetString16(const android::ResStringPool& pool, size_t idx) {
-  if (auto str = pool.stringAt(idx)) {
+  if (auto str = pool.stringAt(idx); str.ok()) {
     return *str;
   }
   return StringPiece16();
 }
 
 std::string GetString(const android::ResStringPool& pool, size_t idx) {
-  if (auto str = pool.string8At(idx)) {
+  if (auto str = pool.string8At(idx); str.ok()) {
     return ModifiedUtf8ToUtf8(str->to_string());
   }
   return Utf16ToUtf8(GetString16(pool, idx));
diff --git a/tools/validatekeymaps/Main.cpp b/tools/validatekeymaps/Main.cpp
index 950473d..991b280 100644
--- a/tools/validatekeymaps/Main.cpp
+++ b/tools/validatekeymaps/Main.cpp
@@ -96,7 +96,7 @@
 
         case FileType::KEY_LAYOUT: {
             base::Result<std::shared_ptr<KeyLayoutMap>> ret = KeyLayoutMap::load(filename);
-            if (!ret) {
+            if (!ret.ok()) {
                 error("Error %s parsing key layout file.\n\n", ret.error().message().c_str());
                 return false;
             }
@@ -106,7 +106,7 @@
         case FileType::KEY_CHARACTER_MAP: {
             base::Result<std::shared_ptr<KeyCharacterMap>> ret =
                     KeyCharacterMap::load(filename, KeyCharacterMap::Format::ANY);
-            if (!ret) {
+            if (!ret.ok()) {
                 error("Error %s parsing key character map file.\n\n",
                       ret.error().message().c_str());
                 return false;
diff --git a/wifi/Android.bp b/wifi/Android.bp
index c05f52c..07b2ea9 100644
--- a/wifi/Android.bp
+++ b/wifi/Android.bp
@@ -31,9 +31,6 @@
         "java/**/*.java",
         "java/**/*.aidl",
     ],
-    exclude_srcs: [
-        ":framework-wifi-non-updatable-sources"
-    ],
     path: "java",
     visibility: ["//visibility:private"],
 }
@@ -48,20 +45,6 @@
 }
 
 filegroup {
-    name: "framework-wifi-non-updatable-sources",
-    srcs: [
-        // TODO(b/146011398) package android.net.wifi is now split amongst 2 jars: framework.jar and
-        // framework-wifi.jar. This is not a good idea, should move WifiNetworkScoreCache
-        // to a separate package.
-        "java/android/net/wifi/SoftApConfToXmlMigrationUtil.java",
-        "java/android/net/wifi/WifiNetworkScoreCache.java",
-        "java/android/net/wifi/WifiMigration.java",
-        "java/android/net/wifi/nl80211/*.java",
-        ":libwificond_ipc_aidl",
-    ],
-}
-
-filegroup {
     name: "framework-wifi-annotations",
     srcs: ["java/android/net/wifi/WifiAnnotations.java"],
 }
@@ -69,6 +52,7 @@
 // list of tests that are allowed to access @hide APIs from framework-wifi
 test_access_hidden_api_whitelist = [
     "//frameworks/base/wifi/tests",
+    "//frameworks/base/wifi/non-updatable/tests",
     "//frameworks/opt/net/wifi/tests/wifitests:__subpackages__",
 
     "//external/robolectric-shadows:__subpackages__",
diff --git a/wifi/java/android/net/wifi/IWifiManager.aidl b/wifi/java/android/net/wifi/IWifiManager.aidl
index 06ebee4..23f47ef 100644
--- a/wifi/java/android/net/wifi/IWifiManager.aidl
+++ b/wifi/java/android/net/wifi/IWifiManager.aidl
@@ -147,6 +147,8 @@
 
     void updateInterfaceIpState(String ifaceName, int mode);
 
+    boolean isDefaultCoexAlgorithmEnabled();
+
     void setCoexUnsafeChannels(in List<CoexUnsafeChannel> unsafeChannels, int mandatoryRestrictions);
 
     List<CoexUnsafeChannel> getCoexUnsafeChannels();
diff --git a/wifi/java/android/net/wifi/SecurityParams.java b/wifi/java/android/net/wifi/SecurityParams.java
index 0ab6f57..8ee2ea0 100644
--- a/wifi/java/android/net/wifi/SecurityParams.java
+++ b/wifi/java/android/net/wifi/SecurityParams.java
@@ -192,6 +192,15 @@
     }
 
     /**
+     * Get the security type of this params.
+     *
+     * @return The security type defined in {@link WifiConfiguration}.
+     */
+    public @SecurityType int getSecurityType() {
+        return mSecurityType;
+    }
+
+    /**
      * Check the security type of this params.
      *
      * @param type the testing security type.
@@ -563,9 +572,64 @@
     }
 
     /**
+     * Create a params according to the security type.
+     *
+     * @param securityType One of the following security types:
+     * {@link WifiConfiguration#SECURITY_TYPE_OPEN},
+     * {@link WifiConfiguration#SECURITY_TYPE_WEP},
+     * {@link WifiConfiguration#SECURITY_TYPE_PSK},
+     * {@link WifiConfiguration#SECURITY_TYPE_EAP},
+     * {@link WifiConfiguration#SECURITY_TYPE_SAE},
+     * {@link WifiConfiguration#SECURITY_TYPE_OWE},
+     * {@link WifiConfiguration#SECURITY_TYPE_WAPI_PSK},
+     * {@link WifiConfiguration#SECURITY_TYPE_WAPI_CERT},
+     * {@link WifiConfiguration#SECURITY_TYPE_EAP_WPA3_ENTERPRISE},
+     * {@link WifiConfiguration#SECURITY_TYPE_EAP_WPA3_ENTERPRISE_192_BIT},
+     *
+     * @return the corresponding security params if the security type is valid;
+     *         otherwise, throw IllegalArgumentException.
+     */
+    public static @NonNull SecurityParams createSecurityParamsBySecurityType(
+            @WifiConfiguration.SecurityType int securityType) {
+        switch (securityType) {
+            case WifiConfiguration.SECURITY_TYPE_OPEN:
+                return createOpenParams();
+            case WifiConfiguration.SECURITY_TYPE_WEP:
+                return createWepParams();
+            case WifiConfiguration.SECURITY_TYPE_PSK:
+                return createWpaWpa2PersonalParams();
+            case WifiConfiguration.SECURITY_TYPE_EAP:
+                return createWpaWpa2EnterpriseParams();
+            case WifiConfiguration.SECURITY_TYPE_SAE:
+                return createWpa3PersonalParams();
+            // The value of {@link WifiConfiguration.SECURITY_TYPE_EAP_SUITE_B} is the same as
+            // {@link #WifiConfiguration.SECURITY_TYPE_EAP_WPA3_ENTERPRISE_192_BIT}, remove it
+            // to avoid duplicate case label errors.
+            case WifiConfiguration.SECURITY_TYPE_EAP_WPA3_ENTERPRISE_192_BIT:
+                return createWpa3Enterprise192BitParams();
+            case WifiConfiguration.SECURITY_TYPE_OWE:
+                return createEnhancedOpenParams();
+            case WifiConfiguration.SECURITY_TYPE_WAPI_PSK:
+                return createWapiPskParams();
+            case WifiConfiguration.SECURITY_TYPE_WAPI_CERT:
+                return createWapiCertParams();
+            case WifiConfiguration.SECURITY_TYPE_EAP_WPA3_ENTERPRISE:
+                return createWpa3EnterpriseParams();
+            case WifiConfiguration.SECURITY_TYPE_OSEN:
+                return createOsenParams();
+            case WifiConfiguration.SECURITY_TYPE_PASSPOINT_R1_R2:
+                return SecurityParams.createPasspointParams(PASSPOINT_R2);
+            case WifiConfiguration.SECURITY_TYPE_PASSPOINT_R3:
+                return SecurityParams.createPasspointParams(PASSPOINT_R3);
+            default:
+                throw new IllegalArgumentException("unknown security type " + securityType);
+        }
+    }
+
+    /**
      * Create EAP security params.
      */
-    public static @NonNull SecurityParams createWpaWpa2EnterpriseParams() {
+    private static @NonNull SecurityParams createWpaWpa2EnterpriseParams() {
         SecurityParams params = new SecurityParams();
         params.mSecurityType = WifiConfiguration.SECURITY_TYPE_EAP;
 
@@ -586,7 +650,7 @@
     /**
      * Create Passpoint security params.
      */
-    public static @NonNull SecurityParams createPasspointParams(@PasspointRelease int release) {
+    private static @NonNull SecurityParams createPasspointParams(@PasspointRelease int release) {
         SecurityParams params = new SecurityParams();
         switch (release) {
             case PASSPOINT_R1:
@@ -616,7 +680,7 @@
     /**
      * Create Enhanced Open params.
      */
-    public static @NonNull SecurityParams createEnhancedOpenParams() {
+    private static @NonNull SecurityParams createEnhancedOpenParams() {
         SecurityParams params = new SecurityParams();
         params.mSecurityType = WifiConfiguration.SECURITY_TYPE_OWE;
 
@@ -639,7 +703,7 @@
     /**
      * Create Open params.
      */
-    public static @NonNull SecurityParams createOpenParams() {
+    private static @NonNull SecurityParams createOpenParams() {
         SecurityParams params = new SecurityParams();
         params.mSecurityType = WifiConfiguration.SECURITY_TYPE_OPEN;
 
@@ -653,7 +717,7 @@
     /**
      * Create OSEN params.
      */
-    public static @NonNull SecurityParams createOsenParams() {
+    private static @NonNull SecurityParams createOsenParams() {
         SecurityParams params = new SecurityParams();
         params.mSecurityType = WifiConfiguration.SECURITY_TYPE_OSEN;
 
@@ -672,7 +736,7 @@
     /**
      * Create WAPI-CERT params.
      */
-    public static @NonNull SecurityParams createWapiCertParams() {
+    private static @NonNull SecurityParams createWapiCertParams() {
         SecurityParams params = new SecurityParams();
         params.mSecurityType = WifiConfiguration.SECURITY_TYPE_WAPI_CERT;
 
@@ -689,7 +753,7 @@
     /**
      * Create WAPI-PSK params.
      */
-    public static @NonNull SecurityParams createWapiPskParams() {
+    private static @NonNull SecurityParams createWapiPskParams() {
         SecurityParams params = new SecurityParams();
         params.mSecurityType = WifiConfiguration.SECURITY_TYPE_WAPI_PSK;
 
@@ -706,7 +770,7 @@
     /**
      * Create WEP params.
      */
-    public static @NonNull SecurityParams createWepParams() {
+    private static @NonNull SecurityParams createWepParams() {
         SecurityParams params = new SecurityParams();
         params.mSecurityType = WifiConfiguration.SECURITY_TYPE_WEP;
 
@@ -730,7 +794,7 @@
     /**
      * Create WPA3 Enterprise 192-bit params.
      */
-    public static @NonNull SecurityParams createWpa3Enterprise192BitParams() {
+    private static @NonNull SecurityParams createWpa3Enterprise192BitParams() {
         SecurityParams params = new SecurityParams();
         params.mSecurityType = WifiConfiguration.SECURITY_TYPE_EAP_WPA3_ENTERPRISE_192_BIT;
 
@@ -758,7 +822,7 @@
     /**
      * Create WPA3 Enterprise params.
      */
-    public static @NonNull SecurityParams createWpa3EnterpriseParams() {
+    private static @NonNull SecurityParams createWpa3EnterpriseParams() {
         SecurityParams params = new SecurityParams();
         params.mSecurityType = WifiConfiguration.SECURITY_TYPE_EAP_WPA3_ENTERPRISE;
 
@@ -780,7 +844,7 @@
     /**
      * Create WPA3 Personal params.
      */
-    public static @NonNull SecurityParams createWpa3PersonalParams() {
+    private static @NonNull SecurityParams createWpa3PersonalParams() {
         SecurityParams params = new SecurityParams();
         params.mSecurityType = WifiConfiguration.SECURITY_TYPE_SAE;
 
@@ -803,7 +867,7 @@
     /**
      * Create WPA/WPA2 Personal params.
      */
-    public static @NonNull SecurityParams createWpaWpa2PersonalParams() {
+    private static @NonNull SecurityParams createWpaWpa2PersonalParams() {
         SecurityParams params = new SecurityParams();
         params.mSecurityType = WifiConfiguration.SECURITY_TYPE_PSK;
 
diff --git a/wifi/java/android/net/wifi/WifiConfiguration.java b/wifi/java/android/net/wifi/WifiConfiguration.java
index ba4a54f..6c0b2df 100644
--- a/wifi/java/android/net/wifi/WifiConfiguration.java
+++ b/wifi/java/android/net/wifi/WifiConfiguration.java
@@ -566,11 +566,28 @@
      */
     public void setSecurityParams(@SecurityType int securityType) {
         // Clear existing data.
-        mSecurityParamsList = new ArrayList<>();
+        mSecurityParamsList.clear();
         addSecurityParams(securityType);
     }
 
     /**
+     * Set security params by the given key management mask.
+     *
+     * @param givenAllowedKeyManagement the given allowed key management mask.
+     * @hide
+     */
+    public void setSecurityParams(@NonNull BitSet givenAllowedKeyManagement) {
+        if (givenAllowedKeyManagement == null) {
+            throw new IllegalArgumentException("Invalid allowed key management mask.");
+        }
+        // Clear existing data.
+        mSecurityParamsList.clear();
+
+        allowedKeyManagement = (BitSet) givenAllowedKeyManagement.clone();
+        convertLegacyFieldsToSecurityParamsIfNeeded();
+    }
+
+    /**
      * Add the various security params.
      * <br>
      * This API would clear existing security types and add a default one.
@@ -578,11 +595,26 @@
      */
     public void setSecurityParams(SecurityParams params) {
         // Clear existing data.
-        mSecurityParamsList = new ArrayList<>();
+        mSecurityParamsList.clear();
         addSecurityParams(params);
     }
 
     /**
+     * Set the security params by the given security params list.
+     *
+     * This will overwrite existing security params list directly.
+     *
+     * @param securityParamsList the desired security params list.
+     * @hide
+     */
+    public void setSecurityParams(@NonNull List<SecurityParams> securityParamsList) {
+        if (securityParamsList == null || securityParamsList.isEmpty()) {
+            throw new IllegalArgumentException("An empty security params list is invalid.");
+        }
+        mSecurityParamsList = new ArrayList<>(securityParamsList);
+    }
+
+    /**
      * Add the various security params to correspond to the provided security type.
      * This is accomplished by setting the various BitSets exposed in WifiConfiguration.
      *
@@ -605,55 +637,7 @@
         if (mSecurityParamsList.stream().anyMatch(params -> params.isSecurityType(securityType))) {
             throw new IllegalArgumentException("duplicate security type " + securityType);
         }
-        SecurityParams params = null;
-        switch (securityType) {
-            case SECURITY_TYPE_OPEN:
-                params = SecurityParams.createOpenParams();
-                break;
-            case SECURITY_TYPE_WEP:
-                params = SecurityParams.createWepParams();
-                break;
-            case SECURITY_TYPE_PSK:
-                params = SecurityParams.createWpaWpa2PersonalParams();
-                break;
-            case SECURITY_TYPE_EAP:
-                params = SecurityParams.createWpaWpa2EnterpriseParams();
-                break;
-            case SECURITY_TYPE_SAE:
-                params = SecurityParams.createWpa3PersonalParams();
-                break;
-            // The value of {@link SECURITY_TYPE_EAP_SUITE_B} is the same as
-            // {@link #SECURITY_TYPE_EAP_WPA3_ENTERPRISE_192_BIT}, remove it to avoid
-            // duplicate case label errors.
-            case SECURITY_TYPE_EAP_WPA3_ENTERPRISE_192_BIT:
-                params = SecurityParams.createWpa3Enterprise192BitParams();
-                break;
-            case SECURITY_TYPE_OWE:
-                params = SecurityParams.createEnhancedOpenParams();
-                break;
-            case SECURITY_TYPE_WAPI_PSK:
-                params = SecurityParams.createWapiPskParams();
-                break;
-            case SECURITY_TYPE_WAPI_CERT:
-                params = SecurityParams.createWapiCertParams();
-                break;
-            case SECURITY_TYPE_EAP_WPA3_ENTERPRISE:
-                params = SecurityParams.createWpa3EnterpriseParams();
-                break;
-            case SECURITY_TYPE_OSEN:
-                params = SecurityParams.createOsenParams();
-                break;
-            case SECURITY_TYPE_PASSPOINT_R1_R2:
-                params = SecurityParams.createPasspointParams(SecurityParams.PASSPOINT_R2);
-                break;
-            case SECURITY_TYPE_PASSPOINT_R3:
-                params = SecurityParams.createPasspointParams(SecurityParams.PASSPOINT_R3);
-                break;
-            default:
-                throw new IllegalArgumentException("unknown security type " + securityType);
-        }
-
-        addSecurityParams(params);
+        addSecurityParams(SecurityParams.createSecurityParamsBySecurityType(securityType));
     }
 
     /** @hide */
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index d7fcd54..5618ee8 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -3225,6 +3225,19 @@
     public @interface CoexRestriction {}
 
     /**
+     * @return {@code true} if the default coex algorithm is enabled. {@code false} otherwise.
+     *
+     * @hide
+     */
+    public boolean isDefaultCoexAlgorithmEnabled() {
+        try {
+            return mService.isDefaultCoexAlgorithmEnabled();
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
      * Specify the set of {@link CoexUnsafeChannel} to propagate through the framework for
      * Wi-Fi/Cellular coex channel avoidance if the default algorithm is disabled via overlay
      * (i.e. config_wifiCoexDefaultAlgorithmEnabled = false). Otherwise do nothing.
diff --git a/wifi/non-updatable/java/Android.bp b/wifi/non-updatable/java/Android.bp
new file mode 100644
index 0000000..b35b4be
--- /dev/null
+++ b/wifi/non-updatable/java/Android.bp
@@ -0,0 +1,35 @@
+// 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.
+
+// This directory contains framework Wifi APIs that are not part of the Wifi module (i.e. not
+// updatable), and are generally only called by the Wifi module.
+
+// necessary since we only want the `path` property to only refer to these files
+filegroup {
+    name: "framework-wifi-non-updatable-sources-internal",
+    srcs: ["src/**/*.java"],
+    path: "src",
+    visibility: ["//visibility:private"],
+}
+
+filegroup {
+    name: "framework-wifi-non-updatable-sources",
+    srcs: [
+        // TODO(b/146011398) package android.net.wifi is now split amongst 2 jars: framework.jar and
+        // framework-wifi.jar. This is not a good idea, should move WifiNetworkScoreCache
+        // to a separate package.
+        ":framework-wifi-non-updatable-sources-internal",
+        ":libwificond_ipc_aidl",
+    ],
+}
diff --git a/wifi/java/android/net/wifi/SoftApConfToXmlMigrationUtil.java b/wifi/non-updatable/java/src/android/net/wifi/SoftApConfToXmlMigrationUtil.java
similarity index 100%
rename from wifi/java/android/net/wifi/SoftApConfToXmlMigrationUtil.java
rename to wifi/non-updatable/java/src/android/net/wifi/SoftApConfToXmlMigrationUtil.java
diff --git a/wifi/java/android/net/wifi/WifiMigration.java b/wifi/non-updatable/java/src/android/net/wifi/WifiMigration.java
similarity index 98%
rename from wifi/java/android/net/wifi/WifiMigration.java
rename to wifi/non-updatable/java/src/android/net/wifi/WifiMigration.java
index 5792d27..4fabc0b 100755
--- a/wifi/java/android/net/wifi/WifiMigration.java
+++ b/wifi/non-updatable/java/src/android/net/wifi/WifiMigration.java
@@ -139,8 +139,8 @@
     /**
      * Load data from legacy shared wifi config store file.
      * <p>
-     * Expected AOSP format is available in the sample files under {@code /frameworks/base/wifi/
-     * java/android/net/wifi/migration_samples}.
+     * Expected AOSP format is available in the sample files under {@code
+     * frameworks/base/wifi/non-updatable/migration_samples/}.
      * </p>
      * <p>
      * Note:
@@ -218,8 +218,8 @@
     /**
      * Load data from legacy user wifi config store file.
      * <p>
-     * Expected AOSP format is available in the sample files under {@code /frameworks/base/wifi/
-     * java/android/net/wifi/migration_samples}.
+     * Expected AOSP format is available in the sample files under {@code
+     * frameworks/base/wifi/non-updatable/migration_samples/}.
      * </p>
      * <p>
      * Note:
diff --git a/wifi/java/android/net/wifi/WifiNetworkScoreCache.java b/wifi/non-updatable/java/src/android/net/wifi/WifiNetworkScoreCache.java
similarity index 98%
rename from wifi/java/android/net/wifi/WifiNetworkScoreCache.java
rename to wifi/non-updatable/java/src/android/net/wifi/WifiNetworkScoreCache.java
index 378549d..3903658 100755
--- a/wifi/java/android/net/wifi/WifiNetworkScoreCache.java
+++ b/wifi/non-updatable/java/src/android/net/wifi/WifiNetworkScoreCache.java
@@ -89,7 +89,7 @@
 
     @Override public final void updateScores(List<ScoredNetwork> networks) {
         if (networks == null || networks.isEmpty()) {
-           return;
+            return;
         }
         if (DBG) {
             Log.d(TAG, "updateScores list size=" + networks.size());
@@ -97,7 +97,7 @@
 
         boolean changed = false;
 
-        synchronized(mLock) {
+        synchronized (mLock) {
             for (ScoredNetwork network : networks) {
                 String networkKey = buildNetworkKey(network);
                 if (networkKey == null) {
@@ -189,7 +189,7 @@
         String key = buildNetworkKey(result);
         if (key == null) return null;
 
-        synchronized(mLock) {
+        synchronized (mLock) {
             ScoredNetwork network = mCache.get(key);
             return network;
         }
diff --git a/wifi/java/android/net/wifi/nl80211/ChannelSettings.java b/wifi/non-updatable/java/src/android/net/wifi/nl80211/ChannelSettings.java
similarity index 100%
rename from wifi/java/android/net/wifi/nl80211/ChannelSettings.java
rename to wifi/non-updatable/java/src/android/net/wifi/nl80211/ChannelSettings.java
diff --git a/wifi/java/android/net/wifi/nl80211/DeviceWiphyCapabilities.java b/wifi/non-updatable/java/src/android/net/wifi/nl80211/DeviceWiphyCapabilities.java
similarity index 100%
rename from wifi/java/android/net/wifi/nl80211/DeviceWiphyCapabilities.java
rename to wifi/non-updatable/java/src/android/net/wifi/nl80211/DeviceWiphyCapabilities.java
diff --git a/wifi/java/android/net/wifi/nl80211/HiddenNetwork.java b/wifi/non-updatable/java/src/android/net/wifi/nl80211/HiddenNetwork.java
similarity index 100%
rename from wifi/java/android/net/wifi/nl80211/HiddenNetwork.java
rename to wifi/non-updatable/java/src/android/net/wifi/nl80211/HiddenNetwork.java
diff --git a/wifi/java/android/net/wifi/nl80211/NativeScanResult.java b/wifi/non-updatable/java/src/android/net/wifi/nl80211/NativeScanResult.java
similarity index 100%
rename from wifi/java/android/net/wifi/nl80211/NativeScanResult.java
rename to wifi/non-updatable/java/src/android/net/wifi/nl80211/NativeScanResult.java
diff --git a/wifi/java/android/net/wifi/nl80211/NativeWifiClient.java b/wifi/non-updatable/java/src/android/net/wifi/nl80211/NativeWifiClient.java
similarity index 100%
rename from wifi/java/android/net/wifi/nl80211/NativeWifiClient.java
rename to wifi/non-updatable/java/src/android/net/wifi/nl80211/NativeWifiClient.java
diff --git a/wifi/java/android/net/wifi/nl80211/PnoNetwork.java b/wifi/non-updatable/java/src/android/net/wifi/nl80211/PnoNetwork.java
similarity index 100%
rename from wifi/java/android/net/wifi/nl80211/PnoNetwork.java
rename to wifi/non-updatable/java/src/android/net/wifi/nl80211/PnoNetwork.java
diff --git a/wifi/java/android/net/wifi/nl80211/PnoSettings.java b/wifi/non-updatable/java/src/android/net/wifi/nl80211/PnoSettings.java
similarity index 100%
rename from wifi/java/android/net/wifi/nl80211/PnoSettings.java
rename to wifi/non-updatable/java/src/android/net/wifi/nl80211/PnoSettings.java
diff --git a/wifi/java/android/net/wifi/nl80211/RadioChainInfo.java b/wifi/non-updatable/java/src/android/net/wifi/nl80211/RadioChainInfo.java
similarity index 100%
rename from wifi/java/android/net/wifi/nl80211/RadioChainInfo.java
rename to wifi/non-updatable/java/src/android/net/wifi/nl80211/RadioChainInfo.java
diff --git a/wifi/java/android/net/wifi/nl80211/SingleScanSettings.java b/wifi/non-updatable/java/src/android/net/wifi/nl80211/SingleScanSettings.java
similarity index 100%
rename from wifi/java/android/net/wifi/nl80211/SingleScanSettings.java
rename to wifi/non-updatable/java/src/android/net/wifi/nl80211/SingleScanSettings.java
diff --git a/wifi/java/android/net/wifi/nl80211/WifiNl80211Manager.java b/wifi/non-updatable/java/src/android/net/wifi/nl80211/WifiNl80211Manager.java
similarity index 100%
rename from wifi/java/android/net/wifi/nl80211/WifiNl80211Manager.java
rename to wifi/non-updatable/java/src/android/net/wifi/nl80211/WifiNl80211Manager.java
diff --git a/wifi/java/android/net/wifi/migration_samples/README.txt b/wifi/non-updatable/migration_samples/README.txt
similarity index 100%
rename from wifi/java/android/net/wifi/migration_samples/README.txt
rename to wifi/non-updatable/migration_samples/README.txt
diff --git a/wifi/java/android/net/wifi/migration_samples/Shared_WifiConfigStore.xml b/wifi/non-updatable/migration_samples/Shared_WifiConfigStore.xml
similarity index 100%
rename from wifi/java/android/net/wifi/migration_samples/Shared_WifiConfigStore.xml
rename to wifi/non-updatable/migration_samples/Shared_WifiConfigStore.xml
diff --git a/wifi/java/android/net/wifi/migration_samples/Shared_WifiConfigStoreSoftAp.xml b/wifi/non-updatable/migration_samples/Shared_WifiConfigStoreSoftAp.xml
similarity index 100%
rename from wifi/java/android/net/wifi/migration_samples/Shared_WifiConfigStoreSoftAp.xml
rename to wifi/non-updatable/migration_samples/Shared_WifiConfigStoreSoftAp.xml
diff --git a/wifi/java/android/net/wifi/migration_samples/User_WifiConfigStore.xml b/wifi/non-updatable/migration_samples/User_WifiConfigStore.xml
similarity index 100%
rename from wifi/java/android/net/wifi/migration_samples/User_WifiConfigStore.xml
rename to wifi/non-updatable/migration_samples/User_WifiConfigStore.xml
diff --git a/wifi/java/android/net/wifi/migration_samples/User_WifiConfigStoreNetworkSuggestions.xml b/wifi/non-updatable/migration_samples/User_WifiConfigStoreNetworkSuggestions.xml
similarity index 100%
rename from wifi/java/android/net/wifi/migration_samples/User_WifiConfigStoreNetworkSuggestions.xml
rename to wifi/non-updatable/migration_samples/User_WifiConfigStoreNetworkSuggestions.xml
diff --git a/wifi/non-updatable/tests/Android.bp b/wifi/non-updatable/tests/Android.bp
new file mode 100644
index 0000000..3f5cacf
--- /dev/null
+++ b/wifi/non-updatable/tests/Android.bp
@@ -0,0 +1,44 @@
+// 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.
+
+android_test {
+    name: "FrameworksWifiNonUpdatableApiTests",
+
+    defaults: ["framework-wifi-test-defaults"],
+
+    srcs: ["src/**/*.java"],
+
+    jacoco: {
+        include_filter: ["android.net.wifi.*"],
+        // TODO(b/147521214) need to exclude test classes
+        exclude_filter: [],
+    },
+
+    static_libs: [
+        "androidx.test.rules",
+        "frameworks-base-testutils",
+        "guava",
+        "mockito-target-minus-junit4",
+        "truth-prebuilt",
+    ],
+
+    libs: [
+        "android.test.runner",
+        "android.test.base",
+    ],
+
+    test_suites: [
+        "general-tests",
+    ],
+}
diff --git a/wifi/non-updatable/tests/AndroidManifest.xml b/wifi/non-updatable/tests/AndroidManifest.xml
new file mode 100644
index 0000000..18986fc
--- /dev/null
+++ b/wifi/non-updatable/tests/AndroidManifest.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ 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
+  -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+     package="android.net.wifi.nonupdatable.test">
+
+    <application>
+        <uses-library android:name="android.test.runner"/>
+        <activity android:label="WifiTestDummyLabel"
+             android:name="WifiTestDummyName"
+             android:exported="true">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN"/>
+                <category android:name="android.intent.category.LAUNCHER"/>
+            </intent-filter>
+        </activity>
+    </application>
+
+    <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
+         android:targetPackage="android.net.wifi.nonupdatable.test"
+         android:label="Frameworks Wifi Non-updatable API Tests">
+    </instrumentation>
+
+</manifest>
diff --git a/wifi/non-updatable/tests/AndroidTest.xml b/wifi/non-updatable/tests/AndroidTest.xml
new file mode 100644
index 0000000..4e8bb55
--- /dev/null
+++ b/wifi/non-updatable/tests/AndroidTest.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+<configuration description="Runs Frameworks Wifi Non-updatable API Tests.">
+    <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
+        <option name="test-file-name" value="FrameworksWifiNonUpdatableApiTests.apk" />
+    </target_preparer>
+
+    <option name="test-suite-tag" value="apct" />
+    <option name="test-tag" value="FrameworksWifiNonUpdatableApiTests" />
+    <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+        <option name="package" value="android.net.wifi.nonupdatable.test" />
+        <option name="runner" value="androidx.test.runner.AndroidJUnitRunner" />
+        <option name="hidden-api-checks" value="false"/>
+    </test>
+</configuration>
diff --git a/wifi/non-updatable/tests/README.md b/wifi/non-updatable/tests/README.md
new file mode 100644
index 0000000..ad535f4
--- /dev/null
+++ b/wifi/non-updatable/tests/README.md
@@ -0,0 +1,32 @@
+# Wifi Non-Updatable Framework Unit Tests
+This package contains unit tests for the non-updatable part (i.e. outside the Wifi module) of the
+Android Wifi framework APIs based on the
+[Android Testing Support Library](http://developer.android.com/tools/testing-support-library/index.html).
+The test cases are built using the [JUnit](http://junit.org/) and [Mockito](http://mockito.org/)
+libraries.
+
+## Running Tests
+The easiest way to run tests is simply run
+
+```
+atest android.net.wifi
+```
+
+To pick up changes in framework/base, you will need to:
+1. rebuild the framework library 'make -j32'
+2. sync over the updated library to the device 'adb sync'
+3. restart framework on the device 'adb shell stop' then 'adb shell start'
+
+To enable syncing data to the device for first time after clean reflash:
+1. adb disable-verity
+2. adb reboot
+3. adb remount
+
+## Adding Tests
+Tests can be added by adding classes to the src directory. JUnit4 style test cases can
+be written by simply annotating test methods with `org.junit.Test`.
+
+## Debugging Tests
+If you are trying to debug why tests are not doing what you expected, you can add android log
+statements and use logcat to view them. The beginning and end of every tests is automatically logged
+with the tag `TestRunner`.
diff --git a/wifi/tests/src/android/net/wifi/SoftApConfToXmlMigrationUtilTest.java b/wifi/non-updatable/tests/src/android/net/wifi/SoftApConfToXmlMigrationUtilTest.java
similarity index 100%
rename from wifi/tests/src/android/net/wifi/SoftApConfToXmlMigrationUtilTest.java
rename to wifi/non-updatable/tests/src/android/net/wifi/SoftApConfToXmlMigrationUtilTest.java
diff --git a/wifi/tests/src/android/net/wifi/WifiNetworkScoreCacheTest.java b/wifi/non-updatable/tests/src/android/net/wifi/WifiNetworkScoreCacheTest.java
similarity index 99%
rename from wifi/tests/src/android/net/wifi/WifiNetworkScoreCacheTest.java
rename to wifi/non-updatable/tests/src/android/net/wifi/WifiNetworkScoreCacheTest.java
index fdd11a3..c4967eb 100644
--- a/wifi/tests/src/android/net/wifi/WifiNetworkScoreCacheTest.java
+++ b/wifi/non-updatable/tests/src/android/net/wifi/WifiNetworkScoreCacheTest.java
@@ -11,7 +11,7 @@
  * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
- * limitations under the License
+ * limitations under the License.
  */
 
 package android.net.wifi;
diff --git a/wifi/tests/src/android/net/wifi/nl80211/DeviceWiphyCapabilitiesTest.java b/wifi/non-updatable/tests/src/android/net/wifi/nl80211/DeviceWiphyCapabilitiesTest.java
similarity index 100%
rename from wifi/tests/src/android/net/wifi/nl80211/DeviceWiphyCapabilitiesTest.java
rename to wifi/non-updatable/tests/src/android/net/wifi/nl80211/DeviceWiphyCapabilitiesTest.java
diff --git a/wifi/tests/src/android/net/wifi/nl80211/NativeScanResultTest.java b/wifi/non-updatable/tests/src/android/net/wifi/nl80211/NativeScanResultTest.java
similarity index 100%
rename from wifi/tests/src/android/net/wifi/nl80211/NativeScanResultTest.java
rename to wifi/non-updatable/tests/src/android/net/wifi/nl80211/NativeScanResultTest.java
diff --git a/wifi/tests/src/android/net/wifi/nl80211/PnoSettingsTest.java b/wifi/non-updatable/tests/src/android/net/wifi/nl80211/PnoSettingsTest.java
similarity index 100%
rename from wifi/tests/src/android/net/wifi/nl80211/PnoSettingsTest.java
rename to wifi/non-updatable/tests/src/android/net/wifi/nl80211/PnoSettingsTest.java
diff --git a/wifi/tests/src/android/net/wifi/nl80211/SingleScanSettingsTest.java b/wifi/non-updatable/tests/src/android/net/wifi/nl80211/SingleScanSettingsTest.java
similarity index 100%
rename from wifi/tests/src/android/net/wifi/nl80211/SingleScanSettingsTest.java
rename to wifi/non-updatable/tests/src/android/net/wifi/nl80211/SingleScanSettingsTest.java
diff --git a/wifi/tests/src/android/net/wifi/nl80211/WifiNl80211ManagerTest.java b/wifi/non-updatable/tests/src/android/net/wifi/nl80211/WifiNl80211ManagerTest.java
similarity index 100%
rename from wifi/tests/src/android/net/wifi/nl80211/WifiNl80211ManagerTest.java
rename to wifi/non-updatable/tests/src/android/net/wifi/nl80211/WifiNl80211ManagerTest.java
diff --git a/wifi/tests/Android.bp b/wifi/tests/Android.bp
index 7eba0a7..c0be244 100644
--- a/wifi/tests/Android.bp
+++ b/wifi/tests/Android.bp
@@ -39,6 +39,7 @@
         "mockito-target-minus-junit4",
         "modules-utils-build",
         "net-tests-utils",
+        "net-utils-framework-common",
         "truth-prebuilt",
     ],
 
diff --git a/wifi/tests/src/android/net/wifi/SecurityParamsTest.java b/wifi/tests/src/android/net/wifi/SecurityParamsTest.java
index 2f6b724..c586ded 100644
--- a/wifi/tests/src/android/net/wifi/SecurityParamsTest.java
+++ b/wifi/tests/src/android/net/wifi/SecurityParamsTest.java
@@ -50,6 +50,7 @@
             int[] expectedAllowedGroupCiphers,
             boolean expectedRequirePmf) {
         assertTrue(params.isSecurityType(expectedSecurityType));
+        assertEquals(expectedSecurityType, params.getSecurityType());
         for (int b: expectedAllowedKeyManagement) {
             assertTrue(params.getAllowedKeyManagement().get(b));
         }
@@ -68,10 +69,32 @@
         assertEquals(expectedRequirePmf, params.isRequirePmf());
     }
 
+    /** Verify the security params created by security type. */
+    @Test
+    public void testSecurityTypeCreator() throws Exception {
+        int[] securityTypes = new int[] {
+                WifiConfiguration.SECURITY_TYPE_WAPI_CERT,
+                WifiConfiguration.SECURITY_TYPE_WAPI_PSK,
+                WifiConfiguration.SECURITY_TYPE_EAP_WPA3_ENTERPRISE_192_BIT,
+                WifiConfiguration.SECURITY_TYPE_OWE,
+                WifiConfiguration.SECURITY_TYPE_SAE,
+                WifiConfiguration.SECURITY_TYPE_OSEN,
+                WifiConfiguration.SECURITY_TYPE_EAP,
+                WifiConfiguration.SECURITY_TYPE_PSK,
+                WifiConfiguration.SECURITY_TYPE_OPEN,
+                WifiConfiguration.SECURITY_TYPE_PASSPOINT_R1_R2,
+                WifiConfiguration.SECURITY_TYPE_PASSPOINT_R3,
+        };
+
+        for (int type: securityTypes) {
+            assertEquals(type,
+                    SecurityParams.createSecurityParamsBySecurityType(type).getSecurityType());
+        }
+    }
+
     /** Verify EAP params creator. */
     @Test
     public void testEapCreator() throws Exception {
-        SecurityParams p = SecurityParams.createWpaWpa2EnterpriseParams();
         int expectedSecurityType = WifiConfiguration.SECURITY_TYPE_EAP;
         int[] expectedAllowedKeyManagement = new int[] {KeyMgmt.WPA_EAP, KeyMgmt.IEEE8021X};
         int[] expectedAllowedProtocols = new int[] {};
@@ -79,16 +102,17 @@
         int[] expectedAllowedPairwiseCiphers = new int[] {};
         int[] expectedAllowedGroupCiphers = new int[] {};
         boolean expectedRequirePmf = false;
+        SecurityParams p = SecurityParams.createSecurityParamsBySecurityType(
+                expectedSecurityType);
         verifySecurityParams(p, expectedSecurityType,
                 expectedAllowedKeyManagement, expectedAllowedProtocols,
                 expectedAllowedAuthAlgorithms, expectedAllowedPairwiseCiphers,
                 expectedAllowedGroupCiphers, expectedRequirePmf);
     }
 
-    /** Verify Passpoint R1 params creator. */
+    /** Verify Passpoint R1/R2 params creator. */
     @Test
-    public void testEapPasspointR1Creator() throws Exception {
-        SecurityParams p = SecurityParams.createPasspointParams(SecurityParams.PASSPOINT_R1);
+    public void testEapPasspointR1R2Creator() throws Exception {
         int expectedSecurityType = WifiConfiguration.SECURITY_TYPE_PASSPOINT_R1_R2;
         int[] expectedAllowedKeyManagement = new int[] {KeyMgmt.WPA_EAP, KeyMgmt.IEEE8021X};
         int[] expectedAllowedProtocols = new int[] {};
@@ -96,23 +120,8 @@
         int[] expectedAllowedPairwiseCiphers = new int[] {};
         int[] expectedAllowedGroupCiphers = new int[] {};
         boolean expectedRequirePmf = false;
-        verifySecurityParams(p, expectedSecurityType,
-                expectedAllowedKeyManagement, expectedAllowedProtocols,
-                expectedAllowedAuthAlgorithms, expectedAllowedPairwiseCiphers,
-                expectedAllowedGroupCiphers, expectedRequirePmf);
-    }
-
-    /** Verify Passpoint R2 params creator. */
-    @Test
-    public void testEapPasspointR2Creator() throws Exception {
-        SecurityParams p = SecurityParams.createPasspointParams(SecurityParams.PASSPOINT_R2);
-        int expectedSecurityType = WifiConfiguration.SECURITY_TYPE_PASSPOINT_R1_R2;
-        int[] expectedAllowedKeyManagement = new int[] {KeyMgmt.WPA_EAP, KeyMgmt.IEEE8021X};
-        int[] expectedAllowedProtocols = new int[] {};
-        int[] expectedAllowedAuthAlgorithms = new int[] {};
-        int[] expectedAllowedPairwiseCiphers = new int[] {};
-        int[] expectedAllowedGroupCiphers = new int[] {};
-        boolean expectedRequirePmf = false;
+        SecurityParams p = SecurityParams.createSecurityParamsBySecurityType(
+                expectedSecurityType);
         verifySecurityParams(p, expectedSecurityType,
                 expectedAllowedKeyManagement, expectedAllowedProtocols,
                 expectedAllowedAuthAlgorithms, expectedAllowedPairwiseCiphers,
@@ -122,7 +131,6 @@
     /** Verify Passpoint R3 params creator. */
     @Test
     public void testEapPasspointR3Creator() throws Exception {
-        SecurityParams p = SecurityParams.createPasspointParams(SecurityParams.PASSPOINT_R3);
         int expectedSecurityType = WifiConfiguration.SECURITY_TYPE_PASSPOINT_R3;
         int[] expectedAllowedKeyManagement = new int[] {KeyMgmt.WPA_EAP, KeyMgmt.IEEE8021X};
         int[] expectedAllowedProtocols = new int[] {};
@@ -130,6 +138,8 @@
         int[] expectedAllowedPairwiseCiphers = new int[] {};
         int[] expectedAllowedGroupCiphers = new int[] {};
         boolean expectedRequirePmf = true;
+        SecurityParams p = SecurityParams.createSecurityParamsBySecurityType(
+                expectedSecurityType);
         verifySecurityParams(p, expectedSecurityType,
                 expectedAllowedKeyManagement, expectedAllowedProtocols,
                 expectedAllowedAuthAlgorithms, expectedAllowedPairwiseCiphers,
@@ -139,7 +149,6 @@
     /** Verify Enhanced Open params creator. */
     @Test
     public void testEnhancedOpenCreator() throws Exception {
-        SecurityParams p = SecurityParams.createEnhancedOpenParams();
         int expectedSecurityType = WifiConfiguration.SECURITY_TYPE_OWE;
         int[] expectedAllowedKeyManagement = new int[] {KeyMgmt.OWE};
         int[] expectedAllowedProtocols = new int[] {Protocol.RSN};
@@ -149,6 +158,8 @@
         int[] expectedAllowedGroupCiphers = new int[] {
                 GroupCipher.CCMP, GroupCipher.GCMP_128, GroupCipher.GCMP_256};
         boolean expectedRequirePmf = true;
+        SecurityParams p = SecurityParams.createSecurityParamsBySecurityType(
+                expectedSecurityType);
         verifySecurityParams(p, expectedSecurityType,
                 expectedAllowedKeyManagement, expectedAllowedProtocols,
                 expectedAllowedAuthAlgorithms, expectedAllowedPairwiseCiphers,
@@ -158,7 +169,6 @@
     /** Verify Open params creator. */
     @Test
     public void testOpenCreator() throws Exception {
-        SecurityParams p = SecurityParams.createOpenParams();
         int expectedSecurityType = WifiConfiguration.SECURITY_TYPE_OPEN;
         int[] expectedAllowedKeyManagement = new int[] {KeyMgmt.NONE};
         int[] expectedAllowedProtocols = new int[] {};
@@ -166,6 +176,8 @@
         int[] expectedAllowedPairwiseCiphers = new int[] {};
         int[] expectedAllowedGroupCiphers = new int[] {};
         boolean expectedRequirePmf = false;
+        SecurityParams p = SecurityParams.createSecurityParamsBySecurityType(
+                                expectedSecurityType);
         verifySecurityParams(p, expectedSecurityType,
                 expectedAllowedKeyManagement, expectedAllowedProtocols,
                 expectedAllowedAuthAlgorithms, expectedAllowedPairwiseCiphers,
@@ -175,7 +187,6 @@
     /** Verify OSEN params creator. */
     @Test
     public void testOsenCreator() throws Exception {
-        SecurityParams p = SecurityParams.createOsenParams();
         int expectedSecurityType = WifiConfiguration.SECURITY_TYPE_OSEN;
         int[] expectedAllowedKeyManagement = new int[] {KeyMgmt.OSEN};
         int[] expectedAllowedProtocols = new int[] {Protocol.OSEN};
@@ -183,6 +194,8 @@
         int[] expectedAllowedPairwiseCiphers = new int[] {};
         int[] expectedAllowedGroupCiphers = new int[] {};
         boolean expectedRequirePmf = false;
+        SecurityParams p = SecurityParams.createSecurityParamsBySecurityType(
+                                expectedSecurityType);
         verifySecurityParams(p, expectedSecurityType,
                 expectedAllowedKeyManagement, expectedAllowedProtocols,
                 expectedAllowedAuthAlgorithms, expectedAllowedPairwiseCiphers,
@@ -192,7 +205,6 @@
     /** Verify WAPI CERT params creator. */
     @Test
     public void testWapiCertCreator() throws Exception {
-        SecurityParams p = SecurityParams.createWapiCertParams();
         int expectedSecurityType = WifiConfiguration.SECURITY_TYPE_WAPI_CERT;
         int[] expectedAllowedKeyManagement = new int[] {KeyMgmt.WAPI_CERT};
         int[] expectedAllowedProtocols = new int[] {Protocol.WAPI};
@@ -200,6 +212,8 @@
         int[] expectedAllowedPairwiseCiphers = new int[] {PairwiseCipher.SMS4};
         int[] expectedAllowedGroupCiphers = new int[] {GroupCipher.SMS4};
         boolean expectedRequirePmf = false;
+        SecurityParams p = SecurityParams.createSecurityParamsBySecurityType(
+                                expectedSecurityType);
         verifySecurityParams(p, expectedSecurityType,
                 expectedAllowedKeyManagement, expectedAllowedProtocols,
                 expectedAllowedAuthAlgorithms, expectedAllowedPairwiseCiphers,
@@ -209,7 +223,6 @@
     /** Verify WAPI PSK params creator. */
     @Test
     public void testWapiPskCreator() throws Exception {
-        SecurityParams p = SecurityParams.createWapiPskParams();
         int expectedSecurityType = WifiConfiguration.SECURITY_TYPE_WAPI_PSK;
         int[] expectedAllowedKeyManagement = new int[] {KeyMgmt.WAPI_PSK};
         int[] expectedAllowedProtocols = new int[] {Protocol.WAPI};
@@ -217,6 +230,8 @@
         int[] expectedAllowedPairwiseCiphers = new int[] {PairwiseCipher.SMS4};
         int[] expectedAllowedGroupCiphers = new int[] {GroupCipher.SMS4};
         boolean expectedRequirePmf = false;
+        SecurityParams p = SecurityParams.createSecurityParamsBySecurityType(
+                                expectedSecurityType);
         verifySecurityParams(p, expectedSecurityType,
                 expectedAllowedKeyManagement, expectedAllowedProtocols,
                 expectedAllowedAuthAlgorithms, expectedAllowedPairwiseCiphers,
@@ -226,7 +241,6 @@
     /** Verify WEP params creator. */
     @Test
     public void testWepCreator() throws Exception {
-        SecurityParams p = SecurityParams.createWepParams();
         int expectedSecurityType = WifiConfiguration.SECURITY_TYPE_WEP;
         int[] expectedAllowedKeyManagement = new int[] {KeyMgmt.NONE};
         int[] expectedAllowedProtocols = new int[] {};
@@ -234,6 +248,8 @@
         int[] expectedAllowedPairwiseCiphers = new int[] {};
         int[] expectedAllowedGroupCiphers = new int[] {};
         boolean expectedRequirePmf = false;
+        SecurityParams p = SecurityParams.createSecurityParamsBySecurityType(
+                                expectedSecurityType);
         verifySecurityParams(p, expectedSecurityType,
                 expectedAllowedKeyManagement, expectedAllowedProtocols,
                 expectedAllowedAuthAlgorithms, expectedAllowedPairwiseCiphers,
@@ -243,7 +259,6 @@
     /** Verify WPA3 Enterprise 192-bit params creator. */
     @Test
     public void testWpa3Enterprise192BitCreator() throws Exception {
-        SecurityParams p = SecurityParams.createWpa3Enterprise192BitParams();
         int expectedSecurityType = WifiConfiguration.SECURITY_TYPE_EAP_WPA3_ENTERPRISE_192_BIT;
         int[] expectedAllowedKeyManagement = new int[] {
                 KeyMgmt.WPA_EAP, KeyMgmt.IEEE8021X, KeyMgmt.SUITE_B_192};
@@ -253,6 +268,8 @@
                 PairwiseCipher.GCMP_128, PairwiseCipher.GCMP_256};
         int[] expectedAllowedGroupCiphers = new int[] {GroupCipher.GCMP_128, GroupCipher.GCMP_256};
         boolean expectedRequirePmf = true;
+        SecurityParams p = SecurityParams.createSecurityParamsBySecurityType(
+                                expectedSecurityType);
         verifySecurityParams(p, expectedSecurityType,
                 expectedAllowedKeyManagement, expectedAllowedProtocols,
                 expectedAllowedAuthAlgorithms, expectedAllowedPairwiseCiphers,
@@ -264,7 +281,6 @@
     /** Verify WPA3 Enterprise params creator. */
     @Test
     public void testWpa3EnterpriseCreator() throws Exception {
-        SecurityParams p = SecurityParams.createWpa3EnterpriseParams();
         int expectedSecurityType = WifiConfiguration.SECURITY_TYPE_EAP_WPA3_ENTERPRISE;
         int[] expectedAllowedKeyManagement = new int[] {KeyMgmt.WPA_EAP, KeyMgmt.IEEE8021X};
         int[] expectedAllowedProtocols = new int[] {Protocol.RSN};
@@ -273,6 +289,8 @@
                 PairwiseCipher.CCMP, PairwiseCipher.GCMP_256};
         int[] expectedAllowedGroupCiphers = new int[] {GroupCipher.CCMP, GroupCipher.GCMP_256};
         boolean expectedRequirePmf = true;
+        SecurityParams p = SecurityParams.createSecurityParamsBySecurityType(
+                                expectedSecurityType);
         verifySecurityParams(p, expectedSecurityType,
                 expectedAllowedKeyManagement, expectedAllowedProtocols,
                 expectedAllowedAuthAlgorithms, expectedAllowedPairwiseCiphers,
@@ -282,7 +300,6 @@
     /** Verify WPA3 Personal params creator. */
     @Test
     public void testWpa3PersonalCreator() throws Exception {
-        SecurityParams p = SecurityParams.createWpa3PersonalParams();
         int expectedSecurityType = WifiConfiguration.SECURITY_TYPE_SAE;
         int[] expectedAllowedKeyManagement = new int[] {KeyMgmt.SAE};
         int[] expectedAllowedProtocols = new int[] {Protocol.RSN};
@@ -292,6 +309,8 @@
         int[] expectedAllowedGroupCiphers = new int[] {
                 GroupCipher.CCMP, GroupCipher.GCMP_128, GroupCipher.GCMP_256};
         boolean expectedRequirePmf = true;
+        SecurityParams p = SecurityParams.createSecurityParamsBySecurityType(
+                                expectedSecurityType);
         verifySecurityParams(p, expectedSecurityType,
                 expectedAllowedKeyManagement, expectedAllowedProtocols,
                 expectedAllowedAuthAlgorithms, expectedAllowedPairwiseCiphers,
@@ -301,7 +320,6 @@
     /** Verify WPA2 Personal EAP params creator. */
     @Test
     public void testWpaWpa2PersonalCreator() throws Exception {
-        SecurityParams p = SecurityParams.createWpaWpa2PersonalParams();
         int expectedSecurityType = WifiConfiguration.SECURITY_TYPE_PSK;
         int[] expectedAllowedKeyManagement = new int[] {KeyMgmt.WPA_PSK};
         int[] expectedAllowedProtocols = new int[] {};
@@ -309,6 +327,8 @@
         int[] expectedAllowedPairwiseCiphers = new int[] {};
         int[] expectedAllowedGroupCiphers = new int[] {};
         boolean expectedRequirePmf = false;
+        SecurityParams p = SecurityParams.createSecurityParamsBySecurityType(
+                                expectedSecurityType);
         verifySecurityParams(p, expectedSecurityType,
                 expectedAllowedKeyManagement, expectedAllowedProtocols,
                 expectedAllowedAuthAlgorithms, expectedAllowedPairwiseCiphers,
@@ -318,7 +338,8 @@
     /** Verify setter/getter methods */
     @Test
     public void testCommonSetterGetter() throws Exception {
-        SecurityParams params = SecurityParams.createWpaWpa2PersonalParams();
+        SecurityParams params = SecurityParams.createSecurityParamsBySecurityType(
+                WifiConfiguration.SECURITY_TYPE_PSK);
 
         // PSK setting
         BitSet allowedKeyManagement = new BitSet();
@@ -362,7 +383,8 @@
     /** Verify SAE-specific methods */
     @Test
     public void testSaeMethods() throws Exception {
-        SecurityParams p = SecurityParams.createWpa3PersonalParams();
+        SecurityParams p = SecurityParams.createSecurityParamsBySecurityType(
+                WifiConfiguration.SECURITY_TYPE_SAE);
 
         assertFalse(p.isAddedByAutoUpgrade());
         p.setIsAddedByAutoUpgrade(true);
@@ -380,7 +402,8 @@
     /** Verify copy constructor. */
     @Test
     public void testCopyConstructor() throws Exception {
-        SecurityParams params = SecurityParams.createWpaWpa2PersonalParams();
+        SecurityParams params = SecurityParams.createSecurityParamsBySecurityType(
+                WifiConfiguration.SECURITY_TYPE_PSK);
         params.setEnabled(false);
         params.setIsAddedByAutoUpgrade(true);
 
@@ -405,9 +428,12 @@
     /** Check that two params are equal if and only if their types are the same. */
     @Test
     public void testEquals() {
-        SecurityParams saeParams1 = SecurityParams.createWpa3PersonalParams();
-        SecurityParams saeParams2 = SecurityParams.createWpa3PersonalParams();
-        SecurityParams pskParams = SecurityParams.createWpaWpa2PersonalParams();
+        SecurityParams saeParams1 = SecurityParams.createSecurityParamsBySecurityType(
+                WifiConfiguration.SECURITY_TYPE_SAE);
+        SecurityParams saeParams2 = SecurityParams.createSecurityParamsBySecurityType(
+                WifiConfiguration.SECURITY_TYPE_SAE);
+        SecurityParams pskParams = SecurityParams.createSecurityParamsBySecurityType(
+                WifiConfiguration.SECURITY_TYPE_PSK);
         assertEquals(saeParams1, saeParams2);
         assertNotEquals(saeParams1, pskParams);
     }
@@ -415,9 +441,12 @@
     /** Check that hash values are the same if and only if their types are the same. */
     @Test
     public void testHashCode() {
-        SecurityParams saeParams1 = SecurityParams.createWpa3PersonalParams();
-        SecurityParams saeParams2 = SecurityParams.createWpa3PersonalParams();
-        SecurityParams pskParams = SecurityParams.createWpaWpa2PersonalParams();
+        SecurityParams saeParams1 = SecurityParams.createSecurityParamsBySecurityType(
+                WifiConfiguration.SECURITY_TYPE_SAE);
+        SecurityParams saeParams2 = SecurityParams.createSecurityParamsBySecurityType(
+                WifiConfiguration.SECURITY_TYPE_SAE);
+        SecurityParams pskParams = SecurityParams.createSecurityParamsBySecurityType(
+                WifiConfiguration.SECURITY_TYPE_PSK);
         assertEquals(saeParams1.hashCode(), saeParams2.hashCode());
         assertNotEquals(saeParams1.hashCode(), pskParams.hashCode());
     }
@@ -426,26 +455,38 @@
     @Test
     public void testIsOpenNetwork() {
         SecurityParams[] openSecurityParams = new SecurityParams[] {
-                SecurityParams.createEnhancedOpenParams(),
-                SecurityParams.createOpenParams(),
+                SecurityParams.createSecurityParamsBySecurityType(
+                        WifiConfiguration.SECURITY_TYPE_OWE),
+                SecurityParams.createSecurityParamsBySecurityType(
+                        WifiConfiguration.SECURITY_TYPE_OPEN),
         };
         for (SecurityParams p: openSecurityParams) {
             assertTrue(p.isOpenSecurityType());
         }
 
         SecurityParams[] nonOpenSecurityParams = new SecurityParams[] {
-                SecurityParams.createWpaWpa2EnterpriseParams(),
-                SecurityParams.createPasspointParams(SecurityParams.PASSPOINT_R1),
-                SecurityParams.createPasspointParams(SecurityParams.PASSPOINT_R2),
-                SecurityParams.createPasspointParams(SecurityParams.PASSPOINT_R3),
-                SecurityParams.createOsenParams(),
-                SecurityParams.createWapiCertParams(),
-                SecurityParams.createWapiPskParams(),
-                SecurityParams.createWepParams(),
-                SecurityParams.createWpa3Enterprise192BitParams(),
-                SecurityParams.createWpa3EnterpriseParams(),
-                SecurityParams.createWpa3PersonalParams(),
-                SecurityParams.createWpaWpa2PersonalParams(),
+                SecurityParams.createSecurityParamsBySecurityType(
+                        WifiConfiguration.SECURITY_TYPE_EAP),
+                SecurityParams.createSecurityParamsBySecurityType(
+                        WifiConfiguration.SECURITY_TYPE_PASSPOINT_R1_R2),
+                SecurityParams.createSecurityParamsBySecurityType(
+                        WifiConfiguration.SECURITY_TYPE_PASSPOINT_R3),
+                SecurityParams.createSecurityParamsBySecurityType(
+                        WifiConfiguration.SECURITY_TYPE_OSEN),
+                SecurityParams.createSecurityParamsBySecurityType(
+                        WifiConfiguration.SECURITY_TYPE_WAPI_PSK),
+                SecurityParams.createSecurityParamsBySecurityType(
+                        WifiConfiguration.SECURITY_TYPE_WAPI_CERT),
+                SecurityParams.createSecurityParamsBySecurityType(
+                        WifiConfiguration.SECURITY_TYPE_WEP),
+                SecurityParams.createSecurityParamsBySecurityType(
+                        WifiConfiguration.SECURITY_TYPE_EAP_WPA3_ENTERPRISE_192_BIT),
+                SecurityParams.createSecurityParamsBySecurityType(
+                        WifiConfiguration.SECURITY_TYPE_EAP_WPA3_ENTERPRISE),
+                SecurityParams.createSecurityParamsBySecurityType(
+                        WifiConfiguration.SECURITY_TYPE_SAE),
+                SecurityParams.createSecurityParamsBySecurityType(
+                        WifiConfiguration.SECURITY_TYPE_PSK),
         };
         for (SecurityParams p: nonOpenSecurityParams) {
             assertFalse(p.isOpenSecurityType());
@@ -456,26 +497,38 @@
     @Test
     public void testIsEnterpriseNetwork() {
         SecurityParams[] enterpriseSecurityParams = new SecurityParams[] {
-                SecurityParams.createWpaWpa2EnterpriseParams(),
-                SecurityParams.createPasspointParams(SecurityParams.PASSPOINT_R1),
-                SecurityParams.createPasspointParams(SecurityParams.PASSPOINT_R2),
-                SecurityParams.createPasspointParams(SecurityParams.PASSPOINT_R3),
-                SecurityParams.createWapiCertParams(),
-                SecurityParams.createWpa3Enterprise192BitParams(),
-                SecurityParams.createWpa3EnterpriseParams(),
+                SecurityParams.createSecurityParamsBySecurityType(
+                        WifiConfiguration.SECURITY_TYPE_EAP),
+                SecurityParams.createSecurityParamsBySecurityType(
+                        WifiConfiguration.SECURITY_TYPE_PASSPOINT_R1_R2),
+                SecurityParams.createSecurityParamsBySecurityType(
+                        WifiConfiguration.SECURITY_TYPE_PASSPOINT_R3),
+                SecurityParams.createSecurityParamsBySecurityType(
+                        WifiConfiguration.SECURITY_TYPE_WAPI_CERT),
+                SecurityParams.createSecurityParamsBySecurityType(
+                        WifiConfiguration.SECURITY_TYPE_EAP_WPA3_ENTERPRISE_192_BIT),
+                SecurityParams.createSecurityParamsBySecurityType(
+                        WifiConfiguration.SECURITY_TYPE_EAP_WPA3_ENTERPRISE),
         };
         for (SecurityParams p: enterpriseSecurityParams) {
             assertTrue(p.isEnterpriseSecurityType());
         }
 
         SecurityParams[] nonEnterpriseSecurityParams = new SecurityParams[] {
-                SecurityParams.createEnhancedOpenParams(),
-                SecurityParams.createOpenParams(),
-                SecurityParams.createOsenParams(),
-                SecurityParams.createWapiPskParams(),
-                SecurityParams.createWepParams(),
-                SecurityParams.createWpa3PersonalParams(),
-                SecurityParams.createWpaWpa2PersonalParams(),
+                SecurityParams.createSecurityParamsBySecurityType(
+                        WifiConfiguration.SECURITY_TYPE_OWE),
+                SecurityParams.createSecurityParamsBySecurityType(
+                        WifiConfiguration.SECURITY_TYPE_OPEN),
+                SecurityParams.createSecurityParamsBySecurityType(
+                        WifiConfiguration.SECURITY_TYPE_OSEN),
+                SecurityParams.createSecurityParamsBySecurityType(
+                        WifiConfiguration.SECURITY_TYPE_WAPI_PSK),
+                SecurityParams.createSecurityParamsBySecurityType(
+                        WifiConfiguration.SECURITY_TYPE_WEP),
+                SecurityParams.createSecurityParamsBySecurityType(
+                        WifiConfiguration.SECURITY_TYPE_SAE),
+                SecurityParams.createSecurityParamsBySecurityType(
+                        WifiConfiguration.SECURITY_TYPE_PSK),
         };
         for (SecurityParams p: nonEnterpriseSecurityParams) {
             assertFalse(p.isEnterpriseSecurityType());
@@ -485,7 +538,8 @@
     /** Check that parcel marshalling/unmarshalling works */
     @Test
     public void testParcelMethods() {
-        SecurityParams params = SecurityParams.createWpa3PersonalParams();
+        SecurityParams params = SecurityParams.createSecurityParamsBySecurityType(
+                WifiConfiguration.SECURITY_TYPE_SAE);
 
         Parcel parcelW = Parcel.obtain();
         params.writeToParcel(parcelW, 0);
diff --git a/wifi/tests/src/android/net/wifi/WifiConfigurationTest.java b/wifi/tests/src/android/net/wifi/WifiConfigurationTest.java
index f351e61..bde44e7 100644
--- a/wifi/tests/src/android/net/wifi/WifiConfigurationTest.java
+++ b/wifi/tests/src/android/net/wifi/WifiConfigurationTest.java
@@ -22,6 +22,8 @@
 import static android.net.wifi.WifiConfiguration.SECURITY_TYPE_OPEN;
 import static android.net.wifi.WifiConfiguration.SECURITY_TYPE_OSEN;
 import static android.net.wifi.WifiConfiguration.SECURITY_TYPE_OWE;
+import static android.net.wifi.WifiConfiguration.SECURITY_TYPE_PASSPOINT_R1_R2;
+import static android.net.wifi.WifiConfiguration.SECURITY_TYPE_PASSPOINT_R3;
 import static android.net.wifi.WifiConfiguration.SECURITY_TYPE_PSK;
 import static android.net.wifi.WifiConfiguration.SECURITY_TYPE_SAE;
 import static android.net.wifi.WifiConfiguration.SECURITY_TYPE_WAPI_CERT;
@@ -51,6 +53,8 @@
 import org.junit.Before;
 import org.junit.Test;
 
+import java.util.ArrayList;
+import java.util.BitSet;
 import java.util.List;
 
 /**
@@ -915,7 +919,7 @@
         WifiConfiguration config = new WifiConfiguration();
         config.setSecurityParams(WifiConfiguration.SECURITY_TYPE_PSK);
         config.addSecurityParams(WifiConfiguration.SECURITY_TYPE_SAE);
-        config.addSecurityParams(SecurityParams.createWapiPskParams());
+        config.addSecurityParams(WifiConfiguration.SECURITY_TYPE_WAPI_PSK);
         List<SecurityParams> paramsList = config.getSecurityParamsList();
         assertEquals(3, paramsList.size());
 
@@ -1004,18 +1008,18 @@
     @Test (expected = IllegalArgumentException.class)
     public void testAddDuplicateSecurityParams() {
         WifiConfiguration config = new WifiConfiguration();
-        config.addSecurityParams(SecurityParams.createWpaWpa2PersonalParams());
-        config.addSecurityParams(SecurityParams.createWpaWpa2PersonalParams());
+        config.addSecurityParams(WifiConfiguration.SECURITY_TYPE_PSK);
+        config.addSecurityParams(WifiConfiguration.SECURITY_TYPE_PSK);
     }
 
     /** Verify that Suite-B type works as expected. */
     @Test
     public void testAddSuiteBSecurityType() {
         WifiConfiguration config = new WifiConfiguration();
-        config.addSecurityParams(SecurityParams.createWpa3EnterpriseParams());
+        config.addSecurityParams(WifiConfiguration.SECURITY_TYPE_EAP_WPA3_ENTERPRISE);
         config.enterpriseConfig.setEapMethod(WifiEnterpriseConfig.Eap.SIM);
         config.enterpriseConfig.setPhase2Method(WifiEnterpriseConfig.Phase2.NONE);
-        config.addSecurityParams(SecurityParams.createWpa3Enterprise192BitParams());
+        config.addSecurityParams(WifiConfiguration.SECURITY_TYPE_EAP_WPA3_ENTERPRISE_192_BIT);
 
         assertFalse(config.isSuiteBCipherEcdheRsaEnabled());
         config.enableSuiteBCiphers(false, true);
@@ -1101,22 +1105,96 @@
     /** Verify the set security params by SecurityParams objects. */
     @Test
     public void testSetBySecurityParamsObject() {
-        Pair[] securityParamsSecurityTypePairs = new Pair[] {
-                new Pair<>(SecurityParams.createWapiCertParams(), SECURITY_TYPE_WAPI_CERT),
-                new Pair<>(SecurityParams.createWapiPskParams(), SECURITY_TYPE_WAPI_PSK),
-                new Pair<>(SecurityParams.createWpa3Enterprise192BitParams(),
-                        SECURITY_TYPE_EAP_WPA3_ENTERPRISE_192_BIT),
-                new Pair<>(SecurityParams.createEnhancedOpenParams(), SECURITY_TYPE_OWE),
-                new Pair<>(SecurityParams.createWpa3PersonalParams(), SECURITY_TYPE_SAE),
-                new Pair<>(SecurityParams.createOsenParams(), SECURITY_TYPE_OSEN),
-                new Pair<>(SecurityParams.createWpaWpa2EnterpriseParams(), SECURITY_TYPE_EAP),
-                new Pair<>(SecurityParams.createWpaWpa2PersonalParams(), SECURITY_TYPE_PSK),
-                new Pair<>(SecurityParams.createOpenParams(), SECURITY_TYPE_OPEN),
+        int[] securityTypes = new int[] {
+                SECURITY_TYPE_WAPI_CERT,
+                SECURITY_TYPE_WAPI_PSK,
+                SECURITY_TYPE_EAP_WPA3_ENTERPRISE_192_BIT,
+                SECURITY_TYPE_OWE,
+                SECURITY_TYPE_SAE,
+                SECURITY_TYPE_OSEN,
+                SECURITY_TYPE_EAP,
+                SECURITY_TYPE_PSK,
+                SECURITY_TYPE_OPEN,
+                SECURITY_TYPE_PASSPOINT_R1_R2,
+                SECURITY_TYPE_PASSPOINT_R3,
         };
-        for (Pair pair: securityParamsSecurityTypePairs) {
+        for (int type: securityTypes) {
             WifiConfiguration config = new WifiConfiguration();
-            config.setSecurityParams((SecurityParams) pair.first);
+            config.setSecurityParams(type);
+            assertTrue(config.isSecurityType(type));
+            assertNotNull(config.getSecurityParams(type));
+        }
+    }
+
+    /** Verify the set security params by an allowed key management mask. */
+    @Test
+    public void testSetSecurityParamsByAllowedKeyManagement() {
+        Pair[] keyMgmtSecurityTypePairs = new Pair[] {
+                new Pair<>(KeyMgmt.WAPI_CERT, SECURITY_TYPE_WAPI_CERT),
+                new Pair<>(KeyMgmt.WAPI_PSK, SECURITY_TYPE_WAPI_PSK),
+                new Pair<>(KeyMgmt.SUITE_B_192, SECURITY_TYPE_EAP_WPA3_ENTERPRISE_192_BIT),
+                new Pair<>(KeyMgmt.OWE, SECURITY_TYPE_OWE),
+                new Pair<>(KeyMgmt.SAE, SECURITY_TYPE_SAE),
+                new Pair<>(KeyMgmt.OSEN, SECURITY_TYPE_OSEN),
+                new Pair<>(KeyMgmt.WPA2_PSK, SECURITY_TYPE_PSK),
+                new Pair<>(KeyMgmt.WPA_EAP, SECURITY_TYPE_EAP),
+                new Pair<>(KeyMgmt.WPA_PSK, SECURITY_TYPE_PSK),
+                new Pair<>(KeyMgmt.NONE, SECURITY_TYPE_OPEN),
+        };
+
+        for (Pair pair: keyMgmtSecurityTypePairs) {
+            BitSet akm = new BitSet();
+            akm.set((int) pair.first);
+            WifiConfiguration config = new WifiConfiguration();
+            config.setSecurityParams(akm);
             assertNotNull(config.getSecurityParams((int) pair.second));
         }
     }
+
+    /** Verify the set security params by an invalid allowed key management mask. */
+    @Test (expected = IllegalArgumentException.class)
+    public void testSetSecurityParamsByInvalidAllowedKeyManagement() {
+        WifiConfiguration config = new WifiConfiguration();
+        BitSet akm = null;
+        config.setSecurityParams(akm);
+    }
+
+    /** Verify the set security params by a security params list. */
+    @Test
+    public void testSetSecurityParamsBySecurityParamsList() {
+        WifiConfiguration config = new WifiConfiguration();
+        config.enterpriseConfig.setEapMethod(WifiEnterpriseConfig.Eap.SIM);
+        config.enterpriseConfig.setPhase2Method(WifiEnterpriseConfig.Phase2.NONE);
+        config.addSecurityParams(SECURITY_TYPE_EAP);
+        config.addSecurityParams(SECURITY_TYPE_EAP_WPA3_ENTERPRISE);
+        assertTrue(config.isSecurityType(SECURITY_TYPE_EAP));
+        assertTrue(config.isSecurityType(SECURITY_TYPE_EAP_WPA3_ENTERPRISE));
+        assertFalse(config.isSecurityType(SECURITY_TYPE_PSK));
+        assertFalse(config.isSecurityType(SECURITY_TYPE_SAE));
+
+        List<SecurityParams> list = new ArrayList<>();
+        list.add(SecurityParams.createSecurityParamsBySecurityType(SECURITY_TYPE_PSK));
+        list.add(SecurityParams.createSecurityParamsBySecurityType(SECURITY_TYPE_SAE));
+        config.setSecurityParams(list);
+        assertFalse(config.isSecurityType(SECURITY_TYPE_EAP));
+        assertFalse(config.isSecurityType(SECURITY_TYPE_EAP_WPA3_ENTERPRISE));
+        assertTrue(config.isSecurityType(SECURITY_TYPE_PSK));
+        assertTrue(config.isSecurityType(SECURITY_TYPE_SAE));
+    }
+
+    /** Verify the set security params by an empty security params list. */
+    @Test (expected = IllegalArgumentException.class)
+    public void testSetSecurityParamsByEmptySecurityParamsList() {
+        WifiConfiguration config = new WifiConfiguration();
+        List<SecurityParams> list = new ArrayList<>();
+        config.setSecurityParams(list);
+    }
+
+    /** Verify the set security params by a null security params list. */
+    @Test (expected = IllegalArgumentException.class)
+    public void testSetSecurityParamsByNullSecurityParamsList() {
+        WifiConfiguration config = new WifiConfiguration();
+        List<SecurityParams> list = null;
+        config.setSecurityParams(list);
+    }
 }