Merge "Revert "Checkbox for removing contributes files""
diff --git a/Android.bp b/Android.bp
index 4594425..035420f 100644
--- a/Android.bp
+++ b/Android.bp
@@ -384,6 +384,7 @@
         "core/java/android/view/IRecentsAnimationRunner.aidl",
         "core/java/android/view/IRemoteAnimationFinishedCallback.aidl",
         "core/java/android/view/IRotationWatcher.aidl",
+        "core/java/android/view/ISystemGestureExclusionListener.aidl",
         "core/java/android/view/IWallpaperVisibilityListener.aidl",
         "core/java/android/view/IWindow.aidl",
         "core/java/android/view/IWindowFocusObserver.aidl",
@@ -753,10 +754,6 @@
         "android.hardware.radio-V1.2-java",
         "android.hardware.radio-V1.3-java",
         "android.hardware.radio-V1.4-java",
-        "android.hardware.radio.config-V1.0-java",
-        "android.hardware.radio.config-V1.1-java",
-        "android.hardware.radio.config-V1.2-java",
-        "android.hardware.radio.deprecated-V1.0-java",
         "android.hardware.thermal-V1.0-java-constants",
         "android.hardware.thermal-V1.0-java",
         "android.hardware.thermal-V1.1-java",
@@ -771,8 +768,6 @@
         "android.hardware.vibrator-V1.2-java",
         "android.hardware.vibrator-V1.3-java",
         "android.hardware.wifi-V1.0-java-constants",
-        "networkstack-aidl-framework-java",
-        "netd_aidl_parcelables-java",
         "devicepolicyprotosnano",
     ],
 
@@ -912,6 +907,9 @@
         "core/java/android/net/dhcp/IDhcpServerCallbacks.aidl",
         "core/java/android/net/ip/IIpClient.aidl",
         "core/java/android/net/ip/IIpClientCallbacks.aidl",
+        "core/java/android/net/IIpMemoryStore.aidl",
+        "core/java/android/net/IIpMemoryStoreCallbacks.aidl",
+        "core/java/android/net/ipmemorystore/**/*.aidl",
     ],
     backend: {
         ndk: {
@@ -925,29 +923,49 @@
 }
 
 aidl_interface {
+    name: "ipmemorystore-aidl-interfaces",
+    local_include_dir: "core/java",
+    srcs: [
+        "core/java/android/net/IIpMemoryStore.aidl",
+        "core/java/android/net/IIpMemoryStoreCallbacks.aidl",
+        "core/java/android/net/ipmemorystore/**/*.aidl",
+    ],
+}
+
+aidl_interface {
     name: "networkstack-aidl-framework",
     local_include_dir: "core/java",
     srcs: [
         "core/java/android/net/TcpKeepalivePacketDataParcelable.aidl",
-        "core/java/android/net/IIpMemoryStore.aidl",
-        "core/java/android/net/ipmemorystore/**/*.aidl",
     ],
     api_dir: "aidl/networkstack",
+    backend: {
+        java: {
+            sdk_version: "28",
+        },
+    },
+}
+
+filegroup {
+    name: "framework-annotations",
+    srcs: [
+        "core/java/android/annotation/NonNull.java",
+        "core/java/android/annotation/Nullable.java",
+        "core/java/android/annotation/IntDef.java",
+        "core/java/android/annotation/IntRange.java",
+        "core/java/android/annotation/UnsupportedAppUsage.java",
+        "core/java/com/android/internal/annotations/GuardedBy.java",
+        "core/java/com/android/internal/annotations/VisibleForTesting.java",
+    ]
 }
 
 filegroup {
     name: "framework-networkstack-shared-srcs",
     srcs: [
         // TODO: remove these annotations as soon as we can use andoid.support.annotations.*
-        "core/java/android/annotation/NonNull.java",
-        "core/java/android/annotation/Nullable.java",
-        "core/java/android/annotation/IntDef.java",
-        "core/java/android/annotation/IntRange.java",
-        "core/java/android/annotation/UnsupportedAppUsage.java",
+        ":framework-annotations",
         "core/java/android/net/DhcpResults.java",
         "core/java/android/util/LocalLog.java",
-        "core/java/com/android/internal/annotations/GuardedBy.java",
-        "core/java/com/android/internal/annotations/VisibleForTesting.java",
         "core/java/com/android/internal/util/HexDump.java",
         "core/java/com/android/internal/util/IndentingPrintWriter.java",
         "core/java/com/android/internal/util/IState.java",
@@ -1667,6 +1685,7 @@
     srcs: [
         ":openjdk_java_files",
         ":non_openjdk_java_files",
+        ":opt-telephony-common-srcs",
     ],
     arg_files: [
         "core/res/AndroidManifest.xml",
@@ -1802,4 +1821,4 @@
     name: "framework-aidl-mappings",
     srcs: [":framework-defaults"],
     output: "framework-aidl-mappings.txt"
-}
\ No newline at end of file
+}
diff --git a/api/current.txt b/api/current.txt
index d1b77f2..8173339 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -5429,7 +5429,7 @@
     method @NonNull public android.app.Notification.Action.Builder addRemoteInput(android.app.RemoteInput);
     method @NonNull public android.app.Notification.Action build();
     method @NonNull public android.app.Notification.Action.Builder extend(android.app.Notification.Action.Extender);
-    method public android.os.Bundle getExtras();
+    method @NonNull public android.os.Bundle getExtras();
     method @NonNull public android.app.Notification.Action.Builder setAllowGeneratedReplies(boolean);
     method @NonNull public android.app.Notification.Action.Builder setContextual(boolean);
     method @NonNull public android.app.Notification.Action.Builder setSemanticAction(int);
@@ -6623,7 +6623,7 @@
     method @Nullable public String[] getAccountTypesWithManagementDisabled();
     method @Nullable public java.util.List<android.content.ComponentName> getActiveAdmins();
     method @NonNull public java.util.Set<java.lang.String> getAffiliationIds(@NonNull android.content.ComponentName);
-    method @Nullable public java.util.List<java.lang.String> getAlwaysOnVpnLockdownWhitelist(@NonNull android.content.ComponentName);
+    method @Nullable public java.util.Set<java.lang.String> getAlwaysOnVpnLockdownWhitelist(@NonNull android.content.ComponentName);
     method @Nullable public String getAlwaysOnVpnPackage(@NonNull android.content.ComponentName);
     method @WorkerThread @NonNull public android.os.Bundle getApplicationRestrictions(@Nullable android.content.ComponentName, String);
     method @Deprecated @Nullable public String getApplicationRestrictionsManagingPackage(@NonNull android.content.ComponentName);
@@ -6736,7 +6736,7 @@
     method public void setAccountManagementDisabled(@NonNull android.content.ComponentName, String, boolean);
     method public void setAffiliationIds(@NonNull android.content.ComponentName, @NonNull java.util.Set<java.lang.String>);
     method public void setAlwaysOnVpnPackage(@NonNull android.content.ComponentName, @Nullable String, boolean) throws android.content.pm.PackageManager.NameNotFoundException;
-    method public void setAlwaysOnVpnPackage(@NonNull android.content.ComponentName, @Nullable String, boolean, @Nullable java.util.List<java.lang.String>) throws android.content.pm.PackageManager.NameNotFoundException;
+    method public void setAlwaysOnVpnPackage(@NonNull android.content.ComponentName, @Nullable String, boolean, @Nullable java.util.Set<java.lang.String>) throws android.content.pm.PackageManager.NameNotFoundException;
     method public boolean setApplicationHidden(@NonNull android.content.ComponentName, String, boolean);
     method @WorkerThread public void setApplicationRestrictions(@Nullable android.content.ComponentName, String, android.os.Bundle);
     method @Deprecated public void setApplicationRestrictionsManagingPackage(@NonNull android.content.ComponentName, @Nullable String) throws android.content.pm.PackageManager.NameNotFoundException;
@@ -11051,6 +11051,7 @@
     method public void dump(android.util.Printer, String);
     method public static CharSequence getCategoryTitle(android.content.Context, int);
     method public boolean isProfileableByShell();
+    method public boolean isResourceOverlay();
     method public boolean isVirtualPreload();
     method public CharSequence loadDescription(android.content.pm.PackageManager);
     field public static final int CATEGORY_AUDIO = 1; // 0x1
@@ -11597,6 +11598,7 @@
     method public abstract android.content.pm.ServiceInfo getServiceInfo(android.content.ComponentName, int) throws android.content.pm.PackageManager.NameNotFoundException;
     method @NonNull public abstract java.util.List<android.content.pm.SharedLibraryInfo> getSharedLibraries(int);
     method @Nullable public android.os.Bundle getSuspendedPackageAppExtras();
+    method public boolean getSyntheticAppDetailsActivityEnabled(@NonNull String);
     method public abstract android.content.pm.FeatureInfo[] getSystemAvailableFeatures();
     method public abstract String[] getSystemSharedLibraryNames();
     method public abstract CharSequence getText(String, @StringRes int, android.content.pm.ApplicationInfo);
@@ -11676,7 +11678,6 @@
     field public static final String FEATURE_FAKETOUCH_MULTITOUCH_DISTINCT = "android.hardware.faketouch.multitouch.distinct";
     field public static final String FEATURE_FAKETOUCH_MULTITOUCH_JAZZHAND = "android.hardware.faketouch.multitouch.jazzhand";
     field public static final String FEATURE_FINGERPRINT = "android.hardware.fingerprint";
-    field public static final String FEATURE_FOLDABLE = "android.hardware.type.foldable";
     field public static final String FEATURE_FREEFORM_WINDOW_MANAGEMENT = "android.software.freeform_window_management";
     field public static final String FEATURE_GAMEPAD = "android.hardware.gamepad";
     field public static final String FEATURE_HIFI_SENSORS = "android.hardware.sensor.hifi_sensors";
@@ -12016,7 +12017,7 @@
     method @NonNull public android.content.pm.ShortcutInfo.Builder setIntents(@NonNull android.content.Intent[]);
     method @NonNull public android.content.pm.ShortcutInfo.Builder setLocusId(@NonNull android.content.LocusId);
     method @NonNull public android.content.pm.ShortcutInfo.Builder setLongLabel(@NonNull CharSequence);
-    method @NonNull public android.content.pm.ShortcutInfo.Builder setLongLived();
+    method @NonNull public android.content.pm.ShortcutInfo.Builder setLongLived(boolean);
     method @NonNull public android.content.pm.ShortcutInfo.Builder setPerson(@NonNull android.app.Person);
     method @NonNull public android.content.pm.ShortcutInfo.Builder setPersons(@NonNull android.app.Person[]);
     method @NonNull public android.content.pm.ShortcutInfo.Builder setRank(int);
@@ -15953,7 +15954,6 @@
   public class MeasuredText {
     method public void getBounds(@IntRange(from=0) int, @IntRange(from=0) int, @NonNull android.graphics.Rect);
     method @FloatRange(from=0.0f) @Px public float getCharWidthAt(@IntRange(from=0) int);
-    method @NonNull public char[] getChars();
     method @FloatRange(from=0.0) @Px public float getWidth(@IntRange(from=0) int, @IntRange(from=0) int);
   }
 
@@ -17367,15 +17367,16 @@
     method @Nullable public java.util.Set<android.util.Size> getInputSizes(int);
     method @NonNull public java.util.Set<java.lang.Integer> getOutputFormats();
     method @IntRange(from=0) public long getOutputMinFrameDuration(int, @NonNull android.util.Size);
-    method public <T> long getOutputMinFrameDuration(@NonNull Class<T>, @NonNull android.util.Size);
+    method @IntRange(from=0) public <T> long getOutputMinFrameDuration(@NonNull Class<T>, @NonNull android.util.Size);
     method @Nullable public java.util.Set<android.util.Size> getOutputSizes(int);
-    method public <T> java.util.Set<android.util.Size> getOutputSizes(@NonNull Class<T>);
+    method @Nullable public <T> java.util.Set<android.util.Size> getOutputSizes(@NonNull Class<T>);
     method @IntRange(from=0) public long getOutputStallDuration(int, @NonNull android.util.Size);
-    method public <T> long getOutputStallDuration(@NonNull Class<T>, @NonNull android.util.Size);
+    method @IntRange(from=0) public <T> long getOutputStallDuration(@NonNull Class<T>, @NonNull android.util.Size);
     method public int getRecommendedUseCase();
     method @Nullable public java.util.Set<java.lang.Integer> getValidOutputFormatsForInput(int);
     method public boolean isOutputSupportedFor(int);
     method public boolean isOutputSupportedFor(@NonNull android.view.Surface);
+    field public static final int USECASE_LOW_LATENCY_SNAPSHOT = 6; // 0x6
     field public static final int USECASE_PREVIEW = 0; // 0x0
     field public static final int USECASE_RAW = 5; // 0x5
     field public static final int USECASE_RECORD = 1; // 0x1
@@ -22810,6 +22811,7 @@
     field public static final int CONSTELLATION_GALILEO = 6; // 0x6
     field public static final int CONSTELLATION_GLONASS = 3; // 0x3
     field public static final int CONSTELLATION_GPS = 1; // 0x1
+    field public static final int CONSTELLATION_IRNSS = 7; // 0x7
     field public static final int CONSTELLATION_QZSS = 4; // 0x4
     field public static final int CONSTELLATION_SBAS = 2; // 0x2
     field public static final int CONSTELLATION_UNKNOWN = 0; // 0x0
@@ -22966,6 +22968,7 @@
     method public void unregisterGnssMeasurementsCallback(@NonNull android.location.GnssMeasurementsEvent.Callback);
     method public void unregisterGnssNavigationMessageCallback(@NonNull android.location.GnssNavigationMessage.Callback);
     method public void unregisterGnssStatusCallback(@NonNull android.location.GnssStatus.Callback);
+    field public static final String EXTRA_PROVIDER_NAME = "android.location.extra.PROVIDER_NAME";
     field public static final String GPS_PROVIDER = "gps";
     field public static final String KEY_LOCATION_CHANGED = "location";
     field public static final String KEY_PROVIDER_ENABLED = "providerEnabled";
@@ -23293,6 +23296,7 @@
     field public static final String ACTION_MICROPHONE_MUTE_CHANGED = "android.media.action.MICROPHONE_MUTE_CHANGED";
     field @Deprecated public static final String ACTION_SCO_AUDIO_STATE_CHANGED = "android.media.SCO_AUDIO_STATE_CHANGED";
     field public static final String ACTION_SCO_AUDIO_STATE_UPDATED = "android.media.ACTION_SCO_AUDIO_STATE_UPDATED";
+    field public static final String ACTION_SPEAKERPHONE_STATE_CHANGED = "android.media.action.SPEAKERPHONE_STATE_CHANGED";
     field public static final int ADJUST_LOWER = -1; // 0xffffffff
     field public static final int ADJUST_MUTE = -100; // 0xffffff9c
     field public static final int ADJUST_RAISE = 1; // 0x1
@@ -23398,15 +23402,16 @@
   }
 
   public final class AudioPlaybackCaptureConfiguration {
+    method @NonNull public android.media.projection.MediaProjection getMediaProjection();
   }
 
   public static final class AudioPlaybackCaptureConfiguration.Builder {
     ctor public AudioPlaybackCaptureConfiguration.Builder(@NonNull android.media.projection.MediaProjection);
     method @NonNull public android.media.AudioPlaybackCaptureConfiguration.Builder addMatchingUid(int);
-    method @NonNull public android.media.AudioPlaybackCaptureConfiguration.Builder addMatchingUsage(@NonNull android.media.AudioAttributes);
+    method @NonNull public android.media.AudioPlaybackCaptureConfiguration.Builder addMatchingUsage(int);
     method @NonNull public android.media.AudioPlaybackCaptureConfiguration build();
     method @NonNull public android.media.AudioPlaybackCaptureConfiguration.Builder excludeUid(int);
-    method @NonNull public android.media.AudioPlaybackCaptureConfiguration.Builder excludeUsage(@NonNull android.media.AudioAttributes);
+    method @NonNull public android.media.AudioPlaybackCaptureConfiguration.Builder excludeUsage(int);
   }
 
   public final class AudioPlaybackConfiguration implements android.os.Parcelable {
@@ -23703,17 +23708,6 @@
     method public void onTearDown(@NonNull android.media.AudioTrack);
   }
 
-  public class CallbackDataSourceDesc extends android.media.DataSourceDesc {
-    method @NonNull public android.media.DataSourceCallback getDataSourceCallback();
-  }
-
-  public static class CallbackDataSourceDesc.Builder extends android.media.DataSourceDesc.BuilderBase<android.media.CallbackDataSourceDesc.Builder> {
-    ctor public CallbackDataSourceDesc.Builder();
-    ctor public CallbackDataSourceDesc.Builder(@Nullable android.media.CallbackDataSourceDesc);
-    method @NonNull public android.media.CallbackDataSourceDesc build();
-    method @NonNull public android.media.CallbackDataSourceDesc.Builder setDataSource(@NonNull android.media.DataSourceCallback);
-  }
-
   public class CamcorderProfile {
     method public static android.media.CamcorderProfile get(int);
     method public static android.media.CamcorderProfile get(int, int);
@@ -23780,10 +23774,18 @@
     field public static final long POSITION_UNKNOWN = 576460752303423L; // 0x20c49ba5e353fL
   }
 
-  protected static class DataSourceDesc.BuilderBase<T extends android.media.DataSourceDesc.BuilderBase> {
-    method @NonNull public T setEndPosition(long);
-    method @NonNull public T setMediaId(@Nullable String);
-    method @NonNull public T setStartPosition(long);
+  public static final class DataSourceDesc.Builder {
+    ctor public DataSourceDesc.Builder();
+    ctor public DataSourceDesc.Builder(@Nullable android.media.DataSourceDesc);
+    method @NonNull public android.media.DataSourceDesc build();
+    method @NonNull public android.media.DataSourceDesc.Builder setDataSource(@NonNull android.net.Uri);
+    method @NonNull public android.media.DataSourceDesc.Builder setDataSource(@NonNull android.net.Uri, @Nullable java.util.Map<java.lang.String,java.lang.String>, @Nullable java.util.List<java.net.HttpCookie>);
+    method @NonNull public android.media.DataSourceDesc.Builder setDataSource(@NonNull android.os.ParcelFileDescriptor);
+    method @NonNull public android.media.DataSourceDesc.Builder setDataSource(@NonNull android.os.ParcelFileDescriptor, long, long);
+    method @NonNull public android.media.DataSourceDesc.Builder setDataSource(@NonNull android.media.DataSourceCallback);
+    method @NonNull public android.media.DataSourceDesc.Builder setEndPosition(long);
+    method @NonNull public android.media.DataSourceDesc.Builder setMediaId(@Nullable String);
+    method @NonNull public android.media.DataSourceDesc.Builder setStartPosition(long);
   }
 
   public final class DeniedByServerException extends android.media.MediaDrmException {
@@ -23988,21 +23990,6 @@
     field public static final int EULER_Z = 2; // 0x2
   }
 
-  public class FileDataSourceDesc extends android.media.DataSourceDesc {
-    method public long getLength();
-    method public long getOffset();
-    method @NonNull public android.os.ParcelFileDescriptor getParcelFileDescriptor();
-    field public static final long FD_LENGTH_UNKNOWN = 576460752303423487L; // 0x7ffffffffffffffL
-  }
-
-  public static class FileDataSourceDesc.Builder extends android.media.DataSourceDesc.BuilderBase<android.media.FileDataSourceDesc.Builder> {
-    ctor public FileDataSourceDesc.Builder();
-    ctor public FileDataSourceDesc.Builder(@Nullable android.media.FileDataSourceDesc);
-    method @NonNull public android.media.FileDataSourceDesc build();
-    method @NonNull public android.media.FileDataSourceDesc.Builder setDataSource(@NonNull android.os.ParcelFileDescriptor);
-    method @NonNull public android.media.FileDataSourceDesc.Builder setDataSource(@NonNull android.os.ParcelFileDescriptor, long, long);
-  }
-
   public abstract class Image implements java.lang.AutoCloseable {
     method public abstract void close();
     method public android.graphics.Rect getCropRect();
@@ -24423,9 +24410,10 @@
     field public static final int AV1Level71 = 2097152; // 0x200000
     field public static final int AV1Level72 = 4194304; // 0x400000
     field public static final int AV1Level73 = 8388608; // 0x800000
-    field public static final int AV1Profile0 = 1; // 0x1
-    field public static final int AV1Profile1 = 2; // 0x2
-    field public static final int AV1Profile2 = 4; // 0x4
+    field public static final int AV1ProfileMain10 = 2; // 0x2
+    field public static final int AV1ProfileMain10HDR10 = 4096; // 0x1000
+    field public static final int AV1ProfileMain10HDR10Plus = 8192; // 0x2000
+    field public static final int AV1ProfileMain8 = 1; // 0x1
     field public static final int AVCLevel1 = 1; // 0x1
     field public static final int AVCLevel11 = 4; // 0x4
     field public static final int AVCLevel12 = 8; // 0x8
@@ -24619,42 +24607,39 @@
     ctor public MediaCodecInfo.VideoCapabilities.PerformancePoint(int, int, int);
     method public boolean covers(@NonNull android.media.MediaFormat);
     method public boolean covers(@NonNull android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint);
-    field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint FHD_100;
-    field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint FHD_120;
-    field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint FHD_200;
-    field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint FHD_24;
-    field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint FHD_240;
-    field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint FHD_25;
-    field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint FHD_30;
-    field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint FHD_50;
-    field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint FHD_60;
-    field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint HD_100;
-    field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint HD_120;
-    field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint HD_200;
-    field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint HD_24;
-    field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint HD_240;
-    field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint HD_25;
-    field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint HD_30;
-    field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint HD_50;
-    field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint HD_60;
-    field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint SD_24;
-    field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint SD_25;
-    field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint SD_30;
-    field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint SD_48;
-    field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint SD_50;
-    field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint SD_60;
-    field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint UHD_100;
-    field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint UHD_120;
-    field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint UHD_200;
-    field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint UHD_24;
-    field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint UHD_240;
-    field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint UHD_25;
-    field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint UHD_30;
-    field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint UHD_50;
-    field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint UHD_60;
-    field public final int frameRate;
-    field public final long macroBlockRate;
-    field public final int macroBlocks;
+    field @NonNull public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint FHD_100;
+    field @NonNull public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint FHD_120;
+    field @NonNull public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint FHD_200;
+    field @NonNull public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint FHD_24;
+    field @NonNull public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint FHD_240;
+    field @NonNull public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint FHD_25;
+    field @NonNull public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint FHD_30;
+    field @NonNull public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint FHD_50;
+    field @NonNull public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint FHD_60;
+    field @NonNull public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint HD_100;
+    field @NonNull public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint HD_120;
+    field @NonNull public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint HD_200;
+    field @NonNull public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint HD_24;
+    field @NonNull public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint HD_240;
+    field @NonNull public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint HD_25;
+    field @NonNull public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint HD_30;
+    field @NonNull public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint HD_50;
+    field @NonNull public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint HD_60;
+    field @NonNull public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint SD_24;
+    field @NonNull public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint SD_25;
+    field @NonNull public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint SD_30;
+    field @NonNull public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint SD_48;
+    field @NonNull public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint SD_50;
+    field @NonNull public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint SD_60;
+    field @NonNull public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint UHD_100;
+    field @NonNull public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint UHD_120;
+    field @NonNull public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint UHD_200;
+    field @NonNull public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint UHD_24;
+    field @NonNull public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint UHD_240;
+    field @NonNull public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint UHD_25;
+    field @NonNull public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint UHD_30;
+    field @NonNull public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint UHD_50;
+    field @NonNull public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint UHD_60;
   }
 
   public final class MediaCodecList {
@@ -25069,6 +25054,7 @@
     field public static final String KEY_FRAME_RATE = "frame-rate";
     field public static final String KEY_GRID_COLUMNS = "grid-cols";
     field public static final String KEY_GRID_ROWS = "grid-rows";
+    field public static final String KEY_HAPTIC_CHANNEL_COUNT = "haptic-channel-count";
     field public static final String KEY_HDR10_PLUS_INFO = "hdr10-plus-info";
     field public static final String KEY_HDR_STATIC_INFO = "hdr-static-info";
     field public static final String KEY_HEIGHT = "height";
@@ -25081,6 +25067,7 @@
     field public static final String KEY_LANGUAGE = "language";
     field public static final String KEY_LATENCY = "latency";
     field public static final String KEY_LEVEL = "level";
+    field public static final String KEY_MAX_BFRAMES = "max-bframes";
     field public static final String KEY_MAX_FPS_TO_ENCODER = "max-fps-to-encoder";
     field public static final String KEY_MAX_HEIGHT = "max-height";
     field public static final String KEY_MAX_INPUT_SIZE = "max-input-size";
@@ -25090,6 +25077,7 @@
     field public static final String KEY_OPERATING_RATE = "operating-rate";
     field public static final String KEY_OUTPUT_REORDER_DEPTH = "output-reorder-depth";
     field public static final String KEY_PCM_ENCODING = "pcm-encoding";
+    field public static final String KEY_PREPEND_HEADER_TO_SYNC_FRAMES = "prepend-sps-pps-to-idr-frames";
     field public static final String KEY_PRIORITY = "priority";
     field public static final String KEY_PROFILE = "profile";
     field public static final String KEY_PUSH_BLANK_BUFFERS_ON_STOP = "push-blank-buffers-on-shutdown";
@@ -25697,14 +25685,14 @@
   public static class MediaPlayer2.DrmEventCallback {
     ctor public MediaPlayer2.DrmEventCallback();
     method public void onDrmConfig(@NonNull android.media.MediaPlayer2, @NonNull android.media.DataSourceDesc, @NonNull android.media.MediaDrm);
-    method public android.media.MediaPlayer2.DrmPreparationInfo onDrmInfo(android.media.MediaPlayer2, android.media.DataSourceDesc, android.media.MediaPlayer2.DrmInfo);
-    method public byte[] onDrmKeyRequest(@NonNull android.media.MediaPlayer2, @NonNull android.media.DataSourceDesc, @NonNull android.media.MediaDrm.KeyRequest);
+    method @Nullable public android.media.MediaPlayer2.DrmPreparationInfo onDrmInfo(@NonNull android.media.MediaPlayer2, @NonNull android.media.DataSourceDesc, @NonNull android.media.MediaPlayer2.DrmInfo);
+    method @NonNull public byte[] onDrmKeyRequest(@NonNull android.media.MediaPlayer2, @NonNull android.media.DataSourceDesc, @NonNull android.media.MediaDrm.KeyRequest);
     method public void onDrmPrepared(@NonNull android.media.MediaPlayer2, @NonNull android.media.DataSourceDesc, int, @Nullable byte[]);
   }
 
   public static final class MediaPlayer2.DrmInfo {
-    method public java.util.Map<java.util.UUID,byte[]> getPssh();
-    method public java.util.List<java.util.UUID> getSupportedSchemes();
+    method @NonNull public java.util.Map<java.util.UUID,byte[]> getPssh();
+    method @NonNull public java.util.List<java.util.UUID> getSupportedSchemes();
   }
 
   public static final class MediaPlayer2.DrmPreparationInfo {
@@ -25712,13 +25700,13 @@
 
   public static final class MediaPlayer2.DrmPreparationInfo.Builder {
     ctor public MediaPlayer2.DrmPreparationInfo.Builder();
-    method public android.media.MediaPlayer2.DrmPreparationInfo build();
-    method public android.media.MediaPlayer2.DrmPreparationInfo.Builder setInitData(@Nullable byte[]);
-    method public android.media.MediaPlayer2.DrmPreparationInfo.Builder setKeySetId(@Nullable byte[]);
-    method public android.media.MediaPlayer2.DrmPreparationInfo.Builder setKeyType(int);
-    method public android.media.MediaPlayer2.DrmPreparationInfo.Builder setMimeType(@Nullable String);
-    method public android.media.MediaPlayer2.DrmPreparationInfo.Builder setOptionalParameters(@Nullable java.util.Map<java.lang.String,java.lang.String>);
-    method public android.media.MediaPlayer2.DrmPreparationInfo.Builder setUuid(@NonNull java.util.UUID);
+    method @NonNull public android.media.MediaPlayer2.DrmPreparationInfo build();
+    method @NonNull public android.media.MediaPlayer2.DrmPreparationInfo.Builder setInitData(@Nullable byte[]);
+    method @NonNull public android.media.MediaPlayer2.DrmPreparationInfo.Builder setKeySetId(@Nullable byte[]);
+    method @NonNull public android.media.MediaPlayer2.DrmPreparationInfo.Builder setKeyType(int);
+    method @NonNull public android.media.MediaPlayer2.DrmPreparationInfo.Builder setMimeType(@Nullable String);
+    method @NonNull public android.media.MediaPlayer2.DrmPreparationInfo.Builder setOptionalParameters(@Nullable java.util.Map<java.lang.String,java.lang.String>);
+    method @NonNull public android.media.MediaPlayer2.DrmPreparationInfo.Builder setUuid(@NonNull java.util.UUID);
   }
 
   public static class MediaPlayer2.EventCallback {
@@ -25749,7 +25737,7 @@
   }
 
   public static final class MediaPlayer2.NoDrmSchemeException extends android.media.MediaDrmException {
-    ctor public MediaPlayer2.NoDrmSchemeException(String);
+    ctor public MediaPlayer2.NoDrmSchemeException(@Nullable String);
   }
 
   public static class MediaPlayer2.TrackInfo {
@@ -26139,10 +26127,11 @@
   }
 
   public final class MediaTimestamp {
+    ctor public MediaTimestamp(long, long, @FloatRange(from=0.0f, to=java.lang.Float.MAX_VALUE) float);
     method public long getAnchorMediaTimeUs();
     method public long getAnchorSystemNanoTime();
     method @Deprecated public long getAnchorSytemNanoTime();
-    method public float getMediaClockRate();
+    method @FloatRange(from=0.0f, to=java.lang.Float.MAX_VALUE) public float getMediaClockRate();
     field public static final android.media.MediaTimestamp TIMESTAMP_UNKNOWN;
   }
 
@@ -26356,6 +26345,8 @@
     method public android.net.Uri getRingtoneUri(int);
     method public boolean getStopPreviousRingtone();
     method public static android.net.Uri getValidRingtoneUri(android.content.Context);
+    method public boolean hasHapticChannels(int);
+    method public static boolean hasHapticChannels(@NonNull android.net.Uri);
     method public int inferStreamType();
     method public static boolean isDefault(android.net.Uri);
     method @Nullable public static android.content.res.AssetFileDescriptor openDefaultRingtoneUri(@NonNull android.content.Context, @NonNull android.net.Uri) throws java.io.FileNotFoundException;
@@ -26416,10 +26407,8 @@
     ctor public Session2CommandGroup.Builder();
     ctor public Session2CommandGroup.Builder(@NonNull android.media.Session2CommandGroup);
     method @NonNull public android.media.Session2CommandGroup.Builder addCommand(@NonNull android.media.Session2Command);
-    method @NonNull public android.media.Session2CommandGroup.Builder addCommand(int);
     method @NonNull public android.media.Session2CommandGroup build();
     method @NonNull public android.media.Session2CommandGroup.Builder removeCommand(@NonNull android.media.Session2Command);
-    method @NonNull public android.media.Session2CommandGroup.Builder removeCommand(int);
   }
 
   public final class Session2Token implements android.os.Parcelable {
@@ -26470,6 +26459,7 @@
   }
 
   public final class SubtitleData {
+    ctor public SubtitleData(int, long, long, @NonNull byte[]);
     method @NonNull public byte[] getData();
     method public long getDurationUs();
     method public long getStartTimeUs();
@@ -26510,6 +26500,7 @@
   }
 
   public final class TimedMetaData {
+    ctor public TimedMetaData(long, @NonNull byte[]);
     method public byte[] getMetaData();
     method public long getTimestamp();
   }
@@ -26634,21 +26625,6 @@
     ctor public UnsupportedSchemeException(String);
   }
 
-  public class UriDataSourceDesc extends android.media.DataSourceDesc {
-    method @NonNull public android.content.Context getContext();
-    method @Nullable public java.util.List<java.net.HttpCookie> getCookies();
-    method @Nullable public java.util.Map<java.lang.String,java.lang.String> getHeaders();
-    method @NonNull public android.net.Uri getUri();
-  }
-
-  public static class UriDataSourceDesc.Builder extends android.media.DataSourceDesc.BuilderBase<android.media.UriDataSourceDesc.Builder> {
-    ctor public UriDataSourceDesc.Builder();
-    ctor public UriDataSourceDesc.Builder(@Nullable android.media.UriDataSourceDesc);
-    method @NonNull public android.media.UriDataSourceDesc build();
-    method @NonNull public android.media.UriDataSourceDesc.Builder setDataSource(@NonNull android.content.Context, @NonNull android.net.Uri);
-    method @NonNull public android.media.UriDataSourceDesc.Builder setDataSource(@NonNull android.content.Context, @NonNull android.net.Uri, @Nullable java.util.Map<java.lang.String,java.lang.String>, @Nullable java.util.List<java.net.HttpCookie>);
-  }
-
   public interface VolumeAutomation {
     method @NonNull public android.media.VolumeShaper createVolumeShaper(@NonNull android.media.VolumeShaper.Configuration);
   }
@@ -28756,10 +28732,9 @@
   }
 
   public final class DnsResolver {
-    method public static android.net.DnsResolver getInstance();
-    method public void query(@Nullable android.net.Network, @NonNull byte[], int, @NonNull android.os.Handler, @NonNull android.net.DnsResolver.RawAnswerListener) throws android.system.ErrnoException;
-    method public void query(@Nullable android.net.Network, @NonNull String, int, int, int, @NonNull android.os.Handler, @NonNull android.net.DnsResolver.RawAnswerListener) throws android.system.ErrnoException;
-    method public void query(@Nullable android.net.Network, @NonNull String, int, @NonNull android.os.Handler, @NonNull android.net.DnsResolver.InetAddressAnswerListener) throws android.system.ErrnoException;
+    method @NonNull public static android.net.DnsResolver getInstance();
+    method public <T> void query(@Nullable android.net.Network, @NonNull byte[], int, @NonNull java.util.concurrent.Executor, @NonNull android.net.DnsResolver.AnswerCallback<T>);
+    method public <T> void query(@Nullable android.net.Network, @NonNull String, int, int, int, @NonNull java.util.concurrent.Executor, @NonNull android.net.DnsResolver.AnswerCallback<T>);
     field public static final int CLASS_IN = 1; // 0x1
     field public static final int FLAG_EMPTY = 0; // 0x0
     field public static final int FLAG_NO_CACHE_LOOKUP = 4; // 0x4
@@ -28769,12 +28744,23 @@
     field public static final int TYPE_AAAA = 28; // 0x1c
   }
 
-  public static interface DnsResolver.InetAddressAnswerListener {
-    method public void onAnswer(@NonNull java.util.List<java.net.InetAddress>);
+  public abstract static class DnsResolver.AnswerCallback<T> {
+    ctor public DnsResolver.AnswerCallback(@NonNull android.net.DnsResolver.AnswerParser<T>);
+    method public abstract void onAnswer(@NonNull T);
+    method public abstract void onParseException(@NonNull android.net.ParseException);
+    method public abstract void onQueryException(@NonNull android.system.ErrnoException);
   }
 
-  public static interface DnsResolver.RawAnswerListener {
-    method public void onAnswer(@Nullable byte[]);
+  public static interface DnsResolver.AnswerParser<T> {
+    method @NonNull public T parse(@NonNull byte[]) throws android.net.ParseException;
+  }
+
+  public abstract static class DnsResolver.InetAddressAnswerCallback extends android.net.DnsResolver.AnswerCallback<java.util.List<java.net.InetAddress>> {
+    ctor public DnsResolver.InetAddressAnswerCallback();
+  }
+
+  public abstract static class DnsResolver.RawAnswerCallback extends android.net.DnsResolver.AnswerCallback<byte[]> {
+    ctor public DnsResolver.RawAnswerCallback();
   }
 
   public class InetAddresses {
@@ -28867,16 +28853,25 @@
   }
 
   public final class LinkProperties implements android.os.Parcelable {
+    ctor public LinkProperties();
+    method public boolean addRoute(@NonNull android.net.RouteInfo);
+    method public void clear();
     method public int describeContents();
-    method public java.util.List<java.net.InetAddress> getDnsServers();
-    method public String getDomains();
-    method public android.net.ProxyInfo getHttpProxy();
+    method @NonNull public java.util.List<java.net.InetAddress> getDnsServers();
+    method @Nullable public String getDomains();
+    method @Nullable public android.net.ProxyInfo getHttpProxy();
     method @Nullable public String getInterfaceName();
-    method public java.util.List<android.net.LinkAddress> getLinkAddresses();
+    method @NonNull public java.util.List<android.net.LinkAddress> getLinkAddresses();
     method public int getMtu();
     method @Nullable public String getPrivateDnsServerName();
-    method public java.util.List<android.net.RouteInfo> getRoutes();
+    method @NonNull public java.util.List<android.net.RouteInfo> getRoutes();
     method public boolean isPrivateDnsActive();
+    method public void setDnsServers(@NonNull java.util.Collection<java.net.InetAddress>);
+    method public void setDomains(@Nullable String);
+    method public void setHttpProxy(@Nullable android.net.ProxyInfo);
+    method public void setInterfaceName(@Nullable String);
+    method public void setLinkAddresses(@NonNull java.util.Collection<android.net.LinkAddress>);
+    method public void setMtu(int);
     method public void writeToParcel(android.os.Parcel, int);
     field @NonNull public static final android.os.Parcelable.Creator<android.net.LinkProperties> CREATOR;
   }
@@ -28984,6 +28979,7 @@
     method public int describeContents();
     method public int getLinkDownstreamBandwidthKbps();
     method public int getLinkUpstreamBandwidthKbps();
+    method public int getSignalStrength();
     method @Nullable public android.net.TransportInfo getTransportInfo();
     method public boolean hasCapability(int);
     method public boolean hasTransport(int);
@@ -29012,6 +29008,7 @@
     field public static final int NET_CAPABILITY_VALIDATED = 16; // 0x10
     field public static final int NET_CAPABILITY_WIFI_P2P = 6; // 0x6
     field public static final int NET_CAPABILITY_XCAP = 9; // 0x9
+    field public static final int SIGNAL_STRENGTH_UNSPECIFIED = -2147483648; // 0x80000000
     field public static final int TRANSPORT_BLUETOOTH = 2; // 0x2
     field public static final int TRANSPORT_CELLULAR = 0; // 0x0
     field public static final int TRANSPORT_ETHERNET = 3; // 0x3
@@ -29023,7 +29020,7 @@
 
   @Deprecated public class NetworkInfo implements android.os.Parcelable {
     method @Deprecated public int describeContents();
-    method @Deprecated public android.net.NetworkInfo.DetailedState getDetailedState();
+    method @Deprecated @NonNull public android.net.NetworkInfo.DetailedState getDetailedState();
     method @Deprecated public String getExtraInfo();
     method @Deprecated public String getReason();
     method @Deprecated public android.net.NetworkInfo.State getState();
@@ -29089,6 +29086,8 @@
   }
 
   public class ParseException extends java.lang.RuntimeException {
+    ctor public ParseException(@NonNull String);
+    ctor public ParseException(@NonNull String, @NonNull Throwable);
     field public String response;
   }
 
@@ -30303,13 +30302,11 @@
   }
 
   public static final class WifiAwareNetworkSpecifier.Builder {
-    ctor public WifiAwareNetworkSpecifier.Builder();
+    ctor public WifiAwareNetworkSpecifier.Builder(@NonNull android.net.wifi.aware.DiscoverySession, @NonNull android.net.wifi.aware.PeerHandle);
     method @NonNull public android.net.wifi.aware.WifiAwareNetworkSpecifier build();
-    method @NonNull public android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder setDiscoverySession(@NonNull android.net.wifi.aware.DiscoverySession);
-    method @NonNull public android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder setPeerHandle(@NonNull android.net.wifi.aware.PeerHandle);
-    method @NonNull public android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder setPort(int);
+    method @NonNull public android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder setPort(@IntRange(from=0, to=65535) int);
     method @NonNull public android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder setPskPassphrase(@NonNull String);
-    method @NonNull public android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder setTransportProtocol(int);
+    method @NonNull public android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder setTransportProtocol(@IntRange(from=0, to=255) int);
   }
 
   public class WifiAwareSession implements java.lang.AutoCloseable {
@@ -35419,6 +35416,7 @@
   }
 
   public final class SystemClock {
+    method @NonNull public static java.time.Clock currentGnssTimeClock();
     method public static long currentThreadTimeMillis();
     method public static long elapsedRealtime();
     method public static long elapsedRealtimeNanos();
@@ -39006,10 +39004,12 @@
     method public static long getLong(android.content.ContentResolver, String) throws android.provider.Settings.SettingNotFoundException;
     method public static String getString(android.content.ContentResolver, String);
     method public static android.net.Uri getUriFor(String);
+    method @Deprecated public static boolean isLocationProviderEnabled(android.content.ContentResolver, String);
     method public static boolean putFloat(android.content.ContentResolver, String, float);
     method public static boolean putInt(android.content.ContentResolver, String, int);
     method public static boolean putLong(android.content.ContentResolver, String, long);
     method public static boolean putString(android.content.ContentResolver, String, String);
+    method @Deprecated public static void setLocationProviderEnabled(android.content.ContentResolver, String, boolean);
     field public static final String ACCESSIBILITY_DISPLAY_INVERSION_ENABLED = "accessibility_display_inversion_enabled";
     field public static final String ACCESSIBILITY_ENABLED = "accessibility_enabled";
     field @Deprecated public static final String ACCESSIBILITY_SPEAK_PASSWORD = "speak_password";
@@ -42483,12 +42483,12 @@
     method public static java.io.FileDescriptor accept(java.io.FileDescriptor, java.net.InetSocketAddress) throws android.system.ErrnoException, java.net.SocketException;
     method public static boolean access(String, int) throws android.system.ErrnoException;
     method public static void bind(java.io.FileDescriptor, java.net.InetAddress, int) throws android.system.ErrnoException, java.net.SocketException;
-    method public static void bind(java.io.FileDescriptor, java.net.SocketAddress) throws android.system.ErrnoException, java.net.SocketException;
+    method public static void bind(@NonNull java.io.FileDescriptor, @NonNull java.net.SocketAddress) throws android.system.ErrnoException, java.net.SocketException;
     method public static void chmod(String, int) throws android.system.ErrnoException;
     method public static void chown(String, int, int) throws android.system.ErrnoException;
     method public static void close(java.io.FileDescriptor) throws android.system.ErrnoException;
     method public static void connect(java.io.FileDescriptor, java.net.InetAddress, int) throws android.system.ErrnoException, java.net.SocketException;
-    method public static void connect(java.io.FileDescriptor, java.net.SocketAddress) throws android.system.ErrnoException, java.net.SocketException;
+    method public static void connect(@NonNull java.io.FileDescriptor, @NonNull java.net.SocketAddress) throws android.system.ErrnoException, java.net.SocketException;
     method public static java.io.FileDescriptor dup(java.io.FileDescriptor) throws android.system.ErrnoException;
     method public static java.io.FileDescriptor dup2(java.io.FileDescriptor, int) throws android.system.ErrnoException;
     method public static String[] environ();
@@ -42553,7 +42553,7 @@
     method public static long sendfile(java.io.FileDescriptor, java.io.FileDescriptor, android.system.Int64Ref, long) throws android.system.ErrnoException;
     method public static int sendto(java.io.FileDescriptor, java.nio.ByteBuffer, int, java.net.InetAddress, int) throws android.system.ErrnoException, java.net.SocketException;
     method public static int sendto(java.io.FileDescriptor, byte[], int, int, int, java.net.InetAddress, int) throws android.system.ErrnoException, java.net.SocketException;
-    method public static int sendto(java.io.FileDescriptor, byte[], int, int, int, java.net.SocketAddress) throws android.system.ErrnoException, java.net.SocketException;
+    method public static int sendto(@NonNull java.io.FileDescriptor, @NonNull byte[], int, int, int, @Nullable java.net.SocketAddress) throws android.system.ErrnoException, java.net.SocketException;
     method @Deprecated public static void setegid(int) throws android.system.ErrnoException;
     method public static void setenv(String, String, boolean) throws android.system.ErrnoException;
     method @Deprecated public static void seteuid(int) throws android.system.ErrnoException;
@@ -43189,6 +43189,7 @@
     method public void unregisterCallback(android.telecom.Call.Callback);
     field @Deprecated public static final String AVAILABLE_PHONE_ACCOUNTS = "selectPhoneAccountAccounts";
     field public static final String EXTRA_LAST_EMERGENCY_CALLBACK_TIME_MILLIS = "android.telecom.extra.LAST_EMERGENCY_CALLBACK_TIME_MILLIS";
+    field public static final String EXTRA_SILENT_RINGING_REQUESTED = "android.telecom.extra.SILENT_RINGING_REQUESTED";
     field public static final String EXTRA_SUGGESTED_PHONE_ACCOUNTS = "android.telecom.extra.SUGGESTED_PHONE_ACCOUNTS";
     field public static final int STATE_ACTIVE = 4; // 0x4
     field public static final int STATE_CONNECTING = 9; // 0x9
@@ -43376,6 +43377,7 @@
   public static class CallScreeningService.CallResponse {
     method public boolean getDisallowCall();
     method public boolean getRejectCall();
+    method public boolean getSilenceCall();
     method public boolean getSkipCallLog();
     method public boolean getSkipNotification();
   }
@@ -43385,6 +43387,7 @@
     method public android.telecom.CallScreeningService.CallResponse build();
     method public android.telecom.CallScreeningService.CallResponse.Builder setDisallowCall(boolean);
     method public android.telecom.CallScreeningService.CallResponse.Builder setRejectCall(boolean);
+    method @NonNull public android.telecom.CallScreeningService.CallResponse.Builder setSilenceCall(boolean);
     method public android.telecom.CallScreeningService.CallResponse.Builder setSkipCallLog(boolean);
     method public android.telecom.CallScreeningService.CallResponse.Builder setSkipNotification(boolean);
   }
@@ -44490,6 +44493,13 @@
     field @NonNull public static final android.os.Parcelable.Creator<android.telephony.CellInfoNr> CREATOR;
   }
 
+  public final class CellInfoTdscdma extends android.telephony.CellInfo implements android.os.Parcelable {
+    method @NonNull public android.telephony.CellIdentityTdscdma getCellIdentity();
+    method @NonNull public android.telephony.CellSignalStrengthTdscdma getCellSignalStrength();
+    method public void writeToParcel(android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.telephony.CellInfoTdscdma> CREATOR;
+  }
+
   public final class CellInfoWcdma extends android.telephony.CellInfo implements android.os.Parcelable {
     method public android.telephony.CellIdentityWcdma getCellIdentity();
     method public android.telephony.CellSignalStrengthWcdma getCellSignalStrength();
@@ -44573,6 +44583,16 @@
     field @NonNull public static final android.os.Parcelable.Creator<android.telephony.CellSignalStrengthNr> CREATOR;
   }
 
+  public final class CellSignalStrengthTdscdma extends android.telephony.CellSignalStrength implements android.os.Parcelable {
+    method public int describeContents();
+    method public int getAsuLevel();
+    method public int getDbm();
+    method public int getLevel();
+    method public int getRscp();
+    method public void writeToParcel(android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.telephony.CellSignalStrengthTdscdma> CREATOR;
+  }
+
   public final class CellSignalStrengthWcdma extends android.telephony.CellSignalStrength implements android.os.Parcelable {
     method public int describeContents();
     method public int getAsuLevel();
@@ -45043,7 +45063,6 @@
     method public void removeOnOpportunisticSubscriptionsChangedListener(@NonNull android.telephony.SubscriptionManager.OnOpportunisticSubscriptionsChangedListener);
     method public void removeOnSubscriptionsChangedListener(android.telephony.SubscriptionManager.OnSubscriptionsChangedListener);
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean removeSubscriptionsFromGroup(@NonNull int[]);
-    method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean setMetered(boolean, int);
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean setOpportunistic(boolean, int);
     method @Nullable @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public String setSubscriptionGroup(@NonNull int[]);
     method public void setSubscriptionOverrideCongested(int, boolean, long);
@@ -45177,7 +45196,7 @@
     method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_NETWORK_STATE, android.Manifest.permission.READ_PHONE_STATE}) public boolean isDataRoamingEnabled();
     method public boolean isEmergencyNumber(@NonNull String);
     method public boolean isHearingAidCompatibilitySupported();
-    method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public boolean isMultisimSupported();
+    method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public int isMultiSimSupported();
     method public boolean isNetworkRoaming();
     method public boolean isRttSupported();
     method public boolean isSmsCapable();
@@ -45242,7 +45261,7 @@
     field public static final String EXTRA_CARRIER_ID = "android.telephony.extra.CARRIER_ID";
     field public static final String EXTRA_CARRIER_NAME = "android.telephony.extra.CARRIER_NAME";
     field public static final String EXTRA_HIDE_PUBLIC_SETTINGS = "android.telephony.extra.HIDE_PUBLIC_SETTINGS";
-    field public static final String EXTRA_INCOMING_NUMBER = "incoming_number";
+    field @Deprecated public static final String EXTRA_INCOMING_NUMBER = "incoming_number";
     field public static final String EXTRA_IS_REFRESH = "android.telephony.extra.IS_REFRESH";
     field public static final String EXTRA_LAUNCH_VOICEMAIL_SETTINGS_INTENT = "android.telephony.extra.LAUNCH_VOICEMAIL_SETTINGS_INTENT";
     field public static final String EXTRA_NETWORK_COUNTRY = "android.telephony.extra.NETWORK_COUNTRY";
@@ -45257,6 +45276,9 @@
     field public static final String EXTRA_SUBSCRIPTION_ID = "android.telephony.extra.SUBSCRIPTION_ID";
     field public static final String EXTRA_VOICEMAIL_NUMBER = "android.telephony.extra.VOICEMAIL_NUMBER";
     field public static final String METADATA_HIDE_VOICEMAIL_SETTINGS_MENU = "android.telephony.HIDE_VOICEMAIL_SETTINGS_MENU";
+    field public static final int MULTISIM_ALLOWED = 0; // 0x0
+    field public static final int MULTISIM_NOT_SUPPORTED_BY_CARRIER = 2; // 0x2
+    field public static final int MULTISIM_NOT_SUPPORTED_BY_HARDWARE = 1; // 0x1
     field public static final int NETWORK_TYPE_1xRTT = 7; // 0x7
     field public static final int NETWORK_TYPE_CDMA = 4; // 0x4
     field public static final int NETWORK_TYPE_EDGE = 2; // 0x2
@@ -45281,7 +45303,7 @@
     field public static final int PHONE_TYPE_GSM = 1; // 0x1
     field public static final int PHONE_TYPE_NONE = 0; // 0x0
     field public static final int PHONE_TYPE_SIP = 3; // 0x3
-    field public static final int SET_OPPORTUNISTIC_SUB_INVALID_PARAMETER = 2; // 0x2
+    field public static final int SET_OPPORTUNISTIC_SUB_INACTIVE_SUBSCRIPTION = 2; // 0x2
     field public static final int SET_OPPORTUNISTIC_SUB_SUCCESS = 0; // 0x0
     field public static final int SET_OPPORTUNISTIC_SUB_VALIDATION_FAILED = 1; // 0x1
     field public static final int SIM_STATE_ABSENT = 1; // 0x1
@@ -50425,6 +50447,7 @@
     method protected float getLeftFadingEdgeStrength();
     method protected int getLeftPaddingOffset();
     method public final boolean getLocalVisibleRect(android.graphics.Rect);
+    method public void getLocationInSurface(@NonNull @Size(2) int[]);
     method public void getLocationInWindow(@Size(2) int[]);
     method public void getLocationOnScreen(@Size(2) int[]);
     method public android.graphics.Matrix getMatrix();
@@ -51938,6 +51961,7 @@
     method @NonNull public android.view.WindowInsets consumeStableInsets();
     method @NonNull public android.view.WindowInsets consumeSystemWindowInsets();
     method @Nullable public android.view.DisplayCutout getDisplayCutout();
+    method @NonNull public android.graphics.Insets getMandatorySystemGestureInsets();
     method public int getStableInsetBottom();
     method public int getStableInsetLeft();
     method public int getStableInsetRight();
@@ -51949,6 +51973,7 @@
     method public int getSystemWindowInsetRight();
     method public int getSystemWindowInsetTop();
     method @NonNull public android.graphics.Insets getSystemWindowInsets();
+    method @NonNull public android.graphics.Insets getTappableElementInsets();
     method public boolean hasInsets();
     method public boolean hasStableInsets();
     method public boolean hasSystemWindowInsets();
@@ -51964,9 +51989,11 @@
     ctor public WindowInsets.Builder(@NonNull android.view.WindowInsets);
     method @NonNull public android.view.WindowInsets build();
     method @NonNull public android.view.WindowInsets.Builder setDisplayCutout(@Nullable android.view.DisplayCutout);
+    method @NonNull public android.view.WindowInsets.Builder setMandatorySystemGestureInsets(@NonNull android.graphics.Insets);
     method @NonNull public android.view.WindowInsets.Builder setStableInsets(@NonNull android.graphics.Insets);
     method @NonNull public android.view.WindowInsets.Builder setSystemGestureInsets(@NonNull android.graphics.Insets);
     method @NonNull public android.view.WindowInsets.Builder setSystemWindowInsets(@NonNull android.graphics.Insets);
+    method @NonNull public android.view.WindowInsets.Builder setTappableElementInsets(@NonNull android.graphics.Insets);
   }
 
   public interface WindowManager extends android.view.ViewManager {
@@ -53011,7 +53038,7 @@
     method public int describeContents();
     method @NonNull public static android.view.contentcapture.ContentCaptureContext forLocusId(@NonNull String);
     method @Nullable public android.os.Bundle getExtras();
-    method @NonNull public android.content.LocusId getLocusId();
+    method @Nullable public android.content.LocusId getLocusId();
     method public void writeToParcel(android.os.Parcel, int);
     field @NonNull public static final android.os.Parcelable.Creator<android.view.contentcapture.ContentCaptureContext> CREATOR;
   }
@@ -53478,7 +53505,6 @@
 package android.view.inspector {
 
   public interface InspectionCompanion<T> {
-    method @Nullable public default String getNodeName();
     method public void mapProperties(@NonNull android.view.inspector.PropertyMapper);
     method public void readProperties(@NonNull T, @NonNull android.view.inspector.PropertyReader);
   }
diff --git a/api/removed.txt b/api/removed.txt
index 5108dd0..fa07094 100644
--- a/api/removed.txt
+++ b/api/removed.txt
@@ -314,17 +314,11 @@
 package android.net {
 
   public class ConnectivityManager {
-    method @Deprecated public void getLatestTetheringEntitlementValue(int, boolean, @NonNull android.net.ConnectivityManager.TetheringEntitlementValueListener, @Nullable android.os.Handler);
     method @Deprecated public boolean requestRouteToHost(int, int);
     method @Deprecated public int startUsingNetworkFeature(int, String);
     method @Deprecated public int stopUsingNetworkFeature(int, String);
   }
 
-  @Deprecated public abstract static class ConnectivityManager.TetheringEntitlementValueListener {
-    ctor public ConnectivityManager.TetheringEntitlementValueListener();
-    method public void onEntitlementResult(int);
-  }
-
   @Deprecated public class NetworkBadging {
     method @NonNull public static android.graphics.drawable.Drawable getWifiIcon(@IntRange(from=0, to=4) int, int, @Nullable android.content.res.Resources.Theme);
     field public static final int BADGING_4K = 30; // 0x1e
@@ -553,11 +547,6 @@
     field @Deprecated public static final String CONTACT_METADATA_SYNC = "contact_metadata_sync";
   }
 
-  public static final class Settings.Secure extends android.provider.Settings.NameValueTable {
-    method @Deprecated public static boolean isLocationProviderEnabled(android.content.ContentResolver, String);
-    method @Deprecated public static void setLocationProviderEnabled(android.content.ContentResolver, String, boolean);
-  }
-
   public static final class Settings.System extends android.provider.Settings.NameValueTable {
     field public static final String APPEND_FOR_LAST_AUDIBLE = "_last_audible";
     field public static final String VOLUME_ALARM = "volume_alarm";
diff --git a/api/system-current.txt b/api/system-current.txt
index 2724133..dd5c9c9 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -186,6 +186,7 @@
     field public static final String SUBSTITUTE_NOTIFICATION_APP_NAME = "android.permission.SUBSTITUTE_NOTIFICATION_APP_NAME";
     field public static final String SUBSTITUTE_SHARE_TARGET_APP_NAME_AND_ICON = "android.permission.SUBSTITUTE_SHARE_TARGET_APP_NAME_AND_ICON";
     field public static final String SUSPEND_APPS = "android.permission.SUSPEND_APPS";
+    field public static final String TEST_MANAGE_ROLLBACKS = "android.permission.TEST_MANAGE_ROLLBACKS";
     field public static final String TETHER_PRIVILEGED = "android.permission.TETHER_PRIVILEGED";
     field public static final String TV_INPUT_HARDWARE = "android.permission.TV_INPUT_HARDWARE";
     field public static final String TV_VIRTUAL_REMOTE_CONTROLLER = "android.permission.TV_VIRTUAL_REMOTE_CONTROLLER";
@@ -338,6 +339,7 @@
     field public static final String OPSTR_GET_ACCOUNTS = "android:get_accounts";
     field public static final String OPSTR_GPS = "android:gps";
     field public static final String OPSTR_INSTANT_APP_START_FOREGROUND = "android:instant_app_start_foreground";
+    field public static final String OPSTR_LEGACY_STORAGE = "android:legacy_storage";
     field public static final String OPSTR_MANAGE_IPSEC_TUNNELS = "android:manage_ipsec_tunnels";
     field public static final String OPSTR_MUTE_MICROPHONE = "android:mute_microphone";
     field public static final String OPSTR_NEIGHBORING_CELLS = "android:neighboring_cells";
@@ -545,6 +547,7 @@
   }
 
   public class NotificationManager {
+    method @NonNull public java.util.List<java.lang.String> getAllowedAssistantCapabilities();
     method @Nullable public android.content.ComponentName getAllowedNotificationAssistant();
     method public boolean isNotificationAssistantAccessGranted(@NonNull android.content.ComponentName);
     method public void setNotificationAssistantAccessGranted(@Nullable android.content.ComponentName, boolean);
@@ -665,7 +668,6 @@
     method @Nullable @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public java.util.List<java.lang.String> getPermittedAccessibilityServices(int);
     method @Nullable @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public java.util.List<java.lang.String> getPermittedInputMethodsForCurrentUser();
     method @Nullable public android.content.ComponentName getProfileOwner() throws java.lang.IllegalArgumentException;
-    method @Nullable @RequiresPermission(value=android.Manifest.permission.INTERACT_ACROSS_USERS, conditional=true) public android.content.ComponentName getProfileOwnerAsUser(@NonNull android.os.UserHandle);
     method @Nullable @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public String getProfileOwnerNameAsUser(int) throws java.lang.IllegalArgumentException;
     method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public int getUserProvisioningState();
     method public boolean isDeviceManaged();
@@ -743,7 +745,8 @@
     method @RequiresPermission(android.Manifest.permission.BACKUP) public String getCurrentTransport();
     method @Nullable @RequiresPermission(android.Manifest.permission.BACKUP) public android.content.ComponentName getCurrentTransportComponent();
     method @RequiresPermission(android.Manifest.permission.BACKUP) public android.content.Intent getDataManagementIntent(String);
-    method @RequiresPermission(android.Manifest.permission.BACKUP) public String getDataManagementLabel(String);
+    method @Nullable @RequiresPermission(android.Manifest.permission.BACKUP) public CharSequence getDataManagementIntentLabel(@NonNull String);
+    method @Deprecated @Nullable @RequiresPermission(android.Manifest.permission.BACKUP) public String getDataManagementLabel(@NonNull String);
     method @RequiresPermission(android.Manifest.permission.BACKUP) public String getDestinationString(String);
     method @RequiresPermission(android.Manifest.permission.BACKUP) public boolean isAppEligibleForBackup(String);
     method @RequiresPermission(android.Manifest.permission.BACKUP) public boolean isBackupEnabled();
@@ -757,7 +760,8 @@
     method @RequiresPermission(android.Manifest.permission.BACKUP) public void setAncestralSerialNumber(long);
     method @RequiresPermission(android.Manifest.permission.BACKUP) public void setAutoRestore(boolean);
     method @RequiresPermission(android.Manifest.permission.BACKUP) public void setBackupEnabled(boolean);
-    method @RequiresPermission(android.Manifest.permission.BACKUP) public void updateTransportAttributes(android.content.ComponentName, String, @Nullable android.content.Intent, String, @Nullable android.content.Intent, @Nullable String);
+    method @Deprecated @RequiresPermission(android.Manifest.permission.BACKUP) public void updateTransportAttributes(@NonNull android.content.ComponentName, @NonNull String, @Nullable android.content.Intent, @NonNull String, @Nullable android.content.Intent, @Nullable String);
+    method @RequiresPermission(android.Manifest.permission.BACKUP) public void updateTransportAttributes(@NonNull android.content.ComponentName, @NonNull String, @Nullable android.content.Intent, @NonNull String, @Nullable android.content.Intent, @Nullable CharSequence);
     field public static final int ERROR_AGENT_FAILURE = -1003; // 0xfffffc15
     field public static final int ERROR_BACKUP_CANCELLED = -2003; // 0xfffff82d
     field public static final int ERROR_BACKUP_NOT_ALLOWED = -2001; // 0xfffff82f
@@ -862,7 +866,8 @@
     method public android.content.Intent configurationIntent();
     method public String currentDestinationString();
     method public android.content.Intent dataManagementIntent();
-    method public String dataManagementLabel();
+    method @Nullable public CharSequence dataManagementIntentLabel();
+    method @Deprecated @Nullable public String dataManagementLabel();
     method public int finishBackup();
     method public void finishRestore();
     method public android.app.backup.RestoreSet[] getAvailableRestoreSets();
@@ -1425,8 +1430,9 @@
     field public static final String ACTION_RESOLVE_INSTANT_APP_PACKAGE = "android.intent.action.RESOLVE_INSTANT_APP_PACKAGE";
     field @RequiresPermission(android.Manifest.permission.REVIEW_ACCESSIBILITY_SERVICES) public static final String ACTION_REVIEW_ACCESSIBILITY_SERVICES = "android.intent.action.REVIEW_ACCESSIBILITY_SERVICES";
     field @RequiresPermission(android.Manifest.permission.GRANT_RUNTIME_PERMISSIONS) public static final String ACTION_REVIEW_APP_PERMISSION_USAGE = "android.intent.action.REVIEW_APP_PERMISSION_USAGE";
+    field @RequiresPermission(android.Manifest.permission.GRANT_RUNTIME_PERMISSIONS) public static final String ACTION_REVIEW_ONGOING_PERMISSION_USAGE = "android.intent.action.REVIEW_ONGOING_PERMISSION_USAGE";
     field public static final String ACTION_REVIEW_PERMISSIONS = "android.intent.action.REVIEW_PERMISSIONS";
-    field public static final String ACTION_REVIEW_PERMISSION_USAGE = "android.intent.action.REVIEW_PERMISSION_USAGE";
+    field @RequiresPermission(android.Manifest.permission.GRANT_RUNTIME_PERMISSIONS) public static final String ACTION_REVIEW_PERMISSION_USAGE = "android.intent.action.REVIEW_PERMISSION_USAGE";
     field public static final String ACTION_ROLLBACK_COMMITTED = "android.intent.action.ROLLBACK_COMMITTED";
     field public static final String ACTION_SHOW_SUSPENDED_APP_DETAILS = "android.intent.action.SHOW_SUSPENDED_APP_DETAILS";
     field @Deprecated public static final String ACTION_SIM_STATE_CHANGED = "android.intent.action.SIM_STATE_CHANGED";
@@ -1479,6 +1485,7 @@
   }
 
   public class OverlayManager {
+    method @Nullable public android.content.om.OverlayInfo getOverlayInfo(@NonNull String, @NonNull android.os.UserHandle);
     method public java.util.List<android.content.om.OverlayInfo> getOverlayInfosForTarget(@Nullable String, int);
     method public boolean setEnabled(@Nullable String, boolean, int);
     method public boolean setEnabledExclusiveInCategory(@Nullable String, int);
@@ -1618,7 +1625,6 @@
     method public abstract java.util.List<android.content.pm.IntentFilterVerificationInfo> getIntentFilterVerifications(String);
     method @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS_FULL) public abstract int getIntentVerificationStatusAsUser(String, int);
     method @android.content.pm.PackageManager.PermissionFlags @RequiresPermission(anyOf={android.Manifest.permission.GRANT_RUNTIME_PERMISSIONS, android.Manifest.permission.REVOKE_RUNTIME_PERMISSIONS, android.Manifest.permission.GET_RUNTIME_PERMISSIONS}) public abstract int getPermissionFlags(String, String, @NonNull android.os.UserHandle);
-    method public boolean getSyntheticAppDetailsActivityEnabled(@NonNull String);
     method @NonNull @RequiresPermission(android.Manifest.permission.SUSPEND_APPS) public String[] getUnsuspendablePackages(@NonNull String[]);
     method @RequiresPermission(android.Manifest.permission.GRANT_RUNTIME_PERMISSIONS) public abstract void grantRuntimePermission(@NonNull String, @NonNull String, @NonNull android.os.UserHandle);
     method @Deprecated public abstract int installExistingPackage(String) throws android.content.pm.PackageManager.NameNotFoundException;
@@ -1648,6 +1654,7 @@
     field public static final String FEATURE_BROADCAST_RADIO = "android.hardware.broadcastradio";
     field public static final String FEATURE_TELEPHONY_CARRIERLOCK = "android.hardware.telephony.carrierlock";
     field public static final int FLAG_PERMISSION_GRANTED_BY_DEFAULT = 32; // 0x20
+    field public static final int FLAG_PERMISSION_HIDDEN = 1024; // 0x400
     field public static final int FLAG_PERMISSION_POLICY_FIXED = 4; // 0x4
     field public static final int FLAG_PERMISSION_REVIEW_REQUIRED = 64; // 0x40
     field public static final int FLAG_PERMISSION_REVOKE_ON_UPGRADE = 8; // 0x8
@@ -1718,7 +1725,7 @@
     method public void onPermissionsChanged(int);
   }
 
-  @IntDef(prefix={"FLAG_PERMISSION_"}, value={android.content.pm.PackageManager.FLAG_PERMISSION_USER_SET, android.content.pm.PackageManager.FLAG_PERMISSION_USER_FIXED, android.content.pm.PackageManager.FLAG_PERMISSION_POLICY_FIXED, android.content.pm.PackageManager.FLAG_PERMISSION_REVOKE_ON_UPGRADE, android.content.pm.PackageManager.FLAG_PERMISSION_SYSTEM_FIXED, android.content.pm.PackageManager.FLAG_PERMISSION_GRANTED_BY_DEFAULT, android.content.pm.PackageManager.FLAG_PERMISSION_USER_SENSITIVE_WHEN_GRANTED, android.content.pm.PackageManager.FLAG_PERMISSION_USER_SENSITIVE_WHEN_DENIED}) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface PackageManager.PermissionFlags {
+  @IntDef(prefix={"FLAG_PERMISSION_"}, value={android.content.pm.PackageManager.FLAG_PERMISSION_USER_SET, android.content.pm.PackageManager.FLAG_PERMISSION_USER_FIXED, android.content.pm.PackageManager.FLAG_PERMISSION_POLICY_FIXED, android.content.pm.PackageManager.FLAG_PERMISSION_REVOKE_ON_UPGRADE, android.content.pm.PackageManager.FLAG_PERMISSION_SYSTEM_FIXED, android.content.pm.PackageManager.FLAG_PERMISSION_GRANTED_BY_DEFAULT, android.content.pm.PackageManager.FLAG_PERMISSION_USER_SENSITIVE_WHEN_GRANTED, android.content.pm.PackageManager.FLAG_PERMISSION_USER_SENSITIVE_WHEN_DENIED, android.content.pm.PackageManager.FLAG_PERMISSION_HIDDEN}) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface PackageManager.PermissionFlags {
   }
 
   public class PermissionGroupInfo extends android.content.pm.PackageItemInfo implements android.os.Parcelable {
@@ -1837,9 +1844,9 @@
   }
 
   public final class RollbackManager {
-    method @RequiresPermission(android.Manifest.permission.MANAGE_ROLLBACKS) public void commitRollback(int, @NonNull java.util.List<android.content.pm.VersionedPackage>, @NonNull android.content.IntentSender);
-    method @RequiresPermission(android.Manifest.permission.MANAGE_ROLLBACKS) @NonNull public java.util.List<android.content.rollback.RollbackInfo> getAvailableRollbacks();
-    method @RequiresPermission(android.Manifest.permission.MANAGE_ROLLBACKS) @NonNull public java.util.List<android.content.rollback.RollbackInfo> getRecentlyCommittedRollbacks();
+    method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_ROLLBACKS, android.Manifest.permission.TEST_MANAGE_ROLLBACKS}) public void commitRollback(int, @NonNull java.util.List<android.content.pm.VersionedPackage>, @NonNull android.content.IntentSender);
+    method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_ROLLBACKS, android.Manifest.permission.TEST_MANAGE_ROLLBACKS}) @NonNull public java.util.List<android.content.rollback.RollbackInfo> getAvailableRollbacks();
+    method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_ROLLBACKS, android.Manifest.permission.TEST_MANAGE_ROLLBACKS}) @NonNull public java.util.List<android.content.rollback.RollbackInfo> getRecentlyCommittedRollbacks();
     field public static final String EXTRA_STATUS = "android.content.rollback.extra.STATUS";
     field public static final String EXTRA_STATUS_MESSAGE = "android.content.rollback.extra.STATUS_MESSAGE";
     field public static final int STATUS_FAILURE = 1; // 0x1
@@ -3067,6 +3074,19 @@
     method public void onLocationBatch(java.util.List<android.location.Location>);
   }
 
+  public final class GnssCapabilities {
+    method public boolean hasCapability(int);
+    field public static final int GEOFENCING = 2; // 0x2
+    field public static final int LOW_POWER_MODE = 0; // 0x0
+    field public static final int MEASUREMENTS = 3; // 0x3
+    field public static final int MEASUREMENT_CORRECTIONS = 5; // 0x5
+    field public static final int MEASUREMENT_CORRECTIONS_EXCESS_PATH_LENGTH = 7; // 0x7
+    field public static final int MEASUREMENT_CORRECTIONS_LOS_SATS = 6; // 0x6
+    field public static final int MEASUREMENT_CORRECTIONS_REFLECTING_PLANE = 8; // 0x8
+    field public static final int NAV_MESSAGES = 4; // 0x4
+    field public static final int SATELLITE_BLACKLIST = 1; // 0x1
+  }
+
   public final class GnssMeasurementCorrections implements android.os.Parcelable {
     method public int describeContents();
     method @FloatRange(from=-1000.0F, to=10000.0f) public double getAltitudeMeters();
@@ -3374,7 +3394,7 @@
   public class LocationManager {
     method @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public void flushGnssBatch();
     method @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public int getGnssBatchSize();
-    method public int getGnssCapabilities();
+    method @Nullable public android.location.GnssCapabilities getGnssCapabilities();
     method @Nullable public String getLocationControllerExtraPackage();
     method @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public void injectGnssMeasurementCorrections(@NonNull android.location.GnssMeasurementCorrections);
     method public boolean isLocationControllerExtraPackageEnabled();
@@ -3558,13 +3578,6 @@
     field public static final int RADIO_TUNER = 1998; // 0x7ce
   }
 
-  public static final class MediaTimestamp.Builder {
-    ctor public MediaTimestamp.Builder();
-    ctor public MediaTimestamp.Builder(@NonNull android.media.MediaTimestamp);
-    method @NonNull public android.media.MediaTimestamp build();
-    method @NonNull public android.media.MediaTimestamp.Builder setMediaTimestamp(long, long, float);
-  }
-
   public class PlayerProxy {
     method public void pause();
     method public void setPan(float);
@@ -3574,20 +3587,6 @@
     method public void stop();
   }
 
-  public static final class SubtitleData.Builder {
-    ctor public SubtitleData.Builder();
-    ctor public SubtitleData.Builder(@NonNull android.media.SubtitleData);
-    method @NonNull public android.media.SubtitleData build();
-    method @NonNull public android.media.SubtitleData.Builder setSubtitleData(int, long, long, @NonNull byte[]);
-  }
-
-  public static final class TimedMetaData.Builder {
-    ctor public TimedMetaData.Builder();
-    ctor public TimedMetaData.Builder(@NonNull android.media.TimedMetaData);
-    method @NonNull public android.media.TimedMetaData build();
-    method @NonNull public android.media.TimedMetaData.Builder setTimedMetaData(long, @NonNull byte[]);
-  }
-
 }
 
 package android.media.audiopolicy {
@@ -4028,8 +4027,8 @@
 package android.net {
 
   public class CaptivePortal implements android.os.Parcelable {
-    ctor public CaptivePortal(android.os.IBinder);
-    method public void logEvent(int, String);
+    ctor public CaptivePortal(@NonNull android.os.IBinder);
+    method public void logEvent(int, @NonNull String);
     method public void useNetwork();
     field public static final int APP_RETURN_DISMISSED = 0; // 0x0
     field public static final int APP_RETURN_UNWANTED = 1; // 0x1
@@ -4045,7 +4044,7 @@
     method @RequiresPermission(anyOf={android.Manifest.permission.TETHER_PRIVILEGED, android.Manifest.permission.WRITE_SETTINGS}) public boolean isTetheringSupported();
     method @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public void registerTetheringEventCallback(@NonNull java.util.concurrent.Executor, @NonNull android.net.ConnectivityManager.OnTetheringEventCallback);
     method @RequiresPermission(anyOf={"android.permission.NETWORK_SETTINGS", android.Manifest.permission.NETWORK_SETUP_WIZARD, "android.permission.NETWORK_STACK"}) public void setAirplaneMode(boolean);
-    method @RequiresPermission(android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK) public void startCaptivePortalApp(android.net.Network, android.os.Bundle);
+    method @RequiresPermission(android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK) public void startCaptivePortalApp(@NonNull android.net.Network, @NonNull android.os.Bundle);
     method @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public void startTethering(int, boolean, android.net.ConnectivityManager.OnStartTetheringCallback);
     method @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public void startTethering(int, boolean, android.net.ConnectivityManager.OnStartTetheringCallback, android.os.Handler);
     method @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public void stopTethering(int);
@@ -4076,8 +4075,8 @@
   }
 
   public final class IpPrefix implements android.os.Parcelable {
-    ctor public IpPrefix(java.net.InetAddress, int);
-    ctor public IpPrefix(String);
+    ctor public IpPrefix(@NonNull java.net.InetAddress, int);
+    ctor public IpPrefix(@NonNull String);
   }
 
   public final class IpSecManager {
@@ -4100,57 +4099,47 @@
     ctor public LinkAddress(java.net.InetAddress, int, int, int);
     ctor public LinkAddress(@NonNull java.net.InetAddress, int);
     ctor public LinkAddress(@NonNull String);
-    ctor public LinkAddress(String, int, int);
+    ctor public LinkAddress(@NonNull String, int, int);
     method public boolean isGlobalPreferred();
-    method public boolean isIPv4();
-    method public boolean isIPv6();
-    method public boolean isSameAddressAs(android.net.LinkAddress);
+    method public boolean isIpv4();
+    method public boolean isIpv6();
+    method public boolean isSameAddressAs(@Nullable android.net.LinkAddress);
   }
 
   public final class LinkProperties implements android.os.Parcelable {
-    ctor public LinkProperties();
-    ctor public LinkProperties(android.net.LinkProperties);
-    method public boolean addDnsServer(java.net.InetAddress);
-    method public boolean addLinkAddress(android.net.LinkAddress);
-    method public boolean addRoute(android.net.RouteInfo);
-    method public void clear();
+    ctor public LinkProperties(@Nullable android.net.LinkProperties);
+    method public boolean addDnsServer(@NonNull java.net.InetAddress);
+    method public boolean addLinkAddress(@NonNull android.net.LinkAddress);
     method @Nullable public android.net.IpPrefix getNat64Prefix();
-    method public java.util.List<java.net.InetAddress> getPcscfServers();
-    method public String getTcpBufferSizes();
-    method public java.util.List<java.net.InetAddress> getValidatedPrivateDnsServers();
-    method public boolean hasGlobalIPv6Address();
-    method public boolean hasIPv4Address();
-    method public boolean hasIPv6DefaultRoute();
-    method public boolean isIPv4Provisioned();
-    method public boolean isIPv6Provisioned();
+    method @NonNull public java.util.List<java.net.InetAddress> getPcscfServers();
+    method @Nullable public String getTcpBufferSizes();
+    method @NonNull public java.util.List<java.net.InetAddress> getValidatedPrivateDnsServers();
+    method public boolean hasGlobalIpv6Address();
+    method public boolean hasIpv4Address();
+    method public boolean hasIpv6DefaultRoute();
+    method public boolean isIpv4Provisioned();
+    method public boolean isIpv6Provisioned();
     method public boolean isProvisioned();
-    method public boolean isReachable(java.net.InetAddress);
-    method public boolean removeDnsServer(java.net.InetAddress);
-    method public boolean removeLinkAddress(android.net.LinkAddress);
-    method public boolean removeRoute(android.net.RouteInfo);
-    method public void setDnsServers(java.util.Collection<java.net.InetAddress>);
-    method public void setDomains(String);
-    method public void setHttpProxy(android.net.ProxyInfo);
-    method public void setInterfaceName(String);
-    method public void setLinkAddresses(java.util.Collection<android.net.LinkAddress>);
-    method public void setMtu(int);
-    method public void setNat64Prefix(android.net.IpPrefix);
-    method public void setPcscfServers(java.util.Collection<java.net.InetAddress>);
+    method public boolean isReachable(@NonNull java.net.InetAddress);
+    method public boolean removeDnsServer(@NonNull java.net.InetAddress);
+    method public boolean removeLinkAddress(@NonNull android.net.LinkAddress);
+    method public boolean removeRoute(@NonNull android.net.RouteInfo);
+    method public void setNat64Prefix(@Nullable android.net.IpPrefix);
+    method public void setPcscfServers(@NonNull java.util.Collection<java.net.InetAddress>);
     method public void setPrivateDnsServerName(@Nullable String);
-    method public void setTcpBufferSizes(String);
+    method public void setTcpBufferSizes(@Nullable String);
     method public void setUsePrivateDns(boolean);
-    method public void setValidatedPrivateDnsServers(java.util.Collection<java.net.InetAddress>);
+    method public void setValidatedPrivateDnsServers(@NonNull java.util.Collection<java.net.InetAddress>);
   }
 
   public class Network implements android.os.Parcelable {
-    ctor public Network(android.net.Network);
-    method public android.net.Network getPrivateDnsBypassingCopy();
+    ctor public Network(@NonNull android.net.Network);
+    method @NonNull public android.net.Network getPrivateDnsBypassingCopy();
   }
 
   public final class NetworkCapabilities implements android.os.Parcelable {
-    method public int getSignalStrength();
-    method public int[] getTransportTypes();
-    method public boolean satisfiedByNetworkCapabilities(android.net.NetworkCapabilities);
+    method @NonNull public int[] getTransportTypes();
+    method public boolean satisfiedByNetworkCapabilities(@Nullable android.net.NetworkCapabilities);
     field public static final int NET_CAPABILITY_OEM_PAID = 22; // 0x16
     field public static final int NET_CAPABILITY_PARTIAL_CONNECTIVITY = 24; // 0x18
   }
@@ -4172,7 +4161,7 @@
   }
 
   public static class NetworkRequest.Builder {
-    method public android.net.NetworkRequest.Builder setSignalStrength(int);
+    method @NonNull public android.net.NetworkRequest.Builder setSignalStrength(int);
   }
 
   public class NetworkScoreManager {
@@ -4196,7 +4185,7 @@
   }
 
   public final class RouteInfo implements android.os.Parcelable {
-    ctor public RouteInfo(android.net.IpPrefix, java.net.InetAddress, String, int);
+    ctor public RouteInfo(@Nullable android.net.IpPrefix, @Nullable java.net.InetAddress, @Nullable String, int);
     method public int getType();
     field public static final int RTN_THROW = 9; // 0x9
     field public static final int RTN_UNICAST = 1; // 0x1
@@ -4236,18 +4225,18 @@
 
   public final class StaticIpConfiguration implements android.os.Parcelable {
     ctor public StaticIpConfiguration();
-    ctor public StaticIpConfiguration(android.net.StaticIpConfiguration);
-    method public void addDnsServer(java.net.InetAddress);
+    ctor public StaticIpConfiguration(@Nullable android.net.StaticIpConfiguration);
+    method public void addDnsServer(@NonNull java.net.InetAddress);
     method public void clear();
     method public int describeContents();
-    method public java.util.List<java.net.InetAddress> getDnsServers();
-    method public String getDomains();
-    method public java.net.InetAddress getGateway();
-    method public android.net.LinkAddress getIpAddress();
-    method public java.util.List<android.net.RouteInfo> getRoutes(String);
-    method public void setDomains(String);
-    method public void setGateway(java.net.InetAddress);
-    method public void setIpAddress(android.net.LinkAddress);
+    method @NonNull public java.util.List<java.net.InetAddress> getDnsServers();
+    method @Nullable public String getDomains();
+    method @Nullable public java.net.InetAddress getGateway();
+    method @Nullable public android.net.LinkAddress getIpAddress();
+    method @NonNull public java.util.List<android.net.RouteInfo> getRoutes(String);
+    method public void setDomains(@Nullable String);
+    method public void setGateway(@Nullable java.net.InetAddress);
+    method public void setIpAddress(@Nullable android.net.LinkAddress);
     method public void writeToParcel(android.os.Parcel, int);
     field @NonNull public static final android.os.Parcelable.Creator<android.net.StaticIpConfiguration> CREATOR;
   }
@@ -4282,11 +4271,14 @@
 
 package android.net.apf {
 
-  public class ApfCapabilities {
+  public final class ApfCapabilities implements android.os.Parcelable {
     ctor public ApfCapabilities(int, int, int);
-    method public static boolean getApfDrop8023Frames(android.content.Context);
-    method public static int[] getApfEthTypeBlackList(android.content.Context);
+    method public int describeContents();
+    method public static boolean getApfDrop8023Frames(@NonNull android.content.Context);
+    method @NonNull public static int[] getApfEthTypeBlackList(@NonNull android.content.Context);
     method public boolean hasDataAccess();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.net.apf.ApfCapabilities> CREATOR;
     field public final int apfPacketFormat;
     field public final int apfVersionSupported;
     field public final int maximumApfProgramSize;
@@ -4298,28 +4290,28 @@
 
   public final class CaptivePortalProbeResult {
     ctor public CaptivePortalProbeResult(int);
-    ctor public CaptivePortalProbeResult(int, String, String);
-    ctor public CaptivePortalProbeResult(int, String, String, android.net.captiveportal.CaptivePortalProbeSpec);
+    ctor public CaptivePortalProbeResult(int, @Nullable String, @Nullable String);
+    ctor public CaptivePortalProbeResult(int, @Nullable String, @Nullable String, @Nullable android.net.captiveportal.CaptivePortalProbeSpec);
     method public boolean isFailed();
     method public boolean isPartialConnectivity();
     method public boolean isPortal();
     method public boolean isSuccessful();
-    field public static final android.net.captiveportal.CaptivePortalProbeResult FAILED;
+    field @NonNull public static final android.net.captiveportal.CaptivePortalProbeResult FAILED;
     field public static final int FAILED_CODE = 599; // 0x257
     field public static final android.net.captiveportal.CaptivePortalProbeResult PARTIAL;
     field public static final int PORTAL_CODE = 302; // 0x12e
-    field public static final android.net.captiveportal.CaptivePortalProbeResult SUCCESS;
+    field @NonNull public static final android.net.captiveportal.CaptivePortalProbeResult SUCCESS;
     field public static final int SUCCESS_CODE = 204; // 0xcc
-    field public final String detectUrl;
+    field @Nullable public final String detectUrl;
     field @Nullable public final android.net.captiveportal.CaptivePortalProbeSpec probeSpec;
-    field public final String redirectUrl;
+    field @Nullable public final String redirectUrl;
   }
 
   public abstract class CaptivePortalProbeSpec {
-    method public String getEncodedSpec();
-    method public abstract android.net.captiveportal.CaptivePortalProbeResult getResult(int, @Nullable String);
-    method public java.net.URL getUrl();
-    method public static java.util.Collection<android.net.captiveportal.CaptivePortalProbeSpec> parseCaptivePortalProbeSpecs(String);
+    method @NonNull public String getEncodedSpec();
+    method @NonNull public abstract android.net.captiveportal.CaptivePortalProbeResult getResult(int, @Nullable String);
+    method @NonNull public java.net.URL getUrl();
+    method @NonNull public static java.util.Collection<android.net.captiveportal.CaptivePortalProbeSpec> parseCaptivePortalProbeSpecs(@NonNull String);
     method @Nullable public static android.net.captiveportal.CaptivePortalProbeSpec parseSpecOrNull(@Nullable String);
   }
 
@@ -4330,78 +4322,78 @@
   public final class ApfProgramEvent implements android.net.metrics.IpConnectivityLog.Event {
   }
 
-  public static class ApfProgramEvent.Builder {
+  public static final class ApfProgramEvent.Builder {
     ctor public ApfProgramEvent.Builder();
-    method public android.net.metrics.ApfProgramEvent build();
-    method public android.net.metrics.ApfProgramEvent.Builder setActualLifetime(long);
-    method public android.net.metrics.ApfProgramEvent.Builder setCurrentRas(int);
-    method public android.net.metrics.ApfProgramEvent.Builder setFilteredRas(int);
-    method public android.net.metrics.ApfProgramEvent.Builder setFlags(boolean, boolean);
-    method public android.net.metrics.ApfProgramEvent.Builder setLifetime(long);
-    method public android.net.metrics.ApfProgramEvent.Builder setProgramLength(int);
+    method @NonNull public android.net.metrics.ApfProgramEvent build();
+    method @NonNull public android.net.metrics.ApfProgramEvent.Builder setActualLifetime(long);
+    method @NonNull public android.net.metrics.ApfProgramEvent.Builder setCurrentRas(int);
+    method @NonNull public android.net.metrics.ApfProgramEvent.Builder setFilteredRas(int);
+    method @NonNull public android.net.metrics.ApfProgramEvent.Builder setFlags(boolean, boolean);
+    method @NonNull public android.net.metrics.ApfProgramEvent.Builder setLifetime(long);
+    method @NonNull public android.net.metrics.ApfProgramEvent.Builder setProgramLength(int);
   }
 
   public final class ApfStats implements android.net.metrics.IpConnectivityLog.Event {
   }
 
-  public static class ApfStats.Builder {
+  public static final class ApfStats.Builder {
     ctor public ApfStats.Builder();
-    method public android.net.metrics.ApfStats build();
-    method public android.net.metrics.ApfStats.Builder setDroppedRas(int);
-    method public android.net.metrics.ApfStats.Builder setDurationMs(long);
-    method public android.net.metrics.ApfStats.Builder setMatchingRas(int);
-    method public android.net.metrics.ApfStats.Builder setMaxProgramSize(int);
-    method public android.net.metrics.ApfStats.Builder setParseErrors(int);
-    method public android.net.metrics.ApfStats.Builder setProgramUpdates(int);
-    method public android.net.metrics.ApfStats.Builder setProgramUpdatesAll(int);
-    method public android.net.metrics.ApfStats.Builder setProgramUpdatesAllowingMulticast(int);
-    method public android.net.metrics.ApfStats.Builder setReceivedRas(int);
-    method public android.net.metrics.ApfStats.Builder setZeroLifetimeRas(int);
+    method @NonNull public android.net.metrics.ApfStats build();
+    method @NonNull public android.net.metrics.ApfStats.Builder setDroppedRas(int);
+    method @NonNull public android.net.metrics.ApfStats.Builder setDurationMs(long);
+    method @NonNull public android.net.metrics.ApfStats.Builder setMatchingRas(int);
+    method @NonNull public android.net.metrics.ApfStats.Builder setMaxProgramSize(int);
+    method @NonNull public android.net.metrics.ApfStats.Builder setParseErrors(int);
+    method @NonNull public android.net.metrics.ApfStats.Builder setProgramUpdates(int);
+    method @NonNull public android.net.metrics.ApfStats.Builder setProgramUpdatesAll(int);
+    method @NonNull public android.net.metrics.ApfStats.Builder setProgramUpdatesAllowingMulticast(int);
+    method @NonNull public android.net.metrics.ApfStats.Builder setReceivedRas(int);
+    method @NonNull public android.net.metrics.ApfStats.Builder setZeroLifetimeRas(int);
   }
 
   public final class DhcpClientEvent implements android.net.metrics.IpConnectivityLog.Event {
   }
 
-  public static class DhcpClientEvent.Builder {
+  public static final class DhcpClientEvent.Builder {
     ctor public DhcpClientEvent.Builder();
-    method public android.net.metrics.DhcpClientEvent build();
-    method public android.net.metrics.DhcpClientEvent.Builder setDurationMs(int);
-    method public android.net.metrics.DhcpClientEvent.Builder setMsg(String);
+    method @NonNull public android.net.metrics.DhcpClientEvent build();
+    method @NonNull public android.net.metrics.DhcpClientEvent.Builder setDurationMs(int);
+    method @NonNull public android.net.metrics.DhcpClientEvent.Builder setMsg(String);
   }
 
   public final class DhcpErrorEvent implements android.net.metrics.IpConnectivityLog.Event {
     ctor public DhcpErrorEvent(int);
     method public static int errorCodeWithOption(int, int);
-    field public static final int BOOTP_TOO_SHORT;
-    field public static final int BUFFER_UNDERFLOW;
-    field public static final int DHCP_BAD_MAGIC_COOKIE;
+    field public static final int BOOTP_TOO_SHORT = 67174400; // 0x4010000
+    field public static final int BUFFER_UNDERFLOW = 83951616; // 0x5010000
+    field public static final int DHCP_BAD_MAGIC_COOKIE = 67239936; // 0x4020000
     field public static final int DHCP_ERROR = 4; // 0x4
-    field public static final int DHCP_INVALID_OPTION_LENGTH;
-    field public static final int DHCP_NO_COOKIE;
-    field public static final int DHCP_NO_MSG_TYPE;
-    field public static final int DHCP_UNKNOWN_MSG_TYPE;
+    field public static final int DHCP_INVALID_OPTION_LENGTH = 67305472; // 0x4030000
+    field public static final int DHCP_NO_COOKIE = 67502080; // 0x4060000
+    field public static final int DHCP_NO_MSG_TYPE = 67371008; // 0x4040000
+    field public static final int DHCP_UNKNOWN_MSG_TYPE = 67436544; // 0x4050000
     field public static final int L2_ERROR = 1; // 0x1
-    field public static final int L2_TOO_SHORT;
-    field public static final int L2_WRONG_ETH_TYPE;
+    field public static final int L2_TOO_SHORT = 16842752; // 0x1010000
+    field public static final int L2_WRONG_ETH_TYPE = 16908288; // 0x1020000
     field public static final int L3_ERROR = 2; // 0x2
-    field public static final int L3_INVALID_IP;
-    field public static final int L3_NOT_IPV4;
-    field public static final int L3_TOO_SHORT;
+    field public static final int L3_INVALID_IP = 33751040; // 0x2030000
+    field public static final int L3_NOT_IPV4 = 33685504; // 0x2020000
+    field public static final int L3_TOO_SHORT = 33619968; // 0x2010000
     field public static final int L4_ERROR = 3; // 0x3
-    field public static final int L4_NOT_UDP;
-    field public static final int L4_WRONG_PORT;
+    field public static final int L4_NOT_UDP = 50397184; // 0x3010000
+    field public static final int L4_WRONG_PORT = 50462720; // 0x3020000
     field public static final int MISC_ERROR = 5; // 0x5
-    field public static final int PARSING_ERROR;
-    field public static final int RECEIVE_ERROR;
+    field public static final int PARSING_ERROR = 84082688; // 0x5030000
+    field public static final int RECEIVE_ERROR = 84017152; // 0x5020000
   }
 
   public class IpConnectivityLog {
     ctor public IpConnectivityLog();
-    method public boolean log(long, android.net.metrics.IpConnectivityLog.Event);
-    method public boolean log(String, android.net.metrics.IpConnectivityLog.Event);
-    method public boolean log(android.net.Network, int[], android.net.metrics.IpConnectivityLog.Event);
-    method public boolean log(int, int[], android.net.metrics.IpConnectivityLog.Event);
-    method public boolean log(android.net.metrics.IpConnectivityLog.Event);
+    method public boolean log(long, @NonNull android.net.metrics.IpConnectivityLog.Event);
+    method public boolean log(@NonNull String, @NonNull android.net.metrics.IpConnectivityLog.Event);
+    method public boolean log(@NonNull android.net.Network, @NonNull int[], @NonNull android.net.metrics.IpConnectivityLog.Event);
+    method public boolean log(int, @NonNull int[], @NonNull android.net.metrics.IpConnectivityLog.Event);
+    method public boolean log(@NonNull android.net.metrics.IpConnectivityLog.Event);
   }
 
   public static interface IpConnectivityLog.Event extends android.os.Parcelable {
@@ -4449,15 +4441,15 @@
   public final class RaEvent implements android.net.metrics.IpConnectivityLog.Event {
   }
 
-  public static class RaEvent.Builder {
+  public static final class RaEvent.Builder {
     ctor public RaEvent.Builder();
-    method public android.net.metrics.RaEvent build();
-    method public android.net.metrics.RaEvent.Builder updateDnsslLifetime(long);
-    method public android.net.metrics.RaEvent.Builder updatePrefixPreferredLifetime(long);
-    method public android.net.metrics.RaEvent.Builder updatePrefixValidLifetime(long);
-    method public android.net.metrics.RaEvent.Builder updateRdnssLifetime(long);
-    method public android.net.metrics.RaEvent.Builder updateRouteInfoLifetime(long);
-    method public android.net.metrics.RaEvent.Builder updateRouterLifetime(long);
+    method @NonNull public android.net.metrics.RaEvent build();
+    method @NonNull public android.net.metrics.RaEvent.Builder updateDnsslLifetime(long);
+    method @NonNull public android.net.metrics.RaEvent.Builder updatePrefixPreferredLifetime(long);
+    method @NonNull public android.net.metrics.RaEvent.Builder updatePrefixValidLifetime(long);
+    method @NonNull public android.net.metrics.RaEvent.Builder updateRdnssLifetime(long);
+    method @NonNull public android.net.metrics.RaEvent.Builder updateRouteInfoLifetime(long);
+    method @NonNull public android.net.metrics.RaEvent.Builder updateRouterLifetime(long);
   }
 
   public final class ValidationProbeEvent implements android.net.metrics.IpConnectivityLog.Event {
@@ -4472,28 +4464,28 @@
     field public static final int PROBE_PRIVDNS = 5; // 0x5
   }
 
-  public static class ValidationProbeEvent.Builder {
+  public static final class ValidationProbeEvent.Builder {
     ctor public ValidationProbeEvent.Builder();
-    method public android.net.metrics.ValidationProbeEvent build();
-    method public android.net.metrics.ValidationProbeEvent.Builder setDurationMs(long);
-    method public android.net.metrics.ValidationProbeEvent.Builder setProbeType(int, boolean);
-    method public android.net.metrics.ValidationProbeEvent.Builder setReturnCode(int);
+    method @NonNull public android.net.metrics.ValidationProbeEvent build();
+    method @NonNull public android.net.metrics.ValidationProbeEvent.Builder setDurationMs(long);
+    method @NonNull public android.net.metrics.ValidationProbeEvent.Builder setProbeType(int, boolean);
+    method @NonNull public android.net.metrics.ValidationProbeEvent.Builder setReturnCode(int);
   }
 
 }
 
 package android.net.util {
 
-  public class SocketUtils {
+  public final class SocketUtils {
     method public static void addArpEntry(@NonNull java.net.Inet4Address, @NonNull android.net.MacAddress, @NonNull String, @NonNull java.io.FileDescriptor) throws java.io.IOException;
     method public static void attachControlPacketFilter(@NonNull java.io.FileDescriptor, int) throws java.net.SocketException;
     method public static void attachDhcpFilter(@NonNull java.io.FileDescriptor) throws java.net.SocketException;
     method public static void attachRaFilter(@NonNull java.io.FileDescriptor, int) throws java.net.SocketException;
     method public static void bindSocketToInterface(@NonNull java.io.FileDescriptor, @NonNull String) throws android.system.ErrnoException;
     method public static void closeSocket(@Nullable java.io.FileDescriptor) throws java.io.IOException;
-    method public static java.net.SocketAddress makeNetlinkSocketAddress(int, int);
-    method public static java.net.SocketAddress makePacketSocketAddress(short, int);
-    method public static java.net.SocketAddress makePacketSocketAddress(int, @NonNull byte[]);
+    method @NonNull public static java.net.SocketAddress makeNetlinkSocketAddress(int, int);
+    method @NonNull public static java.net.SocketAddress makePacketSocketAddress(int, int);
+    method @NonNull public static java.net.SocketAddress makePacketSocketAddress(int, @NonNull byte[]);
     method public static void setSocketTimeValueOption(@NonNull java.io.FileDescriptor, int, int, long) throws android.system.ErrnoException;
   }
 
@@ -4934,6 +4926,10 @@
 
   public final class WifiUsabilityStatsEntry implements android.os.Parcelable {
     method public int describeContents();
+    method public int getCellularDataNetworkType();
+    method public int getCellularSignalStrengthDb();
+    method public int getCellularSignalStrengthDbm();
+    method public boolean getIsSameRegisteredCell();
     method public int getLinkSpeedMbps();
     method public int getProbeElapsedTimeSinceLastUpdateMillis();
     method public int getProbeMcsRateSinceLastUpdate();
@@ -5486,7 +5482,7 @@
   }
 
   public class ServiceSpecificException extends java.lang.RuntimeException {
-    ctor public ServiceSpecificException(int, String);
+    ctor public ServiceSpecificException(int, @Nullable String);
     ctor public ServiceSpecificException(int);
     field public final int errorCode;
   }
@@ -5616,6 +5612,7 @@
     method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public boolean isManagedProfile(int);
     method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public boolean isPrimaryUser();
     method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public boolean isRestrictedProfile();
+    method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public boolean isRestrictedProfile(@NonNull android.os.UserHandle);
     method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public boolean removeUser(@NonNull android.os.UserHandle);
     method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public void setUserIcon(@NonNull android.graphics.Bitmap);
     method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public void setUserName(@Nullable String);
@@ -5723,10 +5720,10 @@
   }
 
   public final class RuntimePermissionUsageInfo implements android.os.Parcelable {
-    ctor public RuntimePermissionUsageInfo(@NonNull CharSequence, int);
+    ctor public RuntimePermissionUsageInfo(@NonNull String, int);
     method public int describeContents();
     method public int getAppAccessCount();
-    method @NonNull public CharSequence getName();
+    method @NonNull public String getName();
     method public void writeToParcel(android.os.Parcel, int);
     field @NonNull public static final android.os.Parcelable.Creator<android.permission.RuntimePermissionUsageInfo> CREATOR;
   }
@@ -5860,6 +5857,7 @@
     method @RequiresPermission(android.Manifest.permission.WRITE_DEVICE_CONFIG) public static boolean setProperty(@NonNull String, @NonNull String, @Nullable String, boolean);
     field public static final String NAMESPACE_ACTIVITY_MANAGER = "activity_manager";
     field public static final String NAMESPACE_ACTIVITY_MANAGER_NATIVE_BOOT = "activity_manager_native_boot";
+    field public static final String NAMESPACE_APP_COMPAT = "app_compat";
     field public static final String NAMESPACE_ATTENTION_MANAGER_SERVICE = "attention_manager_service";
     field public static final String NAMESPACE_AUTOFILL = "autofill";
     field public static final String NAMESPACE_CONNECTIVITY = "connectivity";
@@ -5870,10 +5868,15 @@
     field public static final String NAMESPACE_INTELLIGENCE_ATTENTION = "intelligence_attention";
     field public static final String NAMESPACE_MEDIA_NATIVE = "media_native";
     field public static final String NAMESPACE_NETD_NATIVE = "netd_native";
+    field public static final String NAMESPACE_ROLLBACK = "rollback";
+    field public static final String NAMESPACE_ROLLBACK_BOOT = "rollback_boot";
     field public static final String NAMESPACE_RUNTIME = "runtime";
     field public static final String NAMESPACE_RUNTIME_NATIVE = "runtime_native";
     field public static final String NAMESPACE_RUNTIME_NATIVE_BOOT = "runtime_native_boot";
+    field public static final String NAMESPACE_SCHEDULER = "scheduler";
+    field public static final String NAMESPACE_STORAGE = "storage";
     field public static final String NAMESPACE_SYSTEMUI = "systemui";
+    field public static final String NAMESPACE_TELEPHONY = "telephony";
     field public static final String NAMESPACE_TEXTCLASSIFIER = "textclassifier";
   }
 
@@ -5901,30 +5904,6 @@
     method @Nullable public String getString(@NonNull String, @Nullable String);
   }
 
-  public static interface DeviceConfig.Rollback {
-    field public static final String BOOT_NAMESPACE = "rollback_boot";
-    field public static final String ENABLE_ROLLBACK_TIMEOUT = "enable_rollback_timeout";
-    field public static final String NAMESPACE = "rollback";
-    field public static final String ROLLBACK_LIFETIME_IN_MILLIS = "rollback_lifetime_in_millis";
-  }
-
-  public static interface DeviceConfig.Scheduler {
-    field public static final String ENABLE_FAST_METRICS_COLLECTION = "enable_fast_metrics_collection";
-    field public static final String NAMESPACE = "scheduler";
-  }
-
-  public static interface DeviceConfig.Storage {
-    field public static final String ISOLATED_STORAGE_ENABLED = "isolated_storage_enabled";
-    field public static final String NAMESPACE = "storage";
-  }
-
-  public static interface DeviceConfig.Telephony {
-    field public static final String NAMESPACE = "telephony";
-    field public static final String RAMPING_RINGER_DURATION = "ramping_ringer_duration";
-    field public static final String RAMPING_RINGER_ENABLED = "ramping_ringer_enabled";
-    field public static final String RAMPING_RINGER_VIBRATION_DURATION = "ramping_ringer_vibration_duration";
-  }
-
   public final class DocumentsContract {
     method public static boolean isManageMode(@NonNull android.net.Uri);
     method @NonNull public static android.net.Uri setManageMode(@NonNull android.net.Uri);
@@ -6055,6 +6034,7 @@
     field public static final String ACTION_ACCESSIBILITY_DETAILS_SETTINGS = "android.settings.ACCESSIBILITY_DETAILS_SETTINGS";
     field public static final String ACTION_ENTERPRISE_PRIVACY_SETTINGS = "android.settings.ENTERPRISE_PRIVACY_SETTINGS";
     field public static final String ACTION_LOCATION_CONTROLLER_EXTRA_PACKAGE_SETTINGS = "android.settings.LOCATION_CONTROLLER_EXTRA_PACKAGE_SETTINGS";
+    field public static final String ACTION_MANAGE_DOMAIN_URLS = "android.settings.MANAGE_DOMAIN_URLS";
     field public static final String ACTION_REQUEST_ENABLE_CONTENT_CAPTURE = "android.settings.REQUEST_ENABLE_CONTENT_CAPTURE";
     field public static final String ACTION_SHOW_ADMIN_SUPPORT_DETAILS = "android.settings.SHOW_ADMIN_SUPPORT_DETAILS";
   }
@@ -6118,6 +6098,8 @@
     field public static final String LOCATION_PERMISSIONS_UPGRADE_TO_Q_MODE = "location_permissions_upgrade_to_q_mode";
     field public static final String LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS = "lock_screen_allow_private_notifications";
     field public static final String LOCK_SCREEN_SHOW_NOTIFICATIONS = "lock_screen_show_notifications";
+    field public static final String ODI_CAPTIONS_ENABLED = "odi_captions_enabled";
+    field public static final String ODI_CAPTIONS_OPTED_OUT = "odi_captions_opted_out";
     field public static final String THEME_CUSTOMIZATION_OVERLAY_PACKAGES = "theme_customization_overlay_packages";
     field public static final String USER_SETUP_COMPLETE = "user_setup_complete";
     field public static final int USER_SETUP_PERSONALIZATION_COMPLETE = 10; // 0xa
@@ -6428,6 +6410,7 @@
     method public int getEventType();
     method public void writeToParcel(@NonNull android.os.Parcel, int);
     field @NonNull public static final android.os.Parcelable.Creator<android.service.contentcapture.ActivityEvent> CREATOR;
+    field public static final int TYPE_ACTIVITY_DESTROYED = 24; // 0x18
     field public static final int TYPE_ACTIVITY_PAUSED = 2; // 0x2
     field public static final int TYPE_ACTIVITY_RESUMED = 1; // 0x1
     field public static final int TYPE_ACTIVITY_STOPPED = 23; // 0x17
@@ -6446,6 +6429,7 @@
     method public void onUserDataRemovalRequest(@NonNull android.view.contentcapture.UserDataRemovalRequest);
     method public final void setContentCaptureWhitelist(@Nullable java.util.Set<java.lang.String>, @Nullable java.util.Set<android.content.ComponentName>);
     field public static final String SERVICE_INTERFACE = "android.service.contentcapture.ContentCaptureService";
+    field public static final String SERVICE_META_DATA = "android.content_capture";
   }
 
   public final class SnapshotData implements android.os.Parcelable {
@@ -6646,6 +6630,7 @@
     method public final void adjustNotifications(@NonNull java.util.List<android.service.notification.Adjustment>);
     method public void onActionInvoked(@NonNull String, @NonNull android.app.Notification.Action, int);
     method @NonNull public final android.os.IBinder onBind(@Nullable android.content.Intent);
+    method public void onCapabilitiesChanged();
     method public void onNotificationDirectReplied(@NonNull String);
     method @Nullable public abstract android.service.notification.Adjustment onNotificationEnqueued(@NonNull android.service.notification.StatusBarNotification);
     method @Nullable public android.service.notification.Adjustment onNotificationEnqueued(@NonNull android.service.notification.StatusBarNotification, @NonNull android.app.NotificationChannel);
@@ -7236,7 +7221,6 @@
     field public static final int ACCESS_BLOCK_ALL = 2088; // 0x828
     field public static final int ACCESS_CLASS_DSAC_REJECTION = 2108; // 0x83c
     field public static final int ACCESS_CONTROL_LIST_CHECK_FAILURE = 2128; // 0x850
-    field public static final int ACCESS_PROBE_LIMIT_REACHED = 2079; // 0x81f
     field public static final int ACTIVATION_REJECTED_BCM_VIOLATION = 48; // 0x30
     field public static final int ACTIVATION_REJECT_GGSN = 30; // 0x1e
     field public static final int ACTIVATION_REJECT_UNSPECIFIED = 31; // 0x1f
@@ -7351,9 +7335,7 @@
     field public static final int INVALID_PRIMARY_NSAPI = 2158; // 0x86e
     field public static final int INVALID_SIM_STATE = 2224; // 0x8b0
     field public static final int INVALID_TRANSACTION_ID = 81; // 0x51
-    field public static final int IPV4_CONNECTIONS_LIMIT_REACHED = 2052; // 0x804
     field public static final int IPV6_ADDRESS_TRANSFER_FAILED = 2047; // 0x7ff
-    field public static final int IPV6_CONNECTIONS_LIMIT_REACHED = 2053; // 0x805
     field public static final int IPV6_PREFIX_UNAVAILABLE = 2250; // 0x8ca
     field public static final int IP_ADDRESS_MISMATCH = 119; // 0x77
     field public static final int IP_VERSION_MISMATCH = 2055; // 0x807
@@ -7372,6 +7354,10 @@
     field public static final int MAC_FAILURE = 2183; // 0x887
     field public static final int MAXIMIUM_NSAPIS_EXCEEDED = 2157; // 0x86d
     field public static final int MAXINUM_SIZE_OF_L2_MESSAGE_EXCEEDED = 2166; // 0x876
+    field public static final int MAX_ACCESS_PROBE = 2079; // 0x81f
+    field public static final int MAX_IPV4_CONNECTIONS = 2052; // 0x804
+    field public static final int MAX_IPV6_CONNECTIONS = 2053; // 0x805
+    field public static final int MAX_PPP_INACTIVITY_TIMER_EXPIRED = 2046; // 0x7fe
     field public static final int MESSAGE_INCORRECT_SEMANTIC = 95; // 0x5f
     field public static final int MESSAGE_TYPE_UNSUPPORTED = 97; // 0x61
     field public static final int MIP_CONFIG_FAILURE = 2050; // 0x802
@@ -7480,7 +7466,6 @@
     field public static final int PPP_AUTH_FAILURE = 2229; // 0x8b5
     field public static final int PPP_CHAP_FAILURE = 2232; // 0x8b8
     field public static final int PPP_CLOSE_IN_PROGRESS = 2233; // 0x8b9
-    field public static final int PPP_INACTIVITY_TIMER_EXPIRED = 2046; // 0x7fe
     field public static final int PPP_OPTION_MISMATCH = 2230; // 0x8b6
     field public static final int PPP_PAP_FAILURE = 2231; // 0x8b7
     field public static final int PPP_TIMEOUT = 2228; // 0x8b4
@@ -7681,15 +7666,14 @@
     field public static final String MBMS_STREAMING_SERVICE_ACTION = "android.telephony.action.EmbmsStreaming";
   }
 
-  public class NetworkRegistrationInfo implements android.os.Parcelable {
-    ctor public NetworkRegistrationInfo(int, int, int, int, int, boolean, @NonNull int[], @Nullable android.telephony.CellIdentity);
+  public final class NetworkRegistrationInfo implements android.os.Parcelable {
     method public int describeContents();
     method public int getAccessNetworkTechnology();
-    method @NonNull public int[] getAvailableServices();
+    method @NonNull public java.util.List<java.lang.Integer> getAvailableServices();
     method @Nullable public android.telephony.CellIdentity getCellIdentity();
     method @Nullable public android.telephony.DataSpecificRegistrationStates getDataSpecificStates();
     method public int getDomain();
-    method public int getRegState();
+    method public int getRegistrationState();
     method public int getRejectCause();
     method public int getRoamingType();
     method public int getTransportType();
@@ -7699,31 +7683,30 @@
     field @NonNull public static final android.os.Parcelable.Creator<android.telephony.NetworkRegistrationInfo> CREATOR;
     field public static final int DOMAIN_CS = 1; // 0x1
     field public static final int DOMAIN_PS = 2; // 0x2
-    field public static final int REG_STATE_DENIED = 3; // 0x3
-    field public static final int REG_STATE_HOME = 1; // 0x1
-    field public static final int REG_STATE_NOT_REG_NOT_SEARCHING = 0; // 0x0
-    field public static final int REG_STATE_NOT_REG_SEARCHING = 2; // 0x2
-    field public static final int REG_STATE_ROAMING = 5; // 0x5
-    field public static final int REG_STATE_UNKNOWN = 4; // 0x4
+    field public static final int REGISTRATION_STATE_DENIED = 3; // 0x3
+    field public static final int REGISTRATION_STATE_HOME = 1; // 0x1
+    field public static final int REGISTRATION_STATE_NOT_REGISTERED_OR_SEARCHING = 0; // 0x0
+    field public static final int REGISTRATION_STATE_NOT_REGISTERED_SEARCHING = 2; // 0x2
+    field public static final int REGISTRATION_STATE_ROAMING = 5; // 0x5
+    field public static final int REGISTRATION_STATE_UNKNOWN = 4; // 0x4
     field public static final int SERVICE_TYPE_DATA = 2; // 0x2
     field public static final int SERVICE_TYPE_EMERGENCY = 5; // 0x5
     field public static final int SERVICE_TYPE_SMS = 3; // 0x3
+    field public static final int SERVICE_TYPE_UNKNOWN = 0; // 0x0
     field public static final int SERVICE_TYPE_VIDEO = 4; // 0x4
     field public static final int SERVICE_TYPE_VOICE = 1; // 0x1
   }
 
-  public static class NetworkRegistrationInfo.Builder {
+  public static final class NetworkRegistrationInfo.Builder {
     ctor public NetworkRegistrationInfo.Builder();
     method @NonNull public android.telephony.NetworkRegistrationInfo build();
     method @NonNull public android.telephony.NetworkRegistrationInfo.Builder setAccessNetworkTechnology(int);
-    method @NonNull public android.telephony.NetworkRegistrationInfo.Builder setAvailableServices(@NonNull int[]);
+    method @NonNull public android.telephony.NetworkRegistrationInfo.Builder setAvailableServices(@NonNull java.util.List<java.lang.Integer>);
     method @NonNull public android.telephony.NetworkRegistrationInfo.Builder setCellIdentity(@Nullable android.telephony.CellIdentity);
     method @NonNull public android.telephony.NetworkRegistrationInfo.Builder setDomain(int);
     method @NonNull public android.telephony.NetworkRegistrationInfo.Builder setEmergencyOnly(boolean);
-    method @NonNull public android.telephony.NetworkRegistrationInfo.Builder setNrStatus(int);
-    method @NonNull public android.telephony.NetworkRegistrationInfo.Builder setRegState(int);
+    method @NonNull public android.telephony.NetworkRegistrationInfo.Builder setRegistrationState(int);
     method @NonNull public android.telephony.NetworkRegistrationInfo.Builder setRejectCause(int);
-    method @NonNull public android.telephony.NetworkRegistrationInfo.Builder setRoamingType(int);
     method @NonNull public android.telephony.NetworkRegistrationInfo.Builder setTransportType(int);
   }
 
@@ -7731,19 +7714,19 @@
     ctor public NetworkService();
     method public android.os.IBinder onBind(android.content.Intent);
     method @Nullable public abstract android.telephony.NetworkService.NetworkServiceProvider onCreateNetworkServiceProvider(int);
-    field public static final String NETWORK_SERVICE_INTERFACE = "android.telephony.NetworkService";
+    field public static final String SERVICE_INTERFACE = "android.telephony.NetworkService";
   }
 
   public abstract class NetworkService.NetworkServiceProvider implements java.lang.AutoCloseable {
     ctor public NetworkService.NetworkServiceProvider(int);
     method public abstract void close();
-    method public void getNetworkRegistrationInfo(int, @NonNull android.telephony.NetworkServiceCallback);
     method public final int getSlotIndex();
     method public final void notifyNetworkRegistrationInfoChanged();
+    method public void requestNetworkRegistrationInfo(int, @NonNull android.telephony.NetworkServiceCallback);
   }
 
   public class NetworkServiceCallback {
-    method public void onGetNetworkRegistrationInfoComplete(int, @Nullable android.telephony.NetworkRegistrationInfo);
+    method public void onRequestNetworkRegistrationInfoComplete(int, @Nullable android.telephony.NetworkRegistrationInfo);
     field public static final int RESULT_ERROR_BUSY = 3; // 0x3
     field public static final int RESULT_ERROR_FAILED = 5; // 0x5
     field public static final int RESULT_ERROR_ILLEGAL_STATE = 4; // 0x4
@@ -8045,11 +8028,12 @@
     method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public int getVoiceActivationState();
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean handlePinMmi(String);
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean handlePinMmiForSubscriber(int, String);
-    method @Nullable @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean iccCloseLogicalChannelBySlot(int, int);
+    method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean iccCloseLogicalChannelBySlot(int, int);
     method @Nullable @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public android.telephony.IccOpenLogicalChannelResponse iccOpenLogicalChannelBySlot(int, @Nullable String, int);
     method @NonNull @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public String iccTransmitApduBasicChannelBySlot(int, int, int, int, int, int, @Nullable String);
     method @Nullable @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public String iccTransmitApduLogicalChannelBySlot(int, int, int, int, int, int, int, @Nullable String);
     method public boolean isDataConnectivityPossible();
+    method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isEmergencyAssistanceEnabled();
     method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, android.Manifest.permission.READ_PHONE_STATE}) public boolean isIdle();
     method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, android.Manifest.permission.READ_PHONE_STATE}) public boolean isOffhook();
     method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isPotentialEmergencyNumber(@NonNull String);
@@ -8069,7 +8053,7 @@
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setDataActivationState(int);
     method @Deprecated @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setDataEnabled(int, boolean);
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setDataRoamingEnabled(boolean);
-    method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setMultisimCarrierRestriction(boolean);
+    method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setMultiSimCarrierRestriction(boolean);
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean setPreferredNetworkTypeBitmask(long);
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean setRadio(boolean);
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean setRadioPower(boolean);
@@ -8176,39 +8160,55 @@
 package android.telephony.data {
 
   public final class DataCallResponse implements android.os.Parcelable {
-    ctor public DataCallResponse(int, int, int, int, int, @Nullable String, @Nullable java.util.List<android.net.LinkAddress>, @Nullable java.util.List<java.net.InetAddress>, @Nullable java.util.List<java.net.InetAddress>, @Nullable java.util.List<java.lang.String>, int);
     method public int describeContents();
-    method public int getActive();
     method @NonNull public java.util.List<android.net.LinkAddress> getAddresses();
-    method public int getCallId();
-    method @NonNull public java.util.List<java.net.InetAddress> getDnses();
-    method @NonNull public java.util.List<java.net.InetAddress> getGateways();
-    method @NonNull public String getIfname();
+    method public int getCause();
+    method @NonNull public java.util.List<java.net.InetAddress> getDnsAddresses();
+    method @NonNull public java.util.List<java.net.InetAddress> getGatewayAddresses();
+    method public int getId();
+    method @NonNull public String getInterfaceName();
+    method public int getLinkStatus();
     method public int getMtu();
-    method @NonNull public java.util.List<java.lang.String> getPcscfs();
+    method @NonNull public java.util.List<java.net.InetAddress> getPcscfAddresses();
     method public int getProtocolType();
-    method public int getStatus();
     method 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;
+    field public static final int LINK_STATUS_ACTIVE = 2; // 0x2
+    field public static final int LINK_STATUS_DORMANT = 1; // 0x1
+    field public static final int LINK_STATUS_INACTIVE = 0; // 0x0
+    field public static final int LINK_STATUS_UNKNOWN = -1; // 0xffffffff
+  }
+
+  public static final class DataCallResponse.Builder {
+    ctor public DataCallResponse.Builder();
+    method @NonNull public android.telephony.data.DataCallResponse build();
+    method @NonNull public android.telephony.data.DataCallResponse.Builder setAddresses(@NonNull java.util.List<android.net.LinkAddress>);
+    method @NonNull public android.telephony.data.DataCallResponse.Builder setCause(int);
+    method @NonNull public android.telephony.data.DataCallResponse.Builder setDnsAddresses(@NonNull java.util.List<java.net.InetAddress>);
+    method @NonNull public android.telephony.data.DataCallResponse.Builder setGatewayAddresses(@NonNull java.util.List<java.net.InetAddress>);
+    method @NonNull public android.telephony.data.DataCallResponse.Builder setId(int);
+    method @NonNull public android.telephony.data.DataCallResponse.Builder setInterfaceName(@NonNull String);
+    method @NonNull public android.telephony.data.DataCallResponse.Builder setLinkStatus(int);
+    method @NonNull public android.telephony.data.DataCallResponse.Builder setMtu(int);
+    method @NonNull public android.telephony.data.DataCallResponse.Builder setPcscfAddresses(@NonNull java.util.List<java.net.InetAddress>);
+    method @NonNull public android.telephony.data.DataCallResponse.Builder setProtocolType(int);
+    method @NonNull public android.telephony.data.DataCallResponse.Builder setSuggestedRetryTime(int);
   }
 
   public final class DataProfile implements android.os.Parcelable {
     method public int describeContents();
     method @NonNull public String getApn();
     method public int getAuthType();
-    method public int getBearerBitmap();
-    method public int getMaxConns();
-    method public int getMaxConnsTime();
+    method public int getBearerBitmask();
     method public int getMtu();
     method @Nullable public String getPassword();
     method public int getProfileId();
-    method public int getProtocol();
-    method public int getRoamingProtocol();
-    method public int getSupportedApnTypesBitmap();
+    method public int getProtocolType();
+    method public int getRoamingProtocolType();
+    method public int getSupportedApnTypesBitmask();
     method public int getType();
     method @Nullable public String getUserName();
-    method public int getWaitTime();
     method public boolean isEnabled();
     method public boolean isPersistent();
     method public boolean isPreferred();
@@ -8219,32 +8219,52 @@
     field public static final int TYPE_COMMON = 0; // 0x0
   }
 
+  public static final class DataProfile.Builder {
+    ctor public DataProfile.Builder();
+    method @NonNull public android.telephony.data.DataProfile build();
+    method @NonNull public android.telephony.data.DataProfile.Builder enable(boolean);
+    method @NonNull public android.telephony.data.DataProfile.Builder setApn(@NonNull String);
+    method @NonNull public android.telephony.data.DataProfile.Builder setAuthType(int);
+    method @NonNull public android.telephony.data.DataProfile.Builder setBearerBitmask(int);
+    method @NonNull public android.telephony.data.DataProfile.Builder setMtu(int);
+    method @NonNull public android.telephony.data.DataProfile.Builder setPassword(@NonNull String);
+    method @NonNull public android.telephony.data.DataProfile.Builder setPersistent(boolean);
+    method @NonNull public android.telephony.data.DataProfile.Builder setPreferred(boolean);
+    method @NonNull public android.telephony.data.DataProfile.Builder setProfileId(int);
+    method @NonNull public android.telephony.data.DataProfile.Builder setProtocolType(int);
+    method @NonNull public android.telephony.data.DataProfile.Builder setRoamingProtocolType(int);
+    method @NonNull public android.telephony.data.DataProfile.Builder setSupportedApnTypesBitmask(int);
+    method @NonNull public android.telephony.data.DataProfile.Builder setType(int);
+    method @NonNull public android.telephony.data.DataProfile.Builder setUserName(@NonNull String);
+  }
+
   public abstract class DataService extends android.app.Service {
     ctor public DataService();
     method public android.os.IBinder onBind(android.content.Intent);
     method @Nullable public abstract android.telephony.data.DataService.DataServiceProvider onCreateDataServiceProvider(int);
-    field public static final String DATA_SERVICE_INTERFACE = "android.telephony.data.DataService";
     field public static final int REQUEST_REASON_HANDOVER = 3; // 0x3
     field public static final int REQUEST_REASON_NORMAL = 1; // 0x1
     field public static final int REQUEST_REASON_SHUTDOWN = 2; // 0x2
+    field public static final int REQUEST_REASON_UNKNOWN = 0; // 0x0
+    field public static final String SERVICE_INTERFACE = "android.telephony.data.DataService";
   }
 
   public abstract class DataService.DataServiceProvider implements java.lang.AutoCloseable {
     ctor public DataService.DataServiceProvider(int);
     method public abstract void close();
     method public void deactivateDataCall(int, int, @Nullable android.telephony.data.DataServiceCallback);
-    method public void getDataCallList(@NonNull android.telephony.data.DataServiceCallback);
     method public final int getSlotIndex();
     method public final void notifyDataCallListChanged(java.util.List<android.telephony.data.DataCallResponse>);
-    method public void setDataProfile(@NonNull java.util.List<android.telephony.data.DataProfile>, boolean, @Nullable android.telephony.data.DataServiceCallback);
-    method public void setInitialAttachApn(@NonNull android.telephony.data.DataProfile, boolean, @Nullable android.telephony.data.DataServiceCallback);
-    method public void setupDataCall(int, @NonNull android.telephony.data.DataProfile, boolean, boolean, int, @Nullable android.net.LinkProperties, @Nullable android.telephony.data.DataServiceCallback);
+    method public void requestDataCallList(@NonNull android.telephony.data.DataServiceCallback);
+    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);
   }
 
   public class DataServiceCallback {
     method public void onDataCallListChanged(@NonNull java.util.List<android.telephony.data.DataCallResponse>);
     method public void onDeactivateDataCallComplete(int);
-    method public void onGetDataCallListComplete(int, @NonNull java.util.List<android.telephony.data.DataCallResponse>);
+    method public void onRequestDataCallListComplete(int, @NonNull java.util.List<android.telephony.data.DataCallResponse>);
     method public void onSetDataProfileComplete(int);
     method public void onSetInitialAttachApnComplete(int);
     method public void onSetupDataCallComplete(int, @Nullable android.telephony.data.DataCallResponse);
@@ -8257,15 +8277,15 @@
 
   public abstract class QualifiedNetworksService extends android.app.Service {
     ctor public QualifiedNetworksService();
-    method @NonNull public abstract android.telephony.data.QualifiedNetworksService.NetworkAvailabilityUpdater createNetworkAvailabilityUpdater(int);
+    method @NonNull public abstract android.telephony.data.QualifiedNetworksService.NetworkAvailabilityProvider onCreateNetworkAvailabilityProvider(int);
     field public static final String QUALIFIED_NETWORKS_SERVICE_INTERFACE = "android.telephony.data.QualifiedNetworksService";
   }
 
-  public abstract class QualifiedNetworksService.NetworkAvailabilityUpdater implements java.lang.AutoCloseable {
-    ctor public QualifiedNetworksService.NetworkAvailabilityUpdater(int);
+  public abstract class QualifiedNetworksService.NetworkAvailabilityProvider implements java.lang.AutoCloseable {
+    ctor public QualifiedNetworksService.NetworkAvailabilityProvider(int);
     method public abstract void close();
     method public final int getSlotIndex();
-    method public final void updateQualifiedNetworkTypes(int, @Nullable int[]);
+    method public final void updateQualifiedNetworkTypes(int, @NonNull java.util.List<java.lang.Integer>);
   }
 
 }
@@ -8357,6 +8377,7 @@
     field public static final String EXTRA_EMBEDDED_SUBSCRIPTION_DOWNLOADABLE_SUBSCRIPTIONS = "android.telephony.euicc.extra.EMBEDDED_SUBSCRIPTION_DOWNLOADABLE_SUBSCRIPTIONS";
     field public static final String EXTRA_ENABLE_SUBSCRIPTION = "android.telephony.euicc.extra.ENABLE_SUBSCRIPTION";
     field public static final String EXTRA_FORCE_PROVISION = "android.telephony.euicc.extra.FORCE_PROVISION";
+    field public static final String EXTRA_FROM_SUBSCRIPTION_ID = "android.telephony.euicc.extra.FROM_SUBSCRIPTION_ID";
     field public static final String EXTRA_SUBSCRIPTION_ID = "android.telephony.euicc.extra.SUBSCRIPTION_ID";
     field public static final String EXTRA_SUBSCRIPTION_NICKNAME = "android.telephony.euicc.extra.SUBSCRIPTION_NICKNAME";
   }
@@ -8576,7 +8597,7 @@
     field public final java.util.HashMap<java.lang.String,android.os.Bundle> mParticipants;
   }
 
-  public class ImsException extends java.lang.Exception {
+  public final class ImsException extends java.lang.Exception {
     ctor public ImsException(@Nullable String);
     ctor public ImsException(@Nullable String, int);
     ctor public ImsException(@Nullable String, int, @Nullable Throwable);
@@ -9107,8 +9128,8 @@
     field public static final int STATE_UNAVAILABLE = 0; // 0x0
   }
 
-  public static class ImsFeature.Capabilities {
-    field protected int mCapabilities;
+  @Deprecated public static class ImsFeature.Capabilities {
+    field @Deprecated protected int mCapabilities;
   }
 
   protected static class ImsFeature.CapabilityCallbackProxy {
diff --git a/api/system-removed.txt b/api/system-removed.txt
index 18d0ec0..9780d43 100644
--- a/api/system-removed.txt
+++ b/api/system-removed.txt
@@ -60,14 +60,6 @@
 
 }
 
-package android.content.pm {
-
-  public static class PackageInstaller.SessionParams implements android.os.Parcelable {
-    method @Deprecated public void setEnableRollback();
-  }
-
-}
-
 package android.location {
 
   public class LocationManager {
@@ -149,3 +141,11 @@
 
 }
 
+package android.telephony.data {
+
+  public final class DataCallResponse implements android.os.Parcelable {
+    ctor public DataCallResponse(int, int, int, int, int, @Nullable String, @Nullable java.util.List<android.net.LinkAddress>, @Nullable java.util.List<java.net.InetAddress>, @Nullable java.util.List<java.net.InetAddress>, @Nullable java.util.List<java.net.InetAddress>, int);
+  }
+
+}
+
diff --git a/api/test-current.txt b/api/test-current.txt
index 4ccfa1c..417a9ed 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -14,6 +14,7 @@
     field public static final String MANAGE_ROLLBACKS = "android.permission.MANAGE_ROLLBACKS";
     field public static final String READ_CELL_BROADCASTS = "android.permission.READ_CELL_BROADCASTS";
     field public static final String REMOVE_TASKS = "android.permission.REMOVE_TASKS";
+    field public static final String TEST_MANAGE_ROLLBACKS = "android.permission.TEST_MANAGE_ROLLBACKS";
     field public static final String WRITE_DEVICE_CONFIG = "android.permission.WRITE_DEVICE_CONFIG";
     field public static final String WRITE_MEDIA_STORAGE = "android.permission.WRITE_MEDIA_STORAGE";
     field public static final String WRITE_OBB = "android.permission.WRITE_OBB";
@@ -133,16 +134,19 @@
     method @RequiresPermission("android.permission.MANAGE_APPOPS") public void addHistoricalOps(@NonNull android.app.AppOpsManager.HistoricalOps);
     method @RequiresPermission("android.permission.MANAGE_APPOPS") public void clearHistory();
     method @RequiresPermission("android.permission.GET_APP_OPS_STATS") public void getHistoricalOps(@NonNull android.app.AppOpsManager.HistoricalOpsRequest, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<android.app.AppOpsManager.HistoricalOps>);
-    method @RequiresPermission("android.permission.GET_APP_OPS_STATS") public void getHistoricalOpsFromDiskRaw(@NonNull android.app.AppOpsManager.HistoricalOpsRequest, @Nullable java.util.concurrent.Executor, @NonNull java.util.function.Consumer<android.app.AppOpsManager.HistoricalOps>);
+    method @RequiresPermission("android.permission.MANAGE_APPOPS") public void getHistoricalOpsFromDiskRaw(@NonNull android.app.AppOpsManager.HistoricalOpsRequest, @Nullable java.util.concurrent.Executor, @NonNull java.util.function.Consumer<android.app.AppOpsManager.HistoricalOps>);
     method public static int getNumOps();
     method public static String[] getOpStrs();
     method public boolean isOperationActive(int, int, String);
     method @RequiresPermission("android.permission.MANAGE_APPOPS") public void offsetHistory(long);
+    method public static int opToDefaultMode(@NonNull String);
     method public static String opToPermission(int);
     method public static int permissionToOpCode(String);
+    method @RequiresPermission("android.permission.MANAGE_APPOPS") public void reloadNonHistoricalState();
     method @RequiresPermission("android.permission.MANAGE_APPOPS") public void resetHistoryParameters();
     method @RequiresPermission("android.permission.MANAGE_APPOPS") public void setHistoryParameters(int, long, int);
     method @RequiresPermission("android.permission.MANAGE_APP_OPS_MODES") public void setMode(int, int, String, int);
+    method @RequiresPermission("android.permission.MANAGE_APP_OPS_MODES") public void setMode(String, int, String, int);
     method @RequiresPermission("android.permission.MANAGE_APP_OPS_MODES") public void setUidMode(String, int, int);
     method public void startWatchingActive(@NonNull int[], @NonNull android.app.AppOpsManager.OnOpActiveChangedListener);
     method public void stopWatchingActive(@NonNull android.app.AppOpsManager.OnOpActiveChangedListener);
@@ -168,6 +172,7 @@
     field public static final String OPSTR_GET_ACCOUNTS = "android:get_accounts";
     field public static final String OPSTR_GPS = "android:gps";
     field public static final String OPSTR_INSTANT_APP_START_FOREGROUND = "android:instant_app_start_foreground";
+    field public static final String OPSTR_LEGACY_STORAGE = "android:legacy_storage";
     field public static final String OPSTR_MANAGE_IPSEC_TUNNELS = "android:manage_ipsec_tunnels";
     field public static final String OPSTR_MUTE_MICROPHONE = "android:mute_microphone";
     field public static final String OPSTR_NEIGHBORING_CELLS = "android:neighboring_cells";
@@ -415,7 +420,8 @@
   public class BackupManager {
     method @RequiresPermission("android.permission.BACKUP") public android.content.Intent getConfigurationIntent(String);
     method @RequiresPermission("android.permission.BACKUP") public android.content.Intent getDataManagementIntent(String);
-    method @RequiresPermission("android.permission.BACKUP") public String getDataManagementLabel(String);
+    method @Nullable @RequiresPermission("android.permission.BACKUP") public CharSequence getDataManagementIntentLabel(@NonNull String);
+    method @Deprecated @Nullable @RequiresPermission("android.permission.BACKUP") public String getDataManagementLabel(@NonNull String);
     method @RequiresPermission("android.permission.BACKUP") public String getDestinationString(String);
   }
 
@@ -655,6 +661,7 @@
     method @RequiresPermission(anyOf={"android.permission.GRANT_RUNTIME_PERMISSIONS", "android.permission.REVOKE_RUNTIME_PERMISSIONS"}) public abstract void updatePermissionFlags(String, String, int, int, @NonNull android.os.UserHandle);
     field public static final String FEATURE_ADOPTABLE_STORAGE = "android.software.adoptable_storage";
     field public static final String FEATURE_FILE_BASED_ENCRYPTION = "android.software.file_based_encryption";
+    field public static final int FLAG_PERMISSION_HIDDEN = 1024; // 0x400
     field public static final int FLAG_PERMISSION_REVIEW_REQUIRED = 64; // 0x40
     field public static final int FLAG_PERMISSION_REVOKE_ON_UPGRADE = 8; // 0x8
     field public static final int FLAG_PERMISSION_REVOKE_WHEN_REQUESTED = 128; // 0x80
@@ -720,13 +727,14 @@
   }
 
   public final class RollbackManager {
-    method @RequiresPermission(android.Manifest.permission.MANAGE_ROLLBACKS) public void commitRollback(int, @NonNull java.util.List<android.content.pm.VersionedPackage>, @NonNull android.content.IntentSender);
-    method @RequiresPermission(android.Manifest.permission.MANAGE_ROLLBACKS) public void expireRollbackForPackage(@NonNull String);
-    method @RequiresPermission(android.Manifest.permission.MANAGE_ROLLBACKS) @NonNull public java.util.List<android.content.rollback.RollbackInfo> getAvailableRollbacks();
-    method @RequiresPermission(android.Manifest.permission.MANAGE_ROLLBACKS) @NonNull public java.util.List<android.content.rollback.RollbackInfo> getRecentlyCommittedRollbacks();
-    method @RequiresPermission(android.Manifest.permission.MANAGE_ROLLBACKS) public void reloadPersistedData();
+    method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_ROLLBACKS, android.Manifest.permission.TEST_MANAGE_ROLLBACKS}) public void commitRollback(int, @NonNull java.util.List<android.content.pm.VersionedPackage>, @NonNull android.content.IntentSender);
+    method @RequiresPermission(android.Manifest.permission.TEST_MANAGE_ROLLBACKS) public void expireRollbackForPackage(@NonNull String);
+    method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_ROLLBACKS, android.Manifest.permission.TEST_MANAGE_ROLLBACKS}) @NonNull public java.util.List<android.content.rollback.RollbackInfo> getAvailableRollbacks();
+    method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_ROLLBACKS, android.Manifest.permission.TEST_MANAGE_ROLLBACKS}) @NonNull public java.util.List<android.content.rollback.RollbackInfo> getRecentlyCommittedRollbacks();
+    method @RequiresPermission(android.Manifest.permission.TEST_MANAGE_ROLLBACKS) public void reloadPersistedData();
     field public static final String EXTRA_STATUS = "android.content.rollback.extra.STATUS";
     field public static final String EXTRA_STATUS_MESSAGE = "android.content.rollback.extra.STATUS_MESSAGE";
+    field public static final String PROPERTY_ROLLBACK_LIFETIME_MILLIS = "rollback_lifetime_in_millis";
     field public static final int STATUS_FAILURE = 1; // 0x1
     field public static final int STATUS_FAILURE_INSTALL = 3; // 0x3
     field public static final int STATUS_FAILURE_ROLLBACK_UNAVAILABLE = 2; // 0x2
@@ -1070,6 +1078,25 @@
     method public android.media.BufferingParams.Builder setResumePlaybackMarkMs(int);
   }
 
+  public class CallbackDataSourceDesc extends android.media.DataSourceDesc {
+    method @NonNull public android.media.DataSourceCallback getDataSourceCallback();
+  }
+
+  public class FileDataSourceDesc extends android.media.DataSourceDesc {
+    method public long getLength();
+    method public long getOffset();
+    method @NonNull public android.os.ParcelFileDescriptor getParcelFileDescriptor();
+    field public static final long FD_LENGTH_UNKNOWN = 576460752303423487L; // 0x7ffffffffffffffL
+  }
+
+  public static final class MediaCodecInfo.VideoCapabilities.PerformancePoint {
+    ctor public MediaCodecInfo.VideoCapabilities.PerformancePoint(int, int, int, int, @NonNull android.util.Size);
+    ctor public MediaCodecInfo.VideoCapabilities.PerformancePoint(@NonNull android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint, @NonNull android.util.Size);
+    method public int getMaxFrameRate();
+    method public long getMaxMacroBlockRate();
+    method public int getMaxMacroBlocks();
+  }
+
   public class MediaPlayer2 implements android.media.AudioRouting java.lang.AutoCloseable {
     method public android.media.MediaPlayer2.DrmInfo getDrmInfo(@NonNull android.media.DataSourceDesc);
     method public android.media.MediaDrm.KeyRequest getDrmKeyRequest(@NonNull android.media.DataSourceDesc, @Nullable byte[], @Nullable byte[], @Nullable String, int, @Nullable java.util.Map<java.lang.String,java.lang.String>) throws android.media.MediaPlayer2.NoDrmSchemeException;
@@ -1086,6 +1113,12 @@
     method public android.media.PlaybackParams setAudioStretchMode(int);
   }
 
+  public class UriDataSourceDesc extends android.media.DataSourceDesc {
+    method @Nullable public java.util.List<java.net.HttpCookie> getCookies();
+    method @Nullable public java.util.Map<java.lang.String,java.lang.String> getHeaders();
+    method @NonNull public android.net.Uri getUri();
+  }
+
   public static final class VolumeShaper.Configuration.Builder {
     method @NonNull public android.media.VolumeShaper.Configuration.Builder setOptionFlags(int);
   }
@@ -1174,8 +1207,8 @@
 package android.net {
 
   public class CaptivePortal implements android.os.Parcelable {
-    ctor public CaptivePortal(android.os.IBinder);
-    method public void logEvent(int, String);
+    ctor public CaptivePortal(@NonNull android.os.IBinder);
+    method public void logEvent(int, @NonNull String);
     method public void useNetwork();
     field public static final int APP_RETURN_DISMISSED = 0; // 0x0
     field public static final int APP_RETURN_UNWANTED = 1; // 0x1
@@ -1183,14 +1216,14 @@
   }
 
   public class ConnectivityManager {
-    method @RequiresPermission(android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK) public void startCaptivePortalApp(android.net.Network, android.os.Bundle);
+    method @RequiresPermission(android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK) public void startCaptivePortalApp(@NonNull android.net.Network, @NonNull android.os.Bundle);
     field public static final String EXTRA_CAPTIVE_PORTAL_PROBE_SPEC = "android.net.extra.CAPTIVE_PORTAL_PROBE_SPEC";
     field public static final String EXTRA_CAPTIVE_PORTAL_USER_AGENT = "android.net.extra.CAPTIVE_PORTAL_USER_AGENT";
   }
 
   public final class IpPrefix implements android.os.Parcelable {
-    ctor public IpPrefix(java.net.InetAddress, int);
-    ctor public IpPrefix(String);
+    ctor public IpPrefix(@NonNull java.net.InetAddress, int);
+    ctor public IpPrefix(@NonNull String);
   }
 
   public final class IpSecManager {
@@ -1201,48 +1234,48 @@
     ctor public LinkAddress(java.net.InetAddress, int, int, int);
     ctor public LinkAddress(@NonNull java.net.InetAddress, int);
     ctor public LinkAddress(@NonNull String);
-    ctor public LinkAddress(String, int, int);
+    ctor public LinkAddress(@NonNull String, int, int);
     method public boolean isGlobalPreferred();
-    method public boolean isIPv4();
-    method public boolean isIPv6();
-    method public boolean isSameAddressAs(android.net.LinkAddress);
+    method public boolean isIpv4();
+    method public boolean isIpv6();
+    method public boolean isSameAddressAs(@Nullable android.net.LinkAddress);
   }
 
   public final class LinkProperties implements android.os.Parcelable {
-    ctor public LinkProperties(android.net.LinkProperties);
-    method public boolean addDnsServer(java.net.InetAddress);
-    method public boolean addLinkAddress(android.net.LinkAddress);
+    ctor public LinkProperties(@Nullable android.net.LinkProperties);
+    method public boolean addDnsServer(@NonNull java.net.InetAddress);
+    method public boolean addLinkAddress(@NonNull android.net.LinkAddress);
     method @Nullable public android.net.IpPrefix getNat64Prefix();
-    method public java.util.List<java.net.InetAddress> getPcscfServers();
-    method public String getTcpBufferSizes();
-    method public java.util.List<java.net.InetAddress> getValidatedPrivateDnsServers();
-    method public boolean hasGlobalIPv6Address();
-    method public boolean hasIPv4Address();
-    method public boolean hasIPv6DefaultRoute();
-    method public boolean isIPv4Provisioned();
-    method public boolean isIPv6Provisioned();
+    method @NonNull public java.util.List<java.net.InetAddress> getPcscfServers();
+    method @Nullable public String getTcpBufferSizes();
+    method @NonNull public java.util.List<java.net.InetAddress> getValidatedPrivateDnsServers();
+    method public boolean hasGlobalIpv6Address();
+    method public boolean hasIpv4Address();
+    method public boolean hasIpv6DefaultRoute();
+    method public boolean isIpv4Provisioned();
+    method public boolean isIpv6Provisioned();
     method public boolean isProvisioned();
-    method public boolean isReachable(java.net.InetAddress);
-    method public boolean removeDnsServer(java.net.InetAddress);
-    method public boolean removeLinkAddress(android.net.LinkAddress);
-    method public boolean removeRoute(android.net.RouteInfo);
-    method public void setNat64Prefix(android.net.IpPrefix);
-    method public void setPcscfServers(java.util.Collection<java.net.InetAddress>);
+    method public boolean isReachable(@NonNull java.net.InetAddress);
+    method public boolean removeDnsServer(@NonNull java.net.InetAddress);
+    method public boolean removeLinkAddress(@NonNull android.net.LinkAddress);
+    method public boolean removeRoute(@NonNull android.net.RouteInfo);
+    method public void setNat64Prefix(@Nullable android.net.IpPrefix);
+    method public void setPcscfServers(@NonNull java.util.Collection<java.net.InetAddress>);
     method public void setPrivateDnsServerName(@Nullable String);
-    method public void setTcpBufferSizes(String);
+    method public void setTcpBufferSizes(@Nullable String);
     method public void setUsePrivateDns(boolean);
-    method public void setValidatedPrivateDnsServers(java.util.Collection<java.net.InetAddress>);
+    method public void setValidatedPrivateDnsServers(@NonNull java.util.Collection<java.net.InetAddress>);
   }
 
   public class Network implements android.os.Parcelable {
-    ctor public Network(android.net.Network);
-    method public android.net.Network getPrivateDnsBypassingCopy();
+    ctor public Network(@NonNull android.net.Network);
+    method @NonNull public android.net.Network getPrivateDnsBypassingCopy();
   }
 
   public final class NetworkCapabilities implements android.os.Parcelable {
     method public int[] getCapabilities();
-    method public int[] getTransportTypes();
-    method public boolean satisfiedByNetworkCapabilities(android.net.NetworkCapabilities);
+    method @NonNull public int[] getTransportTypes();
+    method public boolean satisfiedByNetworkCapabilities(@Nullable android.net.NetworkCapabilities);
     field public static final int TRANSPORT_TEST = 7; // 0x7
   }
 
@@ -1251,7 +1284,7 @@
   }
 
   public final class RouteInfo implements android.os.Parcelable {
-    ctor public RouteInfo(android.net.IpPrefix, java.net.InetAddress, String, int);
+    ctor public RouteInfo(@Nullable android.net.IpPrefix, @Nullable java.net.InetAddress, @Nullable String, int);
     method public int getType();
     field public static final int RTN_THROW = 9; // 0x9
     field public static final int RTN_UNICAST = 1; // 0x1
@@ -1260,18 +1293,18 @@
 
   public final class StaticIpConfiguration implements android.os.Parcelable {
     ctor public StaticIpConfiguration();
-    ctor public StaticIpConfiguration(android.net.StaticIpConfiguration);
-    method public void addDnsServer(java.net.InetAddress);
+    ctor public StaticIpConfiguration(@Nullable android.net.StaticIpConfiguration);
+    method public void addDnsServer(@NonNull java.net.InetAddress);
     method public void clear();
     method public int describeContents();
-    method public java.util.List<java.net.InetAddress> getDnsServers();
-    method public String getDomains();
-    method public java.net.InetAddress getGateway();
-    method public android.net.LinkAddress getIpAddress();
-    method public java.util.List<android.net.RouteInfo> getRoutes(String);
-    method public void setDomains(String);
-    method public void setGateway(java.net.InetAddress);
-    method public void setIpAddress(android.net.LinkAddress);
+    method @NonNull public java.util.List<java.net.InetAddress> getDnsServers();
+    method @Nullable public String getDomains();
+    method @Nullable public java.net.InetAddress getGateway();
+    method @Nullable public android.net.LinkAddress getIpAddress();
+    method @NonNull public java.util.List<android.net.RouteInfo> getRoutes(String);
+    method public void setDomains(@Nullable String);
+    method public void setGateway(@Nullable java.net.InetAddress);
+    method public void setIpAddress(@Nullable android.net.LinkAddress);
     method public void writeToParcel(android.os.Parcel, int);
     field @NonNull public static final android.os.Parcelable.Creator<android.net.StaticIpConfiguration> CREATOR;
   }
@@ -1305,11 +1338,14 @@
 
 package android.net.apf {
 
-  public class ApfCapabilities {
+  public final class ApfCapabilities implements android.os.Parcelable {
     ctor public ApfCapabilities(int, int, int);
-    method public static boolean getApfDrop8023Frames(android.content.Context);
-    method public static int[] getApfEthTypeBlackList(android.content.Context);
+    method public int describeContents();
+    method public static boolean getApfDrop8023Frames(@NonNull android.content.Context);
+    method @NonNull public static int[] getApfEthTypeBlackList(@NonNull android.content.Context);
     method public boolean hasDataAccess();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.net.apf.ApfCapabilities> CREATOR;
     field public final int apfPacketFormat;
     field public final int apfVersionSupported;
     field public final int maximumApfProgramSize;
@@ -1321,28 +1357,28 @@
 
   public final class CaptivePortalProbeResult {
     ctor public CaptivePortalProbeResult(int);
-    ctor public CaptivePortalProbeResult(int, String, String);
-    ctor public CaptivePortalProbeResult(int, String, String, android.net.captiveportal.CaptivePortalProbeSpec);
+    ctor public CaptivePortalProbeResult(int, @Nullable String, @Nullable String);
+    ctor public CaptivePortalProbeResult(int, @Nullable String, @Nullable String, @Nullable android.net.captiveportal.CaptivePortalProbeSpec);
     method public boolean isFailed();
     method public boolean isPartialConnectivity();
     method public boolean isPortal();
     method public boolean isSuccessful();
-    field public static final android.net.captiveportal.CaptivePortalProbeResult FAILED;
+    field @NonNull public static final android.net.captiveportal.CaptivePortalProbeResult FAILED;
     field public static final int FAILED_CODE = 599; // 0x257
     field public static final android.net.captiveportal.CaptivePortalProbeResult PARTIAL;
     field public static final int PORTAL_CODE = 302; // 0x12e
-    field public static final android.net.captiveportal.CaptivePortalProbeResult SUCCESS;
+    field @NonNull public static final android.net.captiveportal.CaptivePortalProbeResult SUCCESS;
     field public static final int SUCCESS_CODE = 204; // 0xcc
-    field public final String detectUrl;
+    field @Nullable public final String detectUrl;
     field @Nullable public final android.net.captiveportal.CaptivePortalProbeSpec probeSpec;
-    field public final String redirectUrl;
+    field @Nullable public final String redirectUrl;
   }
 
   public abstract class CaptivePortalProbeSpec {
-    method public String getEncodedSpec();
-    method public abstract android.net.captiveportal.CaptivePortalProbeResult getResult(int, @Nullable String);
-    method public java.net.URL getUrl();
-    method public static java.util.Collection<android.net.captiveportal.CaptivePortalProbeSpec> parseCaptivePortalProbeSpecs(String);
+    method @NonNull public String getEncodedSpec();
+    method @NonNull public abstract android.net.captiveportal.CaptivePortalProbeResult getResult(int, @Nullable String);
+    method @NonNull public java.net.URL getUrl();
+    method @NonNull public static java.util.Collection<android.net.captiveportal.CaptivePortalProbeSpec> parseCaptivePortalProbeSpecs(@NonNull String);
     method @Nullable public static android.net.captiveportal.CaptivePortalProbeSpec parseSpecOrNull(@Nullable String);
   }
 
@@ -1353,78 +1389,78 @@
   public final class ApfProgramEvent implements android.net.metrics.IpConnectivityLog.Event {
   }
 
-  public static class ApfProgramEvent.Builder {
+  public static final class ApfProgramEvent.Builder {
     ctor public ApfProgramEvent.Builder();
-    method public android.net.metrics.ApfProgramEvent build();
-    method public android.net.metrics.ApfProgramEvent.Builder setActualLifetime(long);
-    method public android.net.metrics.ApfProgramEvent.Builder setCurrentRas(int);
-    method public android.net.metrics.ApfProgramEvent.Builder setFilteredRas(int);
-    method public android.net.metrics.ApfProgramEvent.Builder setFlags(boolean, boolean);
-    method public android.net.metrics.ApfProgramEvent.Builder setLifetime(long);
-    method public android.net.metrics.ApfProgramEvent.Builder setProgramLength(int);
+    method @NonNull public android.net.metrics.ApfProgramEvent build();
+    method @NonNull public android.net.metrics.ApfProgramEvent.Builder setActualLifetime(long);
+    method @NonNull public android.net.metrics.ApfProgramEvent.Builder setCurrentRas(int);
+    method @NonNull public android.net.metrics.ApfProgramEvent.Builder setFilteredRas(int);
+    method @NonNull public android.net.metrics.ApfProgramEvent.Builder setFlags(boolean, boolean);
+    method @NonNull public android.net.metrics.ApfProgramEvent.Builder setLifetime(long);
+    method @NonNull public android.net.metrics.ApfProgramEvent.Builder setProgramLength(int);
   }
 
   public final class ApfStats implements android.net.metrics.IpConnectivityLog.Event {
   }
 
-  public static class ApfStats.Builder {
+  public static final class ApfStats.Builder {
     ctor public ApfStats.Builder();
-    method public android.net.metrics.ApfStats build();
-    method public android.net.metrics.ApfStats.Builder setDroppedRas(int);
-    method public android.net.metrics.ApfStats.Builder setDurationMs(long);
-    method public android.net.metrics.ApfStats.Builder setMatchingRas(int);
-    method public android.net.metrics.ApfStats.Builder setMaxProgramSize(int);
-    method public android.net.metrics.ApfStats.Builder setParseErrors(int);
-    method public android.net.metrics.ApfStats.Builder setProgramUpdates(int);
-    method public android.net.metrics.ApfStats.Builder setProgramUpdatesAll(int);
-    method public android.net.metrics.ApfStats.Builder setProgramUpdatesAllowingMulticast(int);
-    method public android.net.metrics.ApfStats.Builder setReceivedRas(int);
-    method public android.net.metrics.ApfStats.Builder setZeroLifetimeRas(int);
+    method @NonNull public android.net.metrics.ApfStats build();
+    method @NonNull public android.net.metrics.ApfStats.Builder setDroppedRas(int);
+    method @NonNull public android.net.metrics.ApfStats.Builder setDurationMs(long);
+    method @NonNull public android.net.metrics.ApfStats.Builder setMatchingRas(int);
+    method @NonNull public android.net.metrics.ApfStats.Builder setMaxProgramSize(int);
+    method @NonNull public android.net.metrics.ApfStats.Builder setParseErrors(int);
+    method @NonNull public android.net.metrics.ApfStats.Builder setProgramUpdates(int);
+    method @NonNull public android.net.metrics.ApfStats.Builder setProgramUpdatesAll(int);
+    method @NonNull public android.net.metrics.ApfStats.Builder setProgramUpdatesAllowingMulticast(int);
+    method @NonNull public android.net.metrics.ApfStats.Builder setReceivedRas(int);
+    method @NonNull public android.net.metrics.ApfStats.Builder setZeroLifetimeRas(int);
   }
 
   public final class DhcpClientEvent implements android.net.metrics.IpConnectivityLog.Event {
   }
 
-  public static class DhcpClientEvent.Builder {
+  public static final class DhcpClientEvent.Builder {
     ctor public DhcpClientEvent.Builder();
-    method public android.net.metrics.DhcpClientEvent build();
-    method public android.net.metrics.DhcpClientEvent.Builder setDurationMs(int);
-    method public android.net.metrics.DhcpClientEvent.Builder setMsg(String);
+    method @NonNull public android.net.metrics.DhcpClientEvent build();
+    method @NonNull public android.net.metrics.DhcpClientEvent.Builder setDurationMs(int);
+    method @NonNull public android.net.metrics.DhcpClientEvent.Builder setMsg(String);
   }
 
   public final class DhcpErrorEvent implements android.net.metrics.IpConnectivityLog.Event {
     ctor public DhcpErrorEvent(int);
     method public static int errorCodeWithOption(int, int);
-    field public static final int BOOTP_TOO_SHORT;
-    field public static final int BUFFER_UNDERFLOW;
-    field public static final int DHCP_BAD_MAGIC_COOKIE;
+    field public static final int BOOTP_TOO_SHORT = 67174400; // 0x4010000
+    field public static final int BUFFER_UNDERFLOW = 83951616; // 0x5010000
+    field public static final int DHCP_BAD_MAGIC_COOKIE = 67239936; // 0x4020000
     field public static final int DHCP_ERROR = 4; // 0x4
-    field public static final int DHCP_INVALID_OPTION_LENGTH;
-    field public static final int DHCP_NO_COOKIE;
-    field public static final int DHCP_NO_MSG_TYPE;
-    field public static final int DHCP_UNKNOWN_MSG_TYPE;
+    field public static final int DHCP_INVALID_OPTION_LENGTH = 67305472; // 0x4030000
+    field public static final int DHCP_NO_COOKIE = 67502080; // 0x4060000
+    field public static final int DHCP_NO_MSG_TYPE = 67371008; // 0x4040000
+    field public static final int DHCP_UNKNOWN_MSG_TYPE = 67436544; // 0x4050000
     field public static final int L2_ERROR = 1; // 0x1
-    field public static final int L2_TOO_SHORT;
-    field public static final int L2_WRONG_ETH_TYPE;
+    field public static final int L2_TOO_SHORT = 16842752; // 0x1010000
+    field public static final int L2_WRONG_ETH_TYPE = 16908288; // 0x1020000
     field public static final int L3_ERROR = 2; // 0x2
-    field public static final int L3_INVALID_IP;
-    field public static final int L3_NOT_IPV4;
-    field public static final int L3_TOO_SHORT;
+    field public static final int L3_INVALID_IP = 33751040; // 0x2030000
+    field public static final int L3_NOT_IPV4 = 33685504; // 0x2020000
+    field public static final int L3_TOO_SHORT = 33619968; // 0x2010000
     field public static final int L4_ERROR = 3; // 0x3
-    field public static final int L4_NOT_UDP;
-    field public static final int L4_WRONG_PORT;
+    field public static final int L4_NOT_UDP = 50397184; // 0x3010000
+    field public static final int L4_WRONG_PORT = 50462720; // 0x3020000
     field public static final int MISC_ERROR = 5; // 0x5
-    field public static final int PARSING_ERROR;
-    field public static final int RECEIVE_ERROR;
+    field public static final int PARSING_ERROR = 84082688; // 0x5030000
+    field public static final int RECEIVE_ERROR = 84017152; // 0x5020000
   }
 
   public class IpConnectivityLog {
     ctor public IpConnectivityLog();
-    method public boolean log(long, android.net.metrics.IpConnectivityLog.Event);
-    method public boolean log(String, android.net.metrics.IpConnectivityLog.Event);
-    method public boolean log(android.net.Network, int[], android.net.metrics.IpConnectivityLog.Event);
-    method public boolean log(int, int[], android.net.metrics.IpConnectivityLog.Event);
-    method public boolean log(android.net.metrics.IpConnectivityLog.Event);
+    method public boolean log(long, @NonNull android.net.metrics.IpConnectivityLog.Event);
+    method public boolean log(@NonNull String, @NonNull android.net.metrics.IpConnectivityLog.Event);
+    method public boolean log(@NonNull android.net.Network, @NonNull int[], @NonNull android.net.metrics.IpConnectivityLog.Event);
+    method public boolean log(int, @NonNull int[], @NonNull android.net.metrics.IpConnectivityLog.Event);
+    method public boolean log(@NonNull android.net.metrics.IpConnectivityLog.Event);
   }
 
   public static interface IpConnectivityLog.Event extends android.os.Parcelable {
@@ -1472,15 +1508,15 @@
   public final class RaEvent implements android.net.metrics.IpConnectivityLog.Event {
   }
 
-  public static class RaEvent.Builder {
+  public static final class RaEvent.Builder {
     ctor public RaEvent.Builder();
-    method public android.net.metrics.RaEvent build();
-    method public android.net.metrics.RaEvent.Builder updateDnsslLifetime(long);
-    method public android.net.metrics.RaEvent.Builder updatePrefixPreferredLifetime(long);
-    method public android.net.metrics.RaEvent.Builder updatePrefixValidLifetime(long);
-    method public android.net.metrics.RaEvent.Builder updateRdnssLifetime(long);
-    method public android.net.metrics.RaEvent.Builder updateRouteInfoLifetime(long);
-    method public android.net.metrics.RaEvent.Builder updateRouterLifetime(long);
+    method @NonNull public android.net.metrics.RaEvent build();
+    method @NonNull public android.net.metrics.RaEvent.Builder updateDnsslLifetime(long);
+    method @NonNull public android.net.metrics.RaEvent.Builder updatePrefixPreferredLifetime(long);
+    method @NonNull public android.net.metrics.RaEvent.Builder updatePrefixValidLifetime(long);
+    method @NonNull public android.net.metrics.RaEvent.Builder updateRdnssLifetime(long);
+    method @NonNull public android.net.metrics.RaEvent.Builder updateRouteInfoLifetime(long);
+    method @NonNull public android.net.metrics.RaEvent.Builder updateRouterLifetime(long);
   }
 
   public final class ValidationProbeEvent implements android.net.metrics.IpConnectivityLog.Event {
@@ -1495,28 +1531,28 @@
     field public static final int PROBE_PRIVDNS = 5; // 0x5
   }
 
-  public static class ValidationProbeEvent.Builder {
+  public static final class ValidationProbeEvent.Builder {
     ctor public ValidationProbeEvent.Builder();
-    method public android.net.metrics.ValidationProbeEvent build();
-    method public android.net.metrics.ValidationProbeEvent.Builder setDurationMs(long);
-    method public android.net.metrics.ValidationProbeEvent.Builder setProbeType(int, boolean);
-    method public android.net.metrics.ValidationProbeEvent.Builder setReturnCode(int);
+    method @NonNull public android.net.metrics.ValidationProbeEvent build();
+    method @NonNull public android.net.metrics.ValidationProbeEvent.Builder setDurationMs(long);
+    method @NonNull public android.net.metrics.ValidationProbeEvent.Builder setProbeType(int, boolean);
+    method @NonNull public android.net.metrics.ValidationProbeEvent.Builder setReturnCode(int);
   }
 
 }
 
 package android.net.util {
 
-  public class SocketUtils {
+  public final class SocketUtils {
     method public static void addArpEntry(@NonNull java.net.Inet4Address, @NonNull android.net.MacAddress, @NonNull String, @NonNull java.io.FileDescriptor) throws java.io.IOException;
     method public static void attachControlPacketFilter(@NonNull java.io.FileDescriptor, int) throws java.net.SocketException;
     method public static void attachDhcpFilter(@NonNull java.io.FileDescriptor) throws java.net.SocketException;
     method public static void attachRaFilter(@NonNull java.io.FileDescriptor, int) throws java.net.SocketException;
     method public static void bindSocketToInterface(@NonNull java.io.FileDescriptor, @NonNull String) throws android.system.ErrnoException;
     method public static void closeSocket(@Nullable java.io.FileDescriptor) throws java.io.IOException;
-    method public static java.net.SocketAddress makeNetlinkSocketAddress(int, int);
-    method public static java.net.SocketAddress makePacketSocketAddress(short, int);
-    method public static java.net.SocketAddress makePacketSocketAddress(int, @NonNull byte[]);
+    method @NonNull public static java.net.SocketAddress makeNetlinkSocketAddress(int, int);
+    method @NonNull public static java.net.SocketAddress makePacketSocketAddress(int, int);
+    method @NonNull public static java.net.SocketAddress makePacketSocketAddress(int, @NonNull byte[]);
     method public static void setSocketTimeValueOption(@NonNull java.io.FileDescriptor, int, int, long) throws android.system.ErrnoException;
   }
 
@@ -2067,6 +2103,8 @@
     method @RequiresPermission(android.Manifest.permission.WRITE_DEVICE_CONFIG) public static boolean setProperty(@NonNull String, @NonNull String, @Nullable String, boolean);
     field public static final String NAMESPACE_AUTOFILL = "autofill";
     field public static final String NAMESPACE_CONTENT_CAPTURE = "content_capture";
+    field public static final String NAMESPACE_ROLLBACK = "rollback";
+    field public static final String NAMESPACE_ROLLBACK_BOOT = "rollback_boot";
   }
 
   public static interface DeviceConfig.OnPropertiesChangedListener {
@@ -2092,13 +2130,6 @@
     method @Nullable public String getString(@NonNull String, @Nullable String);
   }
 
-  public static interface DeviceConfig.Rollback {
-    field public static final String BOOT_NAMESPACE = "rollback_boot";
-    field public static final String ENABLE_ROLLBACK_TIMEOUT = "enable_rollback_timeout";
-    field public static final String NAMESPACE = "rollback";
-    field public static final String ROLLBACK_LIFETIME_IN_MILLIS = "rollback_lifetime_in_millis";
-  }
-
   public final class MediaStore {
     method @RequiresPermission(android.Manifest.permission.CLEAR_APP_USER_DATA) public static void deleteContributedMedia(android.content.Context, String, android.os.UserHandle) throws java.io.IOException;
     method @RequiresPermission(android.Manifest.permission.CLEAR_APP_USER_DATA) public static long getContributedMediaSize(android.content.Context, String, android.os.UserHandle) throws java.io.IOException;
@@ -2394,6 +2425,7 @@
     method public int getEventType();
     method public void writeToParcel(@NonNull android.os.Parcel, int);
     field @NonNull public static final android.os.Parcelable.Creator<android.service.contentcapture.ActivityEvent> CREATOR;
+    field public static final int TYPE_ACTIVITY_DESTROYED = 24; // 0x18
     field public static final int TYPE_ACTIVITY_PAUSED = 2; // 0x2
     field public static final int TYPE_ACTIVITY_RESUMED = 1; // 0x1
     field public static final int TYPE_ACTIVITY_STOPPED = 23; // 0x17
@@ -2412,6 +2444,7 @@
     method public void onUserDataRemovalRequest(@NonNull android.view.contentcapture.UserDataRemovalRequest);
     method public final void setContentCaptureWhitelist(@Nullable java.util.Set<java.lang.String>, @Nullable java.util.Set<android.content.ComponentName>);
     field public static final String SERVICE_INTERFACE = "android.service.contentcapture.ContentCaptureService";
+    field public static final String SERVICE_META_DATA = "android.content_capture";
   }
 
   public final class SnapshotData implements android.os.Parcelable {
@@ -2548,7 +2581,8 @@
     method public int getCarrierIdListVersion();
     method public android.util.Pair<java.lang.Integer,java.lang.Integer> getRadioHalVersion();
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void refreshUiccProfile();
-    method public void setCarrierTestOverride(String, String, String, String, String, String, String);
+    method @Deprecated public void setCarrierTestOverride(String, String, String, String, String, String, String);
+    method public void setCarrierTestOverride(String, String, String, String, String, String, String, String, String);
     field public static final int CARRIER_PRIVILEGE_STATUS_ERROR_LOADING_RULES = -2; // 0xfffffffe
     field public static final int CARRIER_PRIVILEGE_STATUS_HAS_ACCESS = 1; // 0x1
     field public static final int CARRIER_PRIVILEGE_STATUS_NO_ACCESS = 0; // 0x0
@@ -3169,25 +3203,21 @@
 
 package android.view.inspector {
 
-  @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) @java.lang.annotation.Target({java.lang.annotation.ElementType.TYPE}) public @interface InspectableNodeName {
-    method public abstract String value();
-  }
-
   @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) @java.lang.annotation.Target({java.lang.annotation.ElementType.METHOD, java.lang.annotation.ElementType.FIELD}) public @interface InspectableProperty {
     method public abstract int attributeId() default android.content.res.Resources.ID_NULL;
-    method public abstract android.view.inspector.InspectableProperty.EnumMap[] enumMapping() default {};
-    method public abstract android.view.inspector.InspectableProperty.FlagMap[] flagMapping() default {};
+    method public abstract android.view.inspector.InspectableProperty.EnumEntry[] enumMapping() default {};
+    method public abstract android.view.inspector.InspectableProperty.FlagEntry[] flagMapping() default {};
     method public abstract boolean hasAttributeId() default true;
     method public abstract String name() default "";
     method public abstract android.view.inspector.InspectableProperty.ValueType valueType() default android.view.inspector.InspectableProperty.ValueType.INFERRED;
   }
 
-  @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) @java.lang.annotation.Target({java.lang.annotation.ElementType.TYPE}) public static @interface InspectableProperty.EnumMap {
+  @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) @java.lang.annotation.Target({java.lang.annotation.ElementType.TYPE}) public static @interface InspectableProperty.EnumEntry {
     method public abstract String name();
     method public abstract int value();
   }
 
-  @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) @java.lang.annotation.Target({java.lang.annotation.ElementType.TYPE}) public static @interface InspectableProperty.FlagMap {
+  @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) @java.lang.annotation.Target({java.lang.annotation.ElementType.TYPE}) public static @interface InspectableProperty.FlagEntry {
     method public abstract int mask() default 0;
     method public abstract String name();
     method public abstract int target();
@@ -3216,7 +3246,7 @@
   }
 
   public class DatePicker extends android.widget.FrameLayout {
-    method @android.view.inspector.InspectableProperty(name="datePickerMode", enumMapping={@android.view.inspector.InspectableProperty.EnumMap(value=android.widget.DatePicker.MODE_SPINNER, name="spinner"), @android.view.inspector.InspectableProperty.EnumMap(value=android.widget.DatePicker.MODE_CALENDAR, name="calendar")}) public int getMode();
+    method @android.view.inspector.InspectableProperty(name="datePickerMode", enumMapping={@android.view.inspector.InspectableProperty.EnumEntry(value=android.widget.DatePicker.MODE_SPINNER, name="spinner"), @android.view.inspector.InspectableProperty.EnumEntry(value=android.widget.DatePicker.MODE_CALENDAR, name="calendar")}) public int getMode();
     field public static final int MODE_CALENDAR = 2; // 0x2
     field public static final int MODE_SPINNER = 1; // 0x1
   }
@@ -3252,7 +3282,7 @@
     method public android.view.View getAmView();
     method public android.view.View getHourView();
     method public android.view.View getMinuteView();
-    method @android.view.inspector.InspectableProperty(name="timePickerMode", enumMapping={@android.view.inspector.InspectableProperty.EnumMap(name="clock", value=android.widget.TimePicker.MODE_CLOCK), @android.view.inspector.InspectableProperty.EnumMap(name="spinner", value=android.widget.TimePicker.MODE_SPINNER)}) public int getMode();
+    method @android.view.inspector.InspectableProperty(name="timePickerMode", enumMapping={@android.view.inspector.InspectableProperty.EnumEntry(name="clock", value=android.widget.TimePicker.MODE_CLOCK), @android.view.inspector.InspectableProperty.EnumEntry(name="spinner", value=android.widget.TimePicker.MODE_SPINNER)}) public int getMode();
     method public android.view.View getPmView();
     field public static final int MODE_CLOCK = 2; // 0x2
     field public static final int MODE_SPINNER = 1; // 0x1
diff --git a/cmds/idmap2/idmap2/Commands.h b/cmds/idmap2/idmap2/Commands.h
index dcc69b3..718e361 100644
--- a/cmds/idmap2/idmap2/Commands.h
+++ b/cmds/idmap2/idmap2/Commands.h
@@ -20,10 +20,12 @@
 #include <string>
 #include <vector>
 
-bool Create(const std::vector<std::string>& args, std::ostream& out_error);
-bool Dump(const std::vector<std::string>& args, std::ostream& out_error);
-bool Lookup(const std::vector<std::string>& args, std::ostream& out_error);
-bool Scan(const std::vector<std::string>& args, std::ostream& out_error);
-bool Verify(const std::vector<std::string>& args, std::ostream& out_error);
+#include "idmap2/Result.h"
+
+android::idmap2::Result<android::idmap2::Unit> Create(const std::vector<std::string>& args);
+android::idmap2::Result<android::idmap2::Unit> Dump(const std::vector<std::string>& args);
+android::idmap2::Result<android::idmap2::Unit> Lookup(const std::vector<std::string>& args);
+android::idmap2::Result<android::idmap2::Unit> Scan(const std::vector<std::string>& args);
+android::idmap2::Result<android::idmap2::Unit> Verify(const std::vector<std::string>& args);
 
 #endif  // IDMAP2_IDMAP2_COMMANDS_H_
diff --git a/cmds/idmap2/idmap2/Create.cpp b/cmds/idmap2/idmap2/Create.cpp
index c416fa1..47617e0 100644
--- a/cmds/idmap2/idmap2/Create.cpp
+++ b/cmds/idmap2/idmap2/Create.cpp
@@ -33,14 +33,17 @@
 using android::ApkAssets;
 using android::idmap2::BinaryStreamVisitor;
 using android::idmap2::CommandLineOptions;
+using android::idmap2::Error;
 using android::idmap2::Idmap;
 using android::idmap2::PoliciesToBitmask;
 using android::idmap2::PolicyBitmask;
 using android::idmap2::PolicyFlags;
+using android::idmap2::Result;
+using android::idmap2::Unit;
 using android::idmap2::utils::kIdmapFilePermissionMask;
 using android::idmap2::utils::UidHasWriteAccessToPath;
 
-bool Create(const std::vector<std::string>& args, std::ostream& out_error) {
+Result<Unit> Create(const std::vector<std::string>& args) {
   SYSTRACE << "Create " << args;
   std::string target_apk_path;
   std::string overlay_apk_path;
@@ -63,15 +66,14 @@
                           &policies)
           .OptionalFlag("--ignore-overlayable", "disables overlayable and policy checks",
                         &ignore_overlayable);
-  if (!opts.Parse(args, out_error)) {
-    return false;
+  const auto opts_ok = opts.Parse(args);
+  if (!opts_ok) {
+    return opts_ok.GetError();
   }
 
   const uid_t uid = getuid();
   if (!UidHasWriteAccessToPath(uid, idmap_path)) {
-    out_error << "error: uid " << uid << " does not have write access to " << idmap_path
-              << std::endl;
-    return false;
+    return Error("uid %d does not have write access to %s", uid, idmap_path.c_str());
   }
 
   PolicyBitmask fulfilled_policies = 0;
@@ -79,8 +81,7 @@
   if (conv_result) {
     fulfilled_policies |= *conv_result;
   } else {
-    out_error << "error: " << conv_result.GetErrorMessage() << std::endl;
-    return false;
+    return conv_result.GetError();
   }
 
   if (fulfilled_policies == 0) {
@@ -89,36 +90,31 @@
 
   const std::unique_ptr<const ApkAssets> target_apk = ApkAssets::Load(target_apk_path);
   if (!target_apk) {
-    out_error << "error: failed to load apk " << target_apk_path << std::endl;
-    return false;
+    return Error("failed to load apk %s", target_apk_path.c_str());
   }
 
   const std::unique_ptr<const ApkAssets> overlay_apk = ApkAssets::Load(overlay_apk_path);
   if (!overlay_apk) {
-    out_error << "error: failed to load apk " << overlay_apk_path << std::endl;
-    return false;
+    return Error("failed to load apk %s", overlay_apk_path.c_str());
   }
 
-  const std::unique_ptr<const Idmap> idmap =
-      Idmap::FromApkAssets(target_apk_path, *target_apk, overlay_apk_path, *overlay_apk,
-                           fulfilled_policies, !ignore_overlayable, out_error);
+  const auto idmap = Idmap::FromApkAssets(target_apk_path, *target_apk, overlay_apk_path,
+                                          *overlay_apk, fulfilled_policies, !ignore_overlayable);
   if (!idmap) {
-    return false;
+    return Error(idmap.GetError(), "failed to create idmap");
   }
 
   umask(kIdmapFilePermissionMask);
   std::ofstream fout(idmap_path);
   if (fout.fail()) {
-    out_error << "failed to open idmap path " << idmap_path << std::endl;
-    return false;
+    return Error("failed to open idmap path %s", idmap_path.c_str());
   }
   BinaryStreamVisitor visitor(fout);
-  idmap->accept(&visitor);
+  (*idmap)->accept(&visitor);
   fout.close();
   if (fout.fail()) {
-    out_error << "failed to write to idmap path " << idmap_path << std::endl;
-    return false;
+    return Error("failed to write to idmap path %s", idmap_path.c_str());
   }
 
-  return true;
+  return Unit{};
 }
diff --git a/cmds/idmap2/idmap2/Dump.cpp b/cmds/idmap2/idmap2/Dump.cpp
index 3947703..8716bf3 100644
--- a/cmds/idmap2/idmap2/Dump.cpp
+++ b/cmds/idmap2/idmap2/Dump.cpp
@@ -17,6 +17,7 @@
 #include <fstream>
 #include <iostream>
 #include <memory>
+#include <sstream>
 #include <string>
 #include <vector>
 
@@ -24,14 +25,18 @@
 #include "idmap2/Idmap.h"
 #include "idmap2/PrettyPrintVisitor.h"
 #include "idmap2/RawPrintVisitor.h"
+#include "idmap2/Result.h"
 #include "idmap2/SysTrace.h"
 
 using android::idmap2::CommandLineOptions;
+using android::idmap2::Error;
 using android::idmap2::Idmap;
 using android::idmap2::PrettyPrintVisitor;
 using android::idmap2::RawPrintVisitor;
+using android::idmap2::Result;
+using android::idmap2::Unit;
 
-bool Dump(const std::vector<std::string>& args, std::ostream& out_error) {
+Result<Unit> Dump(const std::vector<std::string>& args) {
   SYSTRACE << "Dump " << args;
   std::string idmap_path;
   bool verbose;
@@ -40,23 +45,24 @@
       CommandLineOptions("idmap2 dump")
           .MandatoryOption("--idmap-path", "input: path to idmap file to pretty-print", &idmap_path)
           .OptionalFlag("--verbose", "annotate every byte of the idmap", &verbose);
-  if (!opts.Parse(args, out_error)) {
-    return false;
+  const auto opts_ok = opts.Parse(args);
+  if (!opts_ok) {
+    return opts_ok.GetError();
   }
   std::ifstream fin(idmap_path);
-  const std::unique_ptr<const Idmap> idmap = Idmap::FromBinaryStream(fin, out_error);
+  const auto idmap = Idmap::FromBinaryStream(fin);
   fin.close();
   if (!idmap) {
-    return false;
+    return Error(idmap.GetError(), "failed to load idmap");
   }
 
   if (verbose) {
     RawPrintVisitor visitor(std::cout);
-    idmap->accept(&visitor);
+    (*idmap)->accept(&visitor);
   } else {
     PrettyPrintVisitor visitor(std::cout);
-    idmap->accept(&visitor);
+    (*idmap)->accept(&visitor);
   }
 
-  return true;
+  return Unit{};
 }
diff --git a/cmds/idmap2/idmap2/Lookup.cpp b/cmds/idmap2/idmap2/Lookup.cpp
index 83a40ef..677c6fa 100644
--- a/cmds/idmap2/idmap2/Lookup.cpp
+++ b/cmds/idmap2/idmap2/Lookup.cpp
@@ -57,6 +57,7 @@
 using android::idmap2::IdmapHeader;
 using android::idmap2::ResourceId;
 using android::idmap2::Result;
+using android::idmap2::Unit;
 using android::idmap2::Xml;
 using android::idmap2::ZipFile;
 using android::util::Utf16ToUtf8;
@@ -157,7 +158,7 @@
 }
 }  // namespace
 
-bool Lookup(const std::vector<std::string>& args, std::ostream& out_error) {
+Result<Unit> Lookup(const std::vector<std::string>& args) {
   SYSTRACE << "Lookup " << args;
   std::vector<std::string> idmap_paths;
   std::string config_str;
@@ -172,14 +173,14 @@
                            "'[package:]type/name') to look up",
                            &resid_str);
 
-  if (!opts.Parse(args, out_error)) {
-    return false;
+  const auto opts_ok = opts.Parse(args);
+  if (!opts_ok) {
+    return opts_ok.GetError();
   }
 
   ConfigDescription config;
   if (!ConfigDescription::Parse(config_str, &config)) {
-    out_error << "error: failed to parse config" << std::endl;
-    return false;
+    return Error("failed to parse config");
   }
 
   std::vector<std::unique_ptr<const ApkAssets>> apk_assets;
@@ -191,39 +192,33 @@
     auto idmap_header = IdmapHeader::FromBinaryStream(fin);
     fin.close();
     if (!idmap_header) {
-      out_error << "error: failed to read idmap from " << idmap_path << std::endl;
-      return false;
+      return Error("failed to read idmap from %s", idmap_path.c_str());
     }
 
     if (i == 0) {
       target_path = idmap_header->GetTargetPath().to_string();
       auto target_apk = ApkAssets::Load(target_path);
       if (!target_apk) {
-        out_error << "error: failed to read target apk from " << target_path << std::endl;
-        return false;
+        return Error("failed to read target apk from %s", target_path.c_str());
       }
       apk_assets.push_back(std::move(target_apk));
 
       const Result<std::string> package_name =
           GetTargetPackageNameFromManifest(idmap_header->GetOverlayPath().to_string());
       if (!package_name) {
-        out_error << "error: failed to parse android:targetPackage from overlay manifest"
-                  << std::endl;
-        return false;
+        return Error("failed to parse android:targetPackage from overlay manifest");
       }
       target_package_name = *package_name;
     } else if (target_path != idmap_header->GetTargetPath()) {
-      out_error << "error: different target APKs (expected target APK " << target_path << " but "
-                << idmap_path << " has target APK " << idmap_header->GetTargetPath() << ")"
-                << std::endl;
-      return false;
+      return Error("different target APKs (expected target APK %s but %s has target APK %s)",
+                   target_path.c_str(), idmap_path.c_str(),
+                   idmap_header->GetTargetPath().to_string().c_str());
     }
 
     auto overlay_apk = ApkAssets::LoadOverlay(idmap_path);
     if (!overlay_apk) {
-      out_error << "error: failed to read overlay apk from " << idmap_header->GetOverlayPath()
-                << std::endl;
-      return false;
+      return Error("failed to read overlay apk from %s",
+                   idmap_header->GetOverlayPath().to_string().c_str());
     }
     apk_assets.push_back(std::move(overlay_apk));
   }
@@ -238,16 +233,14 @@
 
   const Result<ResourceId> resid = ParseResReference(am, resid_str, target_package_name);
   if (!resid) {
-    out_error << "error: failed to parse resource ID" << std::endl;
-    return false;
+    return Error(resid.GetError(), "failed to parse resource ID");
   }
 
   const Result<std::string> value = GetValue(am, *resid);
   if (!value) {
-    out_error << StringPrintf("error: resource 0x%08x not found", *resid) << std::endl;
-    return false;
+    return Error(value.GetError(), "resource 0x%08x not found", *resid);
   }
   std::cout << *value << std::endl;
 
-  return true;
+  return Unit{};
 }
diff --git a/cmds/idmap2/idmap2/Main.cpp b/cmds/idmap2/idmap2/Main.cpp
index a0ffccb..d8867fe 100644
--- a/cmds/idmap2/idmap2/Main.cpp
+++ b/cmds/idmap2/idmap2/Main.cpp
@@ -24,14 +24,17 @@
 #include <vector>
 
 #include "idmap2/CommandLineOptions.h"
+#include "idmap2/Result.h"
 #include "idmap2/SysTrace.h"
 
 #include "Commands.h"
 
 using android::idmap2::CommandLineOptions;
+using android::idmap2::Result;
+using android::idmap2::Unit;
 
 using NameToFunctionMap =
-    std::map<std::string, std::function<bool(const std::vector<std::string>&, std::ostream&)>>;
+    std::map<std::string, std::function<Result<Unit>(const std::vector<std::string>&)>>;
 
 namespace {
 
@@ -69,5 +72,10 @@
     PrintUsage(commands, std::cerr);
     return EXIT_FAILURE;
   }
-  return iter->second(*args, std::cerr) ? EXIT_SUCCESS : EXIT_FAILURE;
+  const auto result = iter->second(*args);
+  if (!result) {
+    std::cerr << "error: " << result.GetErrorMessage() << std::endl;
+    return EXIT_FAILURE;
+  }
+  return EXIT_SUCCESS;
 }
diff --git a/cmds/idmap2/idmap2/Scan.cpp b/cmds/idmap2/idmap2/Scan.cpp
index e85f132..24331af 100644
--- a/cmds/idmap2/idmap2/Scan.cpp
+++ b/cmds/idmap2/idmap2/Scan.cpp
@@ -30,6 +30,7 @@
 #include "idmap2/FileUtils.h"
 #include "idmap2/Idmap.h"
 #include "idmap2/ResourceUtils.h"
+#include "idmap2/Result.h"
 #include "idmap2/SysTrace.h"
 #include "idmap2/Xml.h"
 #include "idmap2/ZipFile.h"
@@ -37,6 +38,7 @@
 #include "Commands.h"
 
 using android::idmap2::CommandLineOptions;
+using android::idmap2::Error;
 using android::idmap2::Idmap;
 using android::idmap2::kPolicyProduct;
 using android::idmap2::kPolicyPublic;
@@ -45,6 +47,7 @@
 using android::idmap2::PolicyBitmask;
 using android::idmap2::PolicyFlags;
 using android::idmap2::Result;
+using android::idmap2::Unit;
 using android::idmap2::utils::ExtractOverlayManifestInfo;
 using android::idmap2::utils::FindFiles;
 using android::idmap2::utils::OverlayManifestInfo;
@@ -69,8 +72,8 @@
   return version == "Q" || version == "q";
 }
 
-std::unique_ptr<std::vector<std::string>> FindApkFiles(const std::vector<std::string>& dirs,
-                                                       bool recursive, std::ostream& out_error) {
+Result<std::unique_ptr<std::vector<std::string>>> FindApkFiles(const std::vector<std::string>& dirs,
+                                                               bool recursive) {
   SYSTRACE << "FindApkFiles " << dirs << " " << recursive;
   const auto predicate = [](unsigned char type, const std::string& path) -> bool {
     static constexpr size_t kExtLen = 4;  // strlen(".apk")
@@ -82,8 +85,7 @@
   for (const auto& dir : dirs) {
     const auto apk_paths = FindFiles(dir, recursive, predicate);
     if (!apk_paths) {
-      out_error << "error: failed to open directory " << dir << std::endl;
-      return nullptr;
+      return Error("failed to open directory %s", dir.c_str());
     }
     paths.insert(apk_paths->cbegin(), apk_paths->cend());
   }
@@ -110,7 +112,7 @@
 
 }  // namespace
 
-bool Scan(const std::vector<std::string>& args, std::ostream& out_error) {
+Result<Unit> Scan(const std::vector<std::string>& args) {
   SYSTRACE << "Scan " << args;
   std::vector<std::string> input_directories;
   std::string target_package_name;
@@ -135,22 +137,22 @@
               "input: an overlayable policy this overlay fulfills "
               "(if none or supplied, the overlays will not have their policies overriden",
               &override_policies);
-  if (!opts.Parse(args, out_error)) {
-    return false;
+  const auto opts_ok = opts.Parse(args);
+  if (!opts_ok) {
+    return opts_ok.GetError();
   }
 
-  const auto apk_paths = FindApkFiles(input_directories, recursive, out_error);
+  const auto apk_paths = FindApkFiles(input_directories, recursive);
   if (!apk_paths) {
-    return false;
+    return Error(apk_paths.GetError(), "failed to find apk files");
   }
 
   std::vector<InputOverlay> interesting_apks;
-  for (const std::string& path : *apk_paths) {
+  for (const std::string& path : **apk_paths) {
     Result<OverlayManifestInfo> overlay_info =
         ExtractOverlayManifestInfo(path, /* assert_overlay */ false);
     if (!overlay_info) {
-      out_error << "error: " << overlay_info.GetErrorMessage() << std::endl;
-      return false;
+      return overlay_info.GetError();
     }
 
     if (!overlay_info->is_static) {
@@ -194,16 +196,13 @@
 
   std::stringstream stream;
   for (const auto& overlay : interesting_apks) {
-    // Create the idmap for the overlay if it currently does not exist or if it is not up to date.
-    std::stringstream dev_null;
-
     std::vector<std::string> verify_args = {"--idmap-path", overlay.idmap_path};
     for (const std::string& policy : overlay.policies) {
       verify_args.emplace_back("--policy");
       verify_args.emplace_back(policy);
     }
 
-    if (!Verify(std::vector<std::string>(verify_args), dev_null)) {
+    if (!Verify(std::vector<std::string>(verify_args))) {
       std::vector<std::string> create_args = {"--target-apk-path",  target_apk_path,
                                               "--overlay-apk-path", overlay.apk_path,
                                               "--idmap-path",       overlay.idmap_path};
@@ -216,8 +215,9 @@
         create_args.emplace_back(policy);
       }
 
-      if (!Create(create_args, out_error)) {
-        return false;
+      const auto create_ok = Create(create_args);
+      if (!create_ok) {
+        return Error(create_ok.GetError(), "failed to create idmap");
       }
     }
 
@@ -226,5 +226,5 @@
 
   std::cout << stream.str();
 
-  return true;
+  return Unit{};
 }
diff --git a/cmds/idmap2/idmap2/Verify.cpp b/cmds/idmap2/idmap2/Verify.cpp
index d8fe7aa..9cb67b3 100644
--- a/cmds/idmap2/idmap2/Verify.cpp
+++ b/cmds/idmap2/idmap2/Verify.cpp
@@ -21,29 +21,39 @@
 
 #include "idmap2/CommandLineOptions.h"
 #include "idmap2/Idmap.h"
+#include "idmap2/Result.h"
 #include "idmap2/SysTrace.h"
 
 using android::idmap2::CommandLineOptions;
+using android::idmap2::Error;
 using android::idmap2::IdmapHeader;
+using android::idmap2::Result;
+using android::idmap2::Unit;
 
-bool Verify(const std::vector<std::string>& args, std::ostream& out_error) {
+Result<Unit> Verify(const std::vector<std::string>& args) {
   SYSTRACE << "Verify " << args;
   std::string idmap_path;
 
   const CommandLineOptions opts =
       CommandLineOptions("idmap2 verify")
           .MandatoryOption("--idmap-path", "input: path to idmap file to verify", &idmap_path);
-  if (!opts.Parse(args, out_error)) {
-    return false;
+
+  const auto opts_ok = opts.Parse(args);
+  if (!opts_ok) {
+    return opts_ok.GetError();
   }
 
   std::ifstream fin(idmap_path);
   const std::unique_ptr<const IdmapHeader> header = IdmapHeader::FromBinaryStream(fin);
   fin.close();
   if (!header) {
-    out_error << "error: failed to parse idmap header" << std::endl;
-    return false;
+    return Error("failed to parse idmap header");
   }
 
-  return header->IsUpToDate(out_error);
+  const auto header_ok = header->IsUpToDate();
+  if (!header_ok) {
+    return Error(header_ok.GetError(), "idmap not up to date");
+  }
+
+  return Unit{};
 }
diff --git a/cmds/idmap2/idmap2d/Idmap2Service.cpp b/cmds/idmap2/idmap2d/Idmap2Service.cpp
index fa94414..4f65379 100644
--- a/cmds/idmap2/idmap2d/Idmap2Service.cpp
+++ b/cmds/idmap2/idmap2d/Idmap2Service.cpp
@@ -104,8 +104,7 @@
   std::ifstream fin(idmap_path);
   const std::unique_ptr<const IdmapHeader> header = IdmapHeader::FromBinaryStream(fin);
   fin.close();
-  std::stringstream dev_null;
-  *_aidl_return = header && header->IsUpToDate(dev_null);
+  *_aidl_return = header && header->IsUpToDate();
 
   // TODO(b/119328308): Check that the set of fulfilled policies of the overlay has not changed
 
@@ -139,12 +138,10 @@
     return error("failed to load apk " + overlay_apk_path);
   }
 
-  std::stringstream err;
-  const std::unique_ptr<const Idmap> idmap =
-      Idmap::FromApkAssets(target_apk_path, *target_apk, overlay_apk_path, *overlay_apk,
-                           policy_bitmask, enforce_overlayable, err);
+  const auto idmap = Idmap::FromApkAssets(target_apk_path, *target_apk, overlay_apk_path,
+                                          *overlay_apk, policy_bitmask, enforce_overlayable);
   if (!idmap) {
-    return error(err.str());
+    return error(idmap.GetErrorMessage());
   }
 
   umask(kIdmapFilePermissionMask);
@@ -153,7 +150,7 @@
     return error("failed to open idmap path " + idmap_path);
   }
   BinaryStreamVisitor visitor(fout);
-  idmap->accept(&visitor);
+  (*idmap)->accept(&visitor);
   fout.close();
   if (fout.fail()) {
     return error("failed to write to idmap path " + idmap_path);
diff --git a/cmds/idmap2/include/idmap2/CommandLineOptions.h b/cmds/idmap2/include/idmap2/CommandLineOptions.h
index 6db6bf9..52ac818 100644
--- a/cmds/idmap2/include/idmap2/CommandLineOptions.h
+++ b/cmds/idmap2/include/idmap2/CommandLineOptions.h
@@ -23,6 +23,8 @@
 #include <string>
 #include <vector>
 
+#include "idmap2/Result.h"
+
 namespace android::idmap2 {
 
 /*
@@ -46,7 +48,7 @@
                                      std::string* value);
   CommandLineOptions& OptionalOption(const std::string& name, const std::string& description,
                                      std::vector<std::string>* value);
-  bool Parse(const std::vector<std::string>& argv, std::ostream& outError) const;
+  Result<Unit> Parse(const std::vector<std::string>& argv) const;
   void Usage(std::ostream& out) const;
 
  private:
diff --git a/cmds/idmap2/include/idmap2/Idmap.h b/cmds/idmap2/include/idmap2/Idmap.h
index 1666dc8..5cc0664 100644
--- a/cmds/idmap2/include/idmap2/Idmap.h
+++ b/cmds/idmap2/include/idmap2/Idmap.h
@@ -115,7 +115,7 @@
   // Invariant: anytime the idmap data encoding is changed, the idmap version
   // field *must* be incremented. Because of this, we know that if the idmap
   // header is up-to-date the entire file is up-to-date.
-  bool IsUpToDate(std::ostream& out_error) const;
+  Result<Unit> IsUpToDate() const;
 
   void accept(Visitor* v) const;
 
@@ -228,17 +228,18 @@
   static std::string CanonicalIdmapPathFor(const std::string& absolute_dir,
                                            const std::string& absolute_apk_path);
 
-  static std::unique_ptr<const Idmap> FromBinaryStream(std::istream& stream,
-                                                       std::ostream& out_error);
+  static Result<std::unique_ptr<const Idmap>> FromBinaryStream(std::istream& stream);
 
   // In the current version of idmap, the first package in each resources.arsc
   // file is used; change this in the next version of idmap to use a named
   // package instead; also update FromApkAssets to take additional parameters:
   // the target and overlay package names
-  static std::unique_ptr<const Idmap> FromApkAssets(
-      const std::string& target_apk_path, const ApkAssets& target_apk_assets,
-      const std::string& overlay_apk_path, const ApkAssets& overlay_apk_assets,
-      const PolicyBitmask& fulfilled_policies, bool enforce_overlayable, std::ostream& out_error);
+  static Result<std::unique_ptr<const Idmap>> FromApkAssets(const std::string& target_apk_path,
+                                                            const ApkAssets& target_apk_assets,
+                                                            const std::string& overlay_apk_path,
+                                                            const ApkAssets& overlay_apk_assets,
+                                                            const PolicyBitmask& fulfilled_policies,
+                                                            bool enforce_overlayable);
 
   inline const std::unique_ptr<const IdmapHeader>& GetHeader() const {
     return header_;
diff --git a/cmds/idmap2/libidmap2/CommandLineOptions.cpp b/cmds/idmap2/libidmap2/CommandLineOptions.cpp
index a49a607..d5fd2ce 100644
--- a/cmds/idmap2/libidmap2/CommandLineOptions.cpp
+++ b/cmds/idmap2/libidmap2/CommandLineOptions.cpp
@@ -19,12 +19,14 @@
 #include <iostream>
 #include <memory>
 #include <set>
+#include <sstream>
 #include <string>
 #include <vector>
 
 #include "android-base/macros.h"
 
 #include "idmap2/CommandLineOptions.h"
+#include "idmap2/Result.h"
 
 namespace android::idmap2 {
 
@@ -77,7 +79,7 @@
   return *this;
 }
 
-bool CommandLineOptions::Parse(const std::vector<std::string>& argv, std::ostream& outError) const {
+Result<Unit> CommandLineOptions::Parse(const std::vector<std::string>& argv) const {
   const auto pivot = std::partition(options_.begin(), options_.end(), [](const Option& opt) {
     return opt.count != Option::COUNT_OPTIONAL && opt.count != Option::COUNT_OPTIONAL_ONCE_OR_MORE;
   });
@@ -89,8 +91,9 @@
   for (size_t i = 0; i < argv_size; i++) {
     const std::string arg = argv[i];
     if ("--help" == arg || "-h" == arg) {
-      Usage(outError);
-      return false;
+      std::stringstream stream;
+      Usage(stream);
+      return Error("%s", stream.str().c_str());
     }
     bool match = false;
     for (const Option& opt : options_) {
@@ -100,9 +103,9 @@
         if (opt.argument) {
           i++;
           if (i >= argv_size) {
-            outError << "error: " << opt.name << ": missing argument" << std::endl;
-            Usage(outError);
-            return false;
+            std::stringstream stream;
+            Usage(stream);
+            return Error("%s: missing argument\n%s", opt.name.c_str(), stream.str().c_str());
           }
         }
         opt.action(argv[i]);
@@ -111,20 +114,27 @@
       }
     }
     if (!match) {
-      outError << "error: " << arg << ": unknown option" << std::endl;
-      Usage(outError);
-      return false;
+      std::stringstream stream;
+      Usage(stream);
+      return Error("%s: unknown option\n%s", arg.c_str(), stream.str().c_str());
     }
   }
 
   if (!mandatory_opts.empty()) {
+    std::stringstream stream;
+    bool separator = false;
     for (const auto& opt : mandatory_opts) {
-      outError << "error: " << opt << ": missing mandatory option" << std::endl;
+      if (separator) {
+        stream << ", ";
+      }
+      separator = true;
+      stream << opt << ": missing mandatory option";
     }
-    Usage(outError);
-    return false;
+    stream << std::endl;
+    Usage(stream);
+    return Error("%s", stream.str().c_str());
   }
-  return true;
+  return Unit{};
 }
 
 void CommandLineOptions::Usage(std::ostream& out) const {
diff --git a/cmds/idmap2/libidmap2/Idmap.cpp b/cmds/idmap2/libidmap2/Idmap.cpp
index a7d180c..6d5fe7b 100644
--- a/cmds/idmap2/libidmap2/Idmap.cpp
+++ b/cmds/idmap2/libidmap2/Idmap.cpp
@@ -56,7 +56,7 @@
   }
 
   inline const std::map<TypeId, std::set<std::pair<ResourceId, ResourceId>>>& WARN_UNUSED
-      Map() const {
+  Map() const {
     return map_;
   }
 
@@ -124,7 +124,7 @@
   const Result<uint32_t> b = zip.Crc("AndroidManifest.xml");
   return a && b
              ? Result<uint32_t>(*a ^ *b)
-             : Error("Couldn't get CRC for \"%s\"", a ? "AndroidManifest.xml" : "resources.arsc");
+             : Error("failed to get CRC for \"%s\"", a ? "AndroidManifest.xml" : "resources.arsc");
 }
 
 }  // namespace
@@ -142,62 +142,46 @@
   return std::move(idmap_header);
 }
 
-bool IdmapHeader::IsUpToDate(std::ostream& out_error) const {
+Result<Unit> IdmapHeader::IsUpToDate() const {
   if (magic_ != kIdmapMagic) {
-    out_error << base::StringPrintf("error: bad magic: actual 0x%08x, expected 0x%08x", magic_,
-                                    kIdmapMagic)
-              << std::endl;
-    return false;
+    return Error("bad magic: actual 0x%08x, expected 0x%08x", magic_, kIdmapMagic);
   }
 
   if (version_ != kIdmapCurrentVersion) {
-    out_error << base::StringPrintf("error: bad version: actual 0x%08x, expected 0x%08x", version_,
-                                    kIdmapCurrentVersion)
-              << std::endl;
-    return false;
+    return Error("bad version: actual 0x%08x, expected 0x%08x", version_, kIdmapCurrentVersion);
   }
 
   const std::unique_ptr<const ZipFile> target_zip = ZipFile::Open(target_path_);
   if (!target_zip) {
-    out_error << "error: failed to open target " << target_path_ << std::endl;
-    return false;
+    return Error("failed to open target %s", GetTargetPath().to_string().c_str());
   }
 
   Result<uint32_t> target_crc = GetCrc(*target_zip);
   if (!target_crc) {
-    out_error << "error: failed to get target crc" << std::endl;
-    return false;
+    return Error("failed to get target crc");
   }
 
   if (target_crc_ != *target_crc) {
-    out_error << base::StringPrintf(
-                     "error: bad target crc: idmap version 0x%08x, file system version 0x%08x",
-                     target_crc_, *target_crc)
-              << std::endl;
-    return false;
+    return Error("bad target crc: idmap version 0x%08x, file system version 0x%08x", target_crc_,
+                 *target_crc);
   }
 
   const std::unique_ptr<const ZipFile> overlay_zip = ZipFile::Open(overlay_path_);
   if (!overlay_zip) {
-    out_error << "error: failed to open overlay " << overlay_path_ << std::endl;
-    return false;
+    return Error("failed to open overlay %s", GetOverlayPath().to_string().c_str());
   }
 
   Result<uint32_t> overlay_crc = GetCrc(*overlay_zip);
   if (!overlay_crc) {
-    out_error << "error: failed to get overlay crc" << std::endl;
-    return false;
+    return Error("failed to get overlay crc");
   }
 
   if (overlay_crc_ != *overlay_crc) {
-    out_error << base::StringPrintf(
-                     "error: bad overlay crc: idmap version 0x%08x, file system version 0x%08x",
-                     overlay_crc_, *overlay_crc)
-              << std::endl;
-    return false;
+    return Error("bad overlay crc: idmap version 0x%08x, file system version 0x%08x", overlay_crc_,
+                 *overlay_crc);
   }
 
-  return true;
+  return Unit{};
 }
 
 std::unique_ptr<const IdmapData::Header> IdmapData::Header::FromBinaryStream(std::istream& stream) {
@@ -260,15 +244,13 @@
   return absolute_dir + "/" + copy + "@idmap";
 }
 
-std::unique_ptr<const Idmap> Idmap::FromBinaryStream(std::istream& stream,
-                                                     std::ostream& out_error) {
+Result<std::unique_ptr<const Idmap>> Idmap::FromBinaryStream(std::istream& stream) {
   SYSTRACE << "Idmap::FromBinaryStream";
   std::unique_ptr<Idmap> idmap(new Idmap());
 
   idmap->header_ = IdmapHeader::FromBinaryStream(stream);
   if (!idmap->header_) {
-    out_error << "error: failed to parse idmap header" << std::endl;
-    return nullptr;
+    return Error("failed to parse idmap header");
   }
 
   // idmap version 0x01 does not specify the number of data blocks that follow
@@ -276,13 +258,12 @@
   for (int i = 0; i < 1; i++) {
     std::unique_ptr<const IdmapData> data = IdmapData::FromBinaryStream(stream);
     if (!data) {
-      out_error << "error: failed to parse data block " << i << std::endl;
-      return nullptr;
+      return Error("failed to parse data block %d", i);
     }
     idmap->data_.push_back(std::move(data));
   }
 
-  return std::move(idmap);
+  return {std::move(idmap)};
 }
 
 std::string ConcatPolicies(const std::vector<std::string>& policies) {
@@ -339,63 +320,56 @@
   return Result<Unit>({});
 }
 
-std::unique_ptr<const Idmap> Idmap::FromApkAssets(
-    const std::string& target_apk_path, const ApkAssets& target_apk_assets,
-    const std::string& overlay_apk_path, const ApkAssets& overlay_apk_assets,
-    const PolicyBitmask& fulfilled_policies, bool enforce_overlayable, std::ostream& out_error) {
+Result<std::unique_ptr<const Idmap>> Idmap::FromApkAssets(const std::string& target_apk_path,
+                                                          const ApkAssets& target_apk_assets,
+                                                          const std::string& overlay_apk_path,
+                                                          const ApkAssets& overlay_apk_assets,
+                                                          const PolicyBitmask& fulfilled_policies,
+                                                          bool enforce_overlayable) {
   SYSTRACE << "Idmap::FromApkAssets";
   AssetManager2 target_asset_manager;
   if (!target_asset_manager.SetApkAssets({&target_apk_assets}, true, false)) {
-    out_error << "error: failed to create target asset manager" << std::endl;
-    return nullptr;
+    return Error("failed to create target asset manager");
   }
 
   AssetManager2 overlay_asset_manager;
   if (!overlay_asset_manager.SetApkAssets({&overlay_apk_assets}, true, false)) {
-    out_error << "error: failed to create overlay asset manager" << std::endl;
-    return nullptr;
+    return Error("failed to create overlay asset manager");
   }
 
   const LoadedArsc* target_arsc = target_apk_assets.GetLoadedArsc();
   if (target_arsc == nullptr) {
-    out_error << "error: failed to load target resources.arsc" << std::endl;
-    return nullptr;
+    return Error("failed to load target resources.arsc");
   }
 
   const LoadedArsc* overlay_arsc = overlay_apk_assets.GetLoadedArsc();
   if (overlay_arsc == nullptr) {
-    out_error << "error: failed to load overlay resources.arsc" << std::endl;
-    return nullptr;
+    return Error("failed to load overlay resources.arsc");
   }
 
   const LoadedPackage* target_pkg = GetPackageAtIndex0(*target_arsc);
   if (target_pkg == nullptr) {
-    out_error << "error: failed to load target package from resources.arsc" << std::endl;
-    return nullptr;
+    return Error("failed to load target package from resources.arsc");
   }
 
   const LoadedPackage* overlay_pkg = GetPackageAtIndex0(*overlay_arsc);
   if (overlay_pkg == nullptr) {
-    out_error << "error: failed to load overlay package from resources.arsc" << std::endl;
-    return nullptr;
+    return Error("failed to load overlay package from resources.arsc");
   }
 
   const std::unique_ptr<const ZipFile> target_zip = ZipFile::Open(target_apk_path);
   if (!target_zip) {
-    out_error << "error: failed to open target as zip" << std::endl;
-    return nullptr;
+    return Error("failed to open target as zip");
   }
 
   const std::unique_ptr<const ZipFile> overlay_zip = ZipFile::Open(overlay_apk_path);
   if (!overlay_zip) {
-    out_error << "error: failed to open overlay as zip" << std::endl;
-    return nullptr;
+    return Error("failed to open overlay as zip");
   }
 
   auto overlay_info = utils::ExtractOverlayManifestInfo(overlay_apk_path);
   if (!overlay_info) {
-    out_error << "error: " << overlay_info.GetErrorMessage() << std::endl;
-    return nullptr;
+    return overlay_info.GetError();
   }
 
   std::unique_ptr<IdmapHeader> header(new IdmapHeader());
@@ -404,30 +378,26 @@
 
   Result<uint32_t> crc = GetCrc(*target_zip);
   if (!crc) {
-    out_error << "error: failed to get zip crc for target" << std::endl;
-    return nullptr;
+    return Error(crc.GetError(), "failed to get zip CRC for target");
   }
   header->target_crc_ = *crc;
 
   crc = GetCrc(*overlay_zip);
   if (!crc) {
-    out_error << "error: failed to get zip crc for overlay" << std::endl;
-    return nullptr;
+    return Error(crc.GetError(), "failed to get zip CRC for overlay");
   }
   header->overlay_crc_ = *crc;
 
   if (target_apk_path.size() > sizeof(header->target_path_)) {
-    out_error << "error: target apk path \"" << target_apk_path << "\" longer that maximum size "
-              << sizeof(header->target_path_) << std::endl;
-    return nullptr;
+    return Error("target apk path \"%s\" longer than maximum size %zu", target_apk_path.c_str(),
+                 sizeof(header->target_path_));
   }
   memset(header->target_path_, 0, sizeof(header->target_path_));
   memcpy(header->target_path_, target_apk_path.data(), target_apk_path.size());
 
   if (overlay_apk_path.size() > sizeof(header->overlay_path_)) {
-    out_error << "error: overlay apk path \"" << overlay_apk_path << "\" longer that maximum size "
-              << sizeof(header->overlay_path_) << std::endl;
-    return nullptr;
+    return Error("overlay apk path \"%s\" longer than maximum size %zu", target_apk_path.c_str(),
+                 sizeof(header->target_path_));
   }
   memset(header->overlay_path_, 0, sizeof(header->overlay_path_));
   memcpy(header->overlay_path_, overlay_apk_path.data(), overlay_apk_path.size());
@@ -452,7 +422,7 @@
       continue;
     }
 
-    if (!enforce_overlayable) {
+    if (enforce_overlayable) {
       Result<Unit> success =
           CheckOverlayable(*target_pkg, *overlay_info, fulfilled_policies, target_resid);
       if (!success) {
@@ -467,9 +437,8 @@
   }
 
   if (matching_resources.Map().empty()) {
-    out_error << "overlay \"" << overlay_apk_path << "\" does not successfully overlay any resource"
-              << std::endl;
-    return nullptr;
+    return Error("overlay \"%s\" does not successfully overlay any resource",
+                 overlay_apk_path.c_str());
   }
 
   // encode idmap data
@@ -500,7 +469,7 @@
 
   idmap->data_.push_back(std::move(data));
 
-  return std::move(idmap);
+  return {std::move(idmap)};
 }
 
 void IdmapHeader::accept(Visitor* v) const {
diff --git a/cmds/idmap2/tests/BinaryStreamVisitorTests.cpp b/cmds/idmap2/tests/BinaryStreamVisitorTests.cpp
index 9a0412e..9a5b633 100644
--- a/cmds/idmap2/tests/BinaryStreamVisitorTests.cpp
+++ b/cmds/idmap2/tests/BinaryStreamVisitorTests.cpp
@@ -17,6 +17,7 @@
 #include <memory>
 #include <sstream>
 #include <string>
+#include <utility>
 
 #include "gmock/gmock.h"
 #include "gtest/gtest.h"
@@ -37,16 +38,17 @@
   std::string raw(reinterpret_cast<const char*>(idmap_raw_data), idmap_raw_data_len);
   std::istringstream raw_stream(raw);
 
-  std::stringstream error;
-  std::unique_ptr<const Idmap> idmap1 = Idmap::FromBinaryStream(raw_stream, error);
-  ASSERT_THAT(idmap1, NotNull());
+  auto result1 = Idmap::FromBinaryStream(raw_stream);
+  ASSERT_TRUE(result1);
+  const auto idmap1 = std::move(*result1);
 
   std::stringstream stream;
   BinaryStreamVisitor visitor(stream);
   idmap1->accept(&visitor);
 
-  std::unique_ptr<const Idmap> idmap2 = Idmap::FromBinaryStream(stream, error);
-  ASSERT_THAT(idmap2, NotNull());
+  auto result2 = Idmap::FromBinaryStream(stream);
+  ASSERT_TRUE(result2);
+  const auto idmap2 = std::move(*result2);
 
   ASSERT_EQ(idmap1->GetHeader()->GetTargetCrc(), idmap2->GetHeader()->GetTargetCrc());
   ASSERT_EQ(idmap1->GetHeader()->GetTargetPath(), idmap2->GetHeader()->GetTargetPath());
@@ -76,15 +78,14 @@
   std::unique_ptr<const ApkAssets> overlay_apk = ApkAssets::Load(overlay_apk_path);
   ASSERT_THAT(overlay_apk, NotNull());
 
-  std::stringstream error;
-  std::unique_ptr<const Idmap> idmap =
+  const auto idmap =
       Idmap::FromApkAssets(target_apk_path, *target_apk, overlay_apk_path, *overlay_apk,
-                           PolicyFlags::POLICY_PUBLIC, /* enforce_overlayable */ true, error);
-  ASSERT_THAT(idmap, NotNull());
+                           PolicyFlags::POLICY_PUBLIC, /* enforce_overlayable */ true);
+  ASSERT_TRUE(idmap);
 
   std::stringstream stream;
   BinaryStreamVisitor visitor(stream);
-  idmap->accept(&visitor);
+  (*idmap)->accept(&visitor);
   const std::string str = stream.str();
   const StringPiece data(str);
   std::unique_ptr<const LoadedIdmap> loaded_idmap = LoadedIdmap::Load(data);
diff --git a/cmds/idmap2/tests/CommandLineOptionsTests.cpp b/cmds/idmap2/tests/CommandLineOptionsTests.cpp
index 39f18d3..d567af6 100644
--- a/cmds/idmap2/tests/CommandLineOptionsTests.cpp
+++ b/cmds/idmap2/tests/CommandLineOptionsTests.cpp
@@ -46,14 +46,13 @@
   CommandLineOptions opts =
       CommandLineOptions("test").OptionalFlag("--foo", "", &foo).OptionalFlag("--bar", "", &bar);
 
-  std::ostream fakeStdErr(nullptr);
-  bool success = opts.Parse({"--foo", "--bar"}, fakeStdErr);
+  auto success = opts.Parse({"--foo", "--bar"});
   ASSERT_TRUE(success);
   ASSERT_TRUE(foo);
   ASSERT_TRUE(bar);
 
   foo = bar = false;
-  success = opts.Parse({"--foo"}, fakeStdErr);
+  success = opts.Parse({"--foo"});
   ASSERT_TRUE(success);
   ASSERT_TRUE(foo);
   ASSERT_FALSE(bar);
@@ -65,21 +64,19 @@
   CommandLineOptions opts = CommandLineOptions("test")
                                 .MandatoryOption("--foo", "", &foo)
                                 .MandatoryOption("--bar", "", &bar);
-  std::ostream fakeStdErr(nullptr);
-  bool success = opts.Parse({"--foo", "FOO", "--bar", "BAR"}, fakeStdErr);
+  auto success = opts.Parse({"--foo", "FOO", "--bar", "BAR"});
   ASSERT_TRUE(success);
   ASSERT_EQ(foo, "FOO");
   ASSERT_EQ(bar, "BAR");
 
-  success = opts.Parse({"--foo"}, fakeStdErr);
+  success = opts.Parse({"--foo"});
   ASSERT_FALSE(success);
 }
 
 TEST(CommandLineOptionsTests, MandatoryOptionMultipleArgsButExpectedOnce) {
   std::string foo;
   CommandLineOptions opts = CommandLineOptions("test").MandatoryOption("--foo", "", &foo);
-  std::ostream fakeStdErr(nullptr);
-  bool success = opts.Parse({"--foo", "FIRST", "--foo", "SECOND"}, fakeStdErr);
+  auto success = opts.Parse({"--foo", "FIRST", "--foo", "SECOND"});
   ASSERT_TRUE(success);
   ASSERT_EQ(foo, "SECOND");
 }
@@ -87,8 +84,7 @@
 TEST(CommandLineOptionsTests, MandatoryOptionMultipleArgsAndExpectedOnceOrMore) {
   std::vector<std::string> args;
   CommandLineOptions opts = CommandLineOptions("test").MandatoryOption("--foo", "", &args);
-  std::ostream fakeStdErr(nullptr);
-  bool success = opts.Parse({"--foo", "FOO", "--foo", "BAR"}, fakeStdErr);
+  auto success = opts.Parse({"--foo", "FOO", "--foo", "BAR"});
   ASSERT_TRUE(success);
   ASSERT_EQ(args.size(), 2U);
   ASSERT_EQ(args[0], "FOO");
@@ -101,23 +97,22 @@
   CommandLineOptions opts = CommandLineOptions("test")
                                 .OptionalOption("--foo", "", &foo)
                                 .OptionalOption("--bar", "", &bar);
-  std::ostream fakeStdErr(nullptr);
-  bool success = opts.Parse({"--foo", "FOO", "--bar", "BAR"}, fakeStdErr);
+  auto success = opts.Parse({"--foo", "FOO", "--bar", "BAR"});
   ASSERT_TRUE(success);
   ASSERT_EQ(foo, "FOO");
   ASSERT_EQ(bar, "BAR");
 
-  success = opts.Parse({"--foo", "BAZ"}, fakeStdErr);
+  success = opts.Parse({"--foo", "BAZ"});
   ASSERT_TRUE(success);
   ASSERT_EQ(foo, "BAZ");
 
-  success = opts.Parse({"--foo"}, fakeStdErr);
+  success = opts.Parse({"--foo"});
   ASSERT_FALSE(success);
 
-  success = opts.Parse({"--foo", "--bar", "BAR"}, fakeStdErr);
+  success = opts.Parse({"--foo", "--bar", "BAR"});
   ASSERT_FALSE(success);
 
-  success = opts.Parse({"--foo", "FOO", "--bar"}, fakeStdErr);
+  success = opts.Parse({"--foo", "FOO", "--bar"});
   ASSERT_FALSE(success);
 }
 
@@ -127,8 +122,7 @@
   CommandLineOptions opts = CommandLineOptions("test")
                                 .OptionalOption("--foo", "", &foo)
                                 .OptionalOption("--bar", "", &bar);
-  std::ostream fakeStdErr(nullptr);
-  bool success = opts.Parse({"--foo", "FOO", "--bar", "BAR"}, fakeStdErr);
+  auto success = opts.Parse({"--foo", "FOO", "--bar", "BAR"});
   ASSERT_TRUE(success);
   ASSERT_EQ(foo.size(), 1U);
   ASSERT_EQ(foo[0], "FOO");
@@ -137,7 +131,7 @@
 
   foo.clear();
   bar.clear();
-  success = opts.Parse({"--foo", "BAZ"}, fakeStdErr);
+  success = opts.Parse({"--foo", "BAZ"});
   ASSERT_TRUE(success);
   ASSERT_EQ(foo.size(), 1U);
   ASSERT_EQ(foo[0], "BAZ");
@@ -145,8 +139,7 @@
 
   foo.clear();
   bar.clear();
-  success =
-      opts.Parse({"--foo", "BAZ", "--foo", "BIZ", "--bar", "FIZ", "--bar", "FUZZ"}, fakeStdErr);
+  success = opts.Parse({"--foo", "BAZ", "--foo", "BIZ", "--bar", "FIZ", "--bar", "FUZZ"});
   ASSERT_TRUE(success);
   ASSERT_EQ(foo.size(), 2U);
   ASSERT_EQ(foo[0], "BAZ");
@@ -157,17 +150,17 @@
 
   foo.clear();
   bar.clear();
-  success = opts.Parse({"--foo"}, fakeStdErr);
+  success = opts.Parse({"--foo"});
   ASSERT_FALSE(success);
 
   foo.clear();
   bar.clear();
-  success = opts.Parse({"--foo", "--bar", "BAR"}, fakeStdErr);
+  success = opts.Parse({"--foo", "--bar", "BAR"});
   ASSERT_FALSE(success);
 
   foo.clear();
   bar.clear();
-  success = opts.Parse({"--foo", "FOO", "--bar"}, fakeStdErr);
+  success = opts.Parse({"--foo", "FOO", "--bar"});
   ASSERT_FALSE(success);
 }
 
@@ -179,14 +172,13 @@
                                 .MandatoryOption("--foo", "", &foo)
                                 .OptionalFlag("--baz", "", &baz)
                                 .OptionalOption("--bar", "", &bar);
-  std::ostream fakeStdErr(nullptr);
-  bool success = opts.Parse({"--unexpected"}, fakeStdErr);
+  auto success = opts.Parse({"--unexpected"});
   ASSERT_FALSE(success);
 
-  success = opts.Parse({"--bar", "BAR"}, fakeStdErr);
+  success = opts.Parse({"--bar", "BAR"});
   ASSERT_FALSE(success);
 
-  success = opts.Parse({"--baz", "--foo", "FOO"}, fakeStdErr);
+  success = opts.Parse({"--baz", "--foo", "FOO"});
   ASSERT_TRUE(success);
   ASSERT_TRUE(baz);
   ASSERT_EQ(foo, "FOO");
diff --git a/cmds/idmap2/tests/Idmap2BinaryTests.cpp b/cmds/idmap2/tests/Idmap2BinaryTests.cpp
index a6a2ada..91bc4dd 100644
--- a/cmds/idmap2/tests/Idmap2BinaryTests.cpp
+++ b/cmds/idmap2/tests/Idmap2BinaryTests.cpp
@@ -100,13 +100,12 @@
   struct stat st;
   ASSERT_EQ(stat(GetIdmapPath().c_str(), &st), 0);
 
-  std::stringstream error;
   std::ifstream fin(GetIdmapPath());
-  std::unique_ptr<const Idmap> idmap = Idmap::FromBinaryStream(fin, error);
+  const auto idmap = Idmap::FromBinaryStream(fin);
   fin.close();
 
-  ASSERT_THAT(idmap, NotNull());
-  ASSERT_IDMAP(*idmap, GetTargetApkPath(), GetOverlayApkPath());
+  ASSERT_TRUE(idmap);
+  ASSERT_IDMAP(**idmap, GetTargetApkPath(), GetOverlayApkPath());
 
   unlink(GetIdmapPath().c_str());
 }
@@ -193,24 +192,23 @@
   expected << idmap_static_2_path << std::endl;
   ASSERT_EQ(result->stdout, expected.str());
 
-  std::stringstream error;
   auto idmap_static_no_name_raw_string = utils::ReadFile(idmap_static_no_name_path);
   auto idmap_static_no_name_raw_stream = std::istringstream(*idmap_static_no_name_raw_string);
-  auto idmap_static_no_name = Idmap::FromBinaryStream(idmap_static_no_name_raw_stream, error);
-  ASSERT_THAT(idmap_static_no_name, NotNull());
-  ASSERT_IDMAP(*idmap_static_no_name, GetTargetApkPath(), overlay_static_no_name_apk_path);
+  auto idmap_static_no_name = Idmap::FromBinaryStream(idmap_static_no_name_raw_stream);
+  ASSERT_TRUE(idmap_static_no_name);
+  ASSERT_IDMAP(**idmap_static_no_name, GetTargetApkPath(), overlay_static_no_name_apk_path);
 
   auto idmap_static_1_raw_string = utils::ReadFile(idmap_static_1_path);
   auto idmap_static_1_raw_stream = std::istringstream(*idmap_static_1_raw_string);
-  auto idmap_static_1 = Idmap::FromBinaryStream(idmap_static_1_raw_stream, error);
-  ASSERT_THAT(idmap_static_1, NotNull());
-  ASSERT_IDMAP(*idmap_static_1, GetTargetApkPath(), overlay_static_1_apk_path);
+  auto idmap_static_1 = Idmap::FromBinaryStream(idmap_static_1_raw_stream);
+  ASSERT_TRUE(idmap_static_1);
+  ASSERT_IDMAP(**idmap_static_1, GetTargetApkPath(), overlay_static_1_apk_path);
 
   auto idmap_static_2_raw_string = utils::ReadFile(idmap_static_2_path);
   auto idmap_static_2_raw_stream = std::istringstream(*idmap_static_2_raw_string);
-  auto idmap_static_2 = Idmap::FromBinaryStream(idmap_static_2_raw_stream, error);
-  ASSERT_THAT(idmap_static_2, NotNull());
-  ASSERT_IDMAP(*idmap_static_2, GetTargetApkPath(), overlay_static_2_apk_path);
+  auto idmap_static_2 = Idmap::FromBinaryStream(idmap_static_2_raw_stream);
+  ASSERT_TRUE(idmap_static_2);
+  ASSERT_IDMAP(**idmap_static_2, GetTargetApkPath(), overlay_static_2_apk_path);
 
   unlink(idmap_static_no_name_path.c_str());
   unlink(idmap_static_2_path.c_str());
diff --git a/cmds/idmap2/tests/IdmapTests.cpp b/cmds/idmap2/tests/IdmapTests.cpp
index 8d65428..621f503 100644
--- a/cmds/idmap2/tests/IdmapTests.cpp
+++ b/cmds/idmap2/tests/IdmapTests.cpp
@@ -20,6 +20,7 @@
 #include <memory>
 #include <sstream>
 #include <string>
+#include <utility>
 #include <vector>
 
 #include "gmock/gmock.h"
@@ -127,9 +128,9 @@
   std::string raw(reinterpret_cast<const char*>(idmap_raw_data), idmap_raw_data_len);
   std::istringstream stream(raw);
 
-  std::stringstream error;
-  std::unique_ptr<const Idmap> idmap = Idmap::FromBinaryStream(stream, error);
-  ASSERT_THAT(idmap, NotNull());
+  auto result = Idmap::FromBinaryStream(stream);
+  ASSERT_TRUE(result);
+  const auto idmap = std::move(*result);
 
   ASSERT_THAT(idmap->GetHeader(), NotNull());
   ASSERT_EQ(idmap->GetHeader()->GetMagic(), 0x504d4449U);
@@ -168,9 +169,8 @@
                   10);  // data too small
   std::istringstream stream(raw);
 
-  std::stringstream error;
-  std::unique_ptr<const Idmap> idmap = Idmap::FromBinaryStream(stream, error);
-  ASSERT_THAT(idmap, IsNull());
+  const auto result = Idmap::FromBinaryStream(stream);
+  ASSERT_FALSE(result);
 }
 
 void CreateIdmap(const StringPiece& target_apk_path, const StringPiece& overlay_apk_path,
@@ -182,10 +182,10 @@
   std::unique_ptr<const ApkAssets> overlay_apk = ApkAssets::Load(overlay_apk_path.to_string());
   ASSERT_THAT(overlay_apk, NotNull());
 
-  std::stringstream error;
-  *out_idmap =
+  auto result =
       Idmap::FromApkAssets(target_apk_path.to_string(), *target_apk, overlay_apk_path.to_string(),
-                           *overlay_apk, fulfilled_policies, enforce_overlayable, error);
+                           *overlay_apk, fulfilled_policies, enforce_overlayable);
+  *out_idmap = result ? std::move(*result) : nullptr;
 }
 
 TEST(IdmapTests, CreateIdmapFromApkAssets) {
@@ -471,11 +471,10 @@
   std::unique_ptr<const ApkAssets> overlay_apk = ApkAssets::Load(overlay_apk_path);
   ASSERT_THAT(overlay_apk, NotNull());
 
-  std::stringstream error;
-  std::unique_ptr<const Idmap> idmap =
+  const auto result =
       Idmap::FromApkAssets(target_apk_path, *target_apk, overlay_apk_path, *overlay_apk,
-                           PolicyFlags::POLICY_PUBLIC, /* enforce_overlayable */ true, error);
-  ASSERT_THAT(idmap, IsNull());
+                           PolicyFlags::POLICY_PUBLIC, /* enforce_overlayable */ true);
+  ASSERT_FALSE(result);
 }
 
 TEST(IdmapTests, IdmapHeaderIsUpToDate) {
@@ -489,11 +488,11 @@
   std::unique_ptr<const ApkAssets> overlay_apk = ApkAssets::Load(overlay_apk_path);
   ASSERT_THAT(overlay_apk, NotNull());
 
-  std::stringstream error;
-  std::unique_ptr<const Idmap> idmap = Idmap::FromApkAssets(
-      target_apk_path, *target_apk, overlay_apk_path, *overlay_apk, PolicyFlags::POLICY_PUBLIC,
-      /* enforce_overlayable */ true, error);
-  ASSERT_THAT(idmap, NotNull());
+  auto result = Idmap::FromApkAssets(target_apk_path, *target_apk, overlay_apk_path, *overlay_apk,
+                                     PolicyFlags::POLICY_PUBLIC,
+                                     /* enforce_overlayable */ true);
+  ASSERT_TRUE(result);
+  const auto idmap = std::move(*result);
 
   std::stringstream stream;
   BinaryStreamVisitor visitor(stream);
@@ -501,7 +500,7 @@
 
   std::unique_ptr<const IdmapHeader> header = IdmapHeader::FromBinaryStream(stream);
   ASSERT_THAT(header, NotNull());
-  ASSERT_TRUE(header->IsUpToDate(error)) << error.str();
+  ASSERT_TRUE(header->IsUpToDate());
 
   // magic: bytes (0x0, 0x03)
   std::string bad_magic_string(stream.str());
@@ -514,7 +513,7 @@
       IdmapHeader::FromBinaryStream(bad_magic_stream);
   ASSERT_THAT(bad_magic_header, NotNull());
   ASSERT_NE(header->GetMagic(), bad_magic_header->GetMagic());
-  ASSERT_FALSE(bad_magic_header->IsUpToDate(error));
+  ASSERT_FALSE(bad_magic_header->IsUpToDate());
 
   // version: bytes (0x4, 0x07)
   std::string bad_version_string(stream.str());
@@ -527,7 +526,7 @@
       IdmapHeader::FromBinaryStream(bad_version_stream);
   ASSERT_THAT(bad_version_header, NotNull());
   ASSERT_NE(header->GetVersion(), bad_version_header->GetVersion());
-  ASSERT_FALSE(bad_version_header->IsUpToDate(error));
+  ASSERT_FALSE(bad_version_header->IsUpToDate());
 
   // target crc: bytes (0x8, 0xb)
   std::string bad_target_crc_string(stream.str());
@@ -540,7 +539,7 @@
       IdmapHeader::FromBinaryStream(bad_target_crc_stream);
   ASSERT_THAT(bad_target_crc_header, NotNull());
   ASSERT_NE(header->GetTargetCrc(), bad_target_crc_header->GetTargetCrc());
-  ASSERT_FALSE(bad_target_crc_header->IsUpToDate(error));
+  ASSERT_FALSE(bad_target_crc_header->IsUpToDate());
 
   // overlay crc: bytes (0xc, 0xf)
   std::string bad_overlay_crc_string(stream.str());
@@ -553,7 +552,7 @@
       IdmapHeader::FromBinaryStream(bad_overlay_crc_stream);
   ASSERT_THAT(bad_overlay_crc_header, NotNull());
   ASSERT_NE(header->GetOverlayCrc(), bad_overlay_crc_header->GetOverlayCrc());
-  ASSERT_FALSE(bad_overlay_crc_header->IsUpToDate(error));
+  ASSERT_FALSE(bad_overlay_crc_header->IsUpToDate());
 
   // target path: bytes (0x10, 0x10f)
   std::string bad_target_path_string(stream.str());
@@ -563,7 +562,7 @@
       IdmapHeader::FromBinaryStream(bad_target_path_stream);
   ASSERT_THAT(bad_target_path_header, NotNull());
   ASSERT_NE(header->GetTargetPath(), bad_target_path_header->GetTargetPath());
-  ASSERT_FALSE(bad_target_path_header->IsUpToDate(error));
+  ASSERT_FALSE(bad_target_path_header->IsUpToDate());
 
   // overlay path: bytes (0x110, 0x20f)
   std::string bad_overlay_path_string(stream.str());
@@ -573,7 +572,7 @@
       IdmapHeader::FromBinaryStream(bad_overlay_path_stream);
   ASSERT_THAT(bad_overlay_path_header, NotNull());
   ASSERT_NE(header->GetOverlayPath(), bad_overlay_path_header->GetOverlayPath());
-  ASSERT_FALSE(bad_overlay_path_header->IsUpToDate(error));
+  ASSERT_FALSE(bad_overlay_path_header->IsUpToDate());
 }
 
 class TestVisitor : public Visitor {
@@ -609,13 +608,12 @@
   std::string raw(reinterpret_cast<const char*>(idmap_raw_data), idmap_raw_data_len);
   std::istringstream stream(raw);
 
-  std::stringstream error;
-  std::unique_ptr<const Idmap> idmap = Idmap::FromBinaryStream(stream, error);
-  ASSERT_THAT(idmap, NotNull());
+  const auto idmap = Idmap::FromBinaryStream(stream);
+  ASSERT_TRUE(idmap);
 
   std::stringstream test_stream;
   TestVisitor visitor(test_stream);
-  idmap->accept(&visitor);
+  (*idmap)->accept(&visitor);
 
   ASSERT_EQ(test_stream.str(),
             "TestVisitor::visit(Idmap)\n"
diff --git a/cmds/idmap2/tests/PrettyPrintVisitorTests.cpp b/cmds/idmap2/tests/PrettyPrintVisitorTests.cpp
index eaa47cd..27a3880 100644
--- a/cmds/idmap2/tests/PrettyPrintVisitorTests.cpp
+++ b/cmds/idmap2/tests/PrettyPrintVisitorTests.cpp
@@ -46,15 +46,14 @@
   std::unique_ptr<const ApkAssets> overlay_apk = ApkAssets::Load(overlay_apk_path);
   ASSERT_THAT(overlay_apk, NotNull());
 
-  std::stringstream error;
-  std::unique_ptr<const Idmap> idmap =
+  const auto idmap =
       Idmap::FromApkAssets(target_apk_path, *target_apk, overlay_apk_path, *overlay_apk,
-                           PolicyFlags::POLICY_PUBLIC, /* enforce_overlayable */ true, error);
-  ASSERT_THAT(idmap, NotNull());
+                           PolicyFlags::POLICY_PUBLIC, /* enforce_overlayable */ true);
+  ASSERT_TRUE(idmap);
 
   std::stringstream stream;
   PrettyPrintVisitor visitor(stream);
-  idmap->accept(&visitor);
+  (*idmap)->accept(&visitor);
 
   ASSERT_NE(stream.str().find("target apk path  : "), std::string::npos);
   ASSERT_NE(stream.str().find("overlay apk path : "), std::string::npos);
@@ -67,13 +66,12 @@
   std::string raw(reinterpret_cast<const char*>(idmap_raw_data), idmap_raw_data_len);
   std::istringstream raw_stream(raw);
 
-  std::stringstream error;
-  std::unique_ptr<const Idmap> idmap = Idmap::FromBinaryStream(raw_stream, error);
-  ASSERT_THAT(idmap, NotNull());
+  const auto idmap = Idmap::FromBinaryStream(raw_stream);
+  ASSERT_TRUE(idmap);
 
   std::stringstream stream;
   PrettyPrintVisitor visitor(stream);
-  idmap->accept(&visitor);
+  (*idmap)->accept(&visitor);
 
   ASSERT_NE(stream.str().find("target apk path  : "), std::string::npos);
   ASSERT_NE(stream.str().find("overlay apk path : "), std::string::npos);
diff --git a/cmds/idmap2/tests/RawPrintVisitorTests.cpp b/cmds/idmap2/tests/RawPrintVisitorTests.cpp
index 7ec13ed..7372148 100644
--- a/cmds/idmap2/tests/RawPrintVisitorTests.cpp
+++ b/cmds/idmap2/tests/RawPrintVisitorTests.cpp
@@ -40,15 +40,14 @@
   std::unique_ptr<const ApkAssets> overlay_apk = ApkAssets::Load(overlay_apk_path);
   ASSERT_THAT(overlay_apk, NotNull());
 
-  std::stringstream error;
-  std::unique_ptr<const Idmap> idmap =
+  const auto idmap =
       Idmap::FromApkAssets(target_apk_path, *target_apk, overlay_apk_path, *overlay_apk,
-                           PolicyFlags::POLICY_PUBLIC, /* enforce_overlayable */ true, error);
-  ASSERT_THAT(idmap, NotNull());
+                           PolicyFlags::POLICY_PUBLIC, /* enforce_overlayable */ true);
+  ASSERT_TRUE(idmap);
 
   std::stringstream stream;
   RawPrintVisitor visitor(stream);
-  idmap->accept(&visitor);
+  (*idmap)->accept(&visitor);
 
   ASSERT_NE(stream.str().find("00000000: 504d4449  magic\n"), std::string::npos);
   ASSERT_NE(stream.str().find("00000004: 00000001  version\n"), std::string::npos);
@@ -64,13 +63,12 @@
   std::string raw(reinterpret_cast<const char*>(idmap_raw_data), idmap_raw_data_len);
   std::istringstream raw_stream(raw);
 
-  std::stringstream error;
-  std::unique_ptr<const Idmap> idmap = Idmap::FromBinaryStream(raw_stream, error);
-  ASSERT_THAT(idmap, NotNull());
+  const auto idmap = Idmap::FromBinaryStream(raw_stream);
+  ASSERT_TRUE(idmap);
 
   std::stringstream stream;
   RawPrintVisitor visitor(stream);
-  idmap->accept(&visitor);
+  (*idmap)->accept(&visitor);
 
   ASSERT_NE(stream.str().find("00000000: 504d4449  magic\n"), std::string::npos);
   ASSERT_NE(stream.str().find("00000004: 00000001  version\n"), std::string::npos);
diff --git a/cmds/idmap2/tests/data/overlay/AndroidManifest.xml b/cmds/idmap2/tests/data/overlay/AndroidManifest.xml
index a7767a6..619bb6c 100644
--- a/cmds/idmap2/tests/data/overlay/AndroidManifest.xml
+++ b/cmds/idmap2/tests/data/overlay/AndroidManifest.xml
@@ -16,6 +16,7 @@
 <manifest
     xmlns:android="http://schemas.android.com/apk/res/android"
     package="test.overlay">
+    <application android:hasCode="false"/>
     <overlay
         android:targetPackage="test.target"
         android:targetName="TestResources"/>
diff --git a/cmds/idmap2/tests/data/signature-overlay/AndroidManifest.xml b/cmds/idmap2/tests/data/signature-overlay/AndroidManifest.xml
index 5dacebd..9e6a453 100644
--- a/cmds/idmap2/tests/data/signature-overlay/AndroidManifest.xml
+++ b/cmds/idmap2/tests/data/signature-overlay/AndroidManifest.xml
@@ -16,6 +16,7 @@
 <manifest
     xmlns:android="http://schemas.android.com/apk/res/android"
     package="test.overlay.system">
+    <application android:hasCode="false"/>
     <overlay
         android:targetPackage="test.target"
         android:targetName="TestResources"/>
diff --git a/cmds/idmap2/tests/data/system-overlay-invalid/AndroidManifest.xml b/cmds/idmap2/tests/data/system-overlay-invalid/AndroidManifest.xml
index ae687d3..c7b652c 100644
--- a/cmds/idmap2/tests/data/system-overlay-invalid/AndroidManifest.xml
+++ b/cmds/idmap2/tests/data/system-overlay-invalid/AndroidManifest.xml
@@ -16,6 +16,7 @@
 <manifest
     xmlns:android="http://schemas.android.com/apk/res/android"
     package="test.overlay.system.invalid">
+    <application android:hasCode="false"/>
     <overlay
         android:targetPackage="test.target"
         android:targetName="TestResources"/>
diff --git a/cmds/idmap2/tests/data/system-overlay/AndroidManifest.xml b/cmds/idmap2/tests/data/system-overlay/AndroidManifest.xml
index 5dacebd..9e6a453 100644
--- a/cmds/idmap2/tests/data/system-overlay/AndroidManifest.xml
+++ b/cmds/idmap2/tests/data/system-overlay/AndroidManifest.xml
@@ -16,6 +16,7 @@
 <manifest
     xmlns:android="http://schemas.android.com/apk/res/android"
     package="test.overlay.system">
+    <application android:hasCode="false"/>
     <overlay
         android:targetPackage="test.target"
         android:targetName="TestResources"/>
diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto
index b8e8fdc..1735b05 100644
--- a/cmds/statsd/src/atoms.proto
+++ b/cmds/statsd/src/atoms.proto
@@ -45,6 +45,7 @@
 import "frameworks/base/core/proto/android/stats/devicepolicy/device_policy.proto";
 import "frameworks/base/core/proto/android/stats/devicepolicy/device_policy_enums.proto";
 import "frameworks/base/core/proto/android/stats/launcher/launcher.proto";
+import "frameworks/base/core/proto/android/stats/storage/storage_enums.proto";
 import "frameworks/base/core/proto/android/stats/style/style_enums.proto";
 import "frameworks/base/core/proto/android/telecomm/enums.proto";
 import "frameworks/base/core/proto/android/telephony/enums.proto";
@@ -250,6 +251,7 @@
         HiddenApiUsed hidden_api_used = 178 [(allow_from_any_uid) = true];
         StyleUIChanged style_ui_changed = 179;
         PrivacyIndicatorsInteracted privacy_indicators_interacted = 180;
+        AppInstallOnExternalStorageReported app_install_on_external_storage_reported = 181;
     }
 
     // Pulled events will start at field 10000.
@@ -308,7 +310,7 @@
         DangerousPermissionState dangerous_permission_state = 10050;
         TrainInfo train_info = 10051;
         TimeZoneDataInfo time_zone_data_info = 10052;
-        SDCardInfo sdcard_info = 10053;
+        ExternalStorageInfo external_storage_info = 10053;
         GpuStatsGlobalInfo gpu_stats_global_info = 10054;
         GpuStatsAppInfo gpu_stats_app_info = 10055;
         SystemIonHeapSize system_ion_heap_size = 10056;
@@ -2063,6 +2065,9 @@
     // HCI reason code associated with this event
     // Default: STATUS_UNKNOWN
     optional android.bluetooth.hci.StatusEnum reason_code = 6;
+    // A status value related to this specific event
+    // Default: 0
+    optional int64 event_value = 7;
 }
 
 /**
@@ -2558,6 +2563,18 @@
 }
 
 /**
+ * Logs whenever an app is installed on external storage.
+ * Logged from:
+        frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java
+ */
+message AppInstallOnExternalStorageReported {
+    // The type of external storage.
+    optional android.stats.storage.ExternalStorageType storage_type = 1;
+    // The name of the package that is installed on the sd card.
+    optional string package_name = 2;
+}
+
+/**
  * Logs when an app crashes.
  * Logged from:
  *      frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -3297,25 +3314,27 @@
 }
 
 /**
- * Logs that an SD card is mounted and information about it, its type (public or private) and the
- * size in bytes.
+ * Logs that external storage is mounted and information about it, the storage type (sd card/usb/
+ * others), its type (public or private) and the size in bytes.
  * Pulled from:
  *   StatsCompanionService
  */
 
-message SDCardInfo {
+message ExternalStorageInfo {
 
-    enum Type {
+    enum VolumeType {
         UNKNOWN = 0;
-        TYPE_PUBLIC = 1;
-        TYPE_PRIVATE = 2;
-        OTHERS = 3;
+        PUBLIC = 1;
+        PRIVATE = 2;
+        OTHER = 3;
     }
 
-    // Type of the SD card: TYPE_PUBLIC if portable and TYPE_PRIVATE if internal.
-    optional Type type = 1;
+    // The type of external storage.
+    optional android.stats.storage.ExternalStorageType storage_type = 1;
+    // Type of the volume: TYPE_PUBLIC if portable and TYPE_PRIVATE if internal.
+    optional VolumeType volume_type = 2;
     // Total size of the sd card in bytes.
-    optional int64 size_bytes = 2;
+    optional int64 size_bytes = 3;
 }
 
 /*
@@ -3403,7 +3422,6 @@
  * - When user clicks privacy chip
  * - How does the user exit the Privacy Dialog
  * Logged from:
- *   packages/SystemUI/src/com/android/systemui/privacy/OngoingPrivacyDialog.kt
  *   packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
  */
 message PrivacyIndicatorsInteracted {
diff --git a/cmds/statsd/src/external/StatsPullerManager.cpp b/cmds/statsd/src/external/StatsPullerManager.cpp
index c7ae656..2abfc24 100644
--- a/cmds/statsd/src/external/StatsPullerManager.cpp
+++ b/cmds/statsd/src/external/StatsPullerManager.cpp
@@ -242,9 +242,9 @@
         // TimeZoneDataInfo.
         {android::util::TIME_ZONE_DATA_INFO,
          {.puller = new StatsCompanionServicePuller(android::util::TIME_ZONE_DATA_INFO)}},
-        // SDCardInfo
-        {android::util::SDCARD_INFO,
-         {.puller = new StatsCompanionServicePuller(android::util::SDCARD_INFO)}},
+        // ExternalStorageInfo
+        {android::util::EXTERNAL_STORAGE_INFO,
+         {.puller = new StatsCompanionServicePuller(android::util::EXTERNAL_STORAGE_INFO)}},
         // GpuStatsGlobalInfo
         {android::util::GPU_STATS_GLOBAL_INFO,
          {.puller = new GpuStatsPuller(android::util::GPU_STATS_GLOBAL_INFO)}},
diff --git a/cmds/statsd/src/metrics/CountMetricProducer.cpp b/cmds/statsd/src/metrics/CountMetricProducer.cpp
index 254d7d5..c023e6f 100644
--- a/cmds/statsd/src/metrics/CountMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/CountMetricProducer.cpp
@@ -319,10 +319,11 @@
         return;
     }
 
-    flushCurrentBucketLocked(eventTimeNs, eventTimeNs);
     // Setup the bucket start time and number.
     int64_t numBucketsForward = 1 + (eventTimeNs - currentBucketEndTimeNs) / mBucketSizeNs;
-    mCurrentBucketStartTimeNs = currentBucketEndTimeNs + (numBucketsForward - 1) * mBucketSizeNs;
+    int64_t nextBucketNs = currentBucketEndTimeNs + (numBucketsForward - 1) * mBucketSizeNs;
+    flushCurrentBucketLocked(eventTimeNs, nextBucketNs);
+
     mCurrentBucketNum += numBucketsForward;
     VLOG("metric %lld: new bucket start time: %lld", (long long)mMetricId,
          (long long)mCurrentBucketStartTimeNs);
@@ -375,6 +376,7 @@
     // Only resets the counters, but doesn't setup the times nor numbers.
     // (Do not clear since the old one is still referenced in mAnomalyTrackers).
     mCurrentSlicedCounter = std::make_shared<DimToValMap>();
+    mCurrentBucketStartTimeNs = nextBucketStartTimeNs;
 }
 
 // Rough estimate of CountMetricProducer buffer stored. This number will be
diff --git a/cmds/statsd/src/metrics/DurationMetricProducer.cpp b/cmds/statsd/src/metrics/DurationMetricProducer.cpp
index 7dc4e2d..615c7f2 100644
--- a/cmds/statsd/src/metrics/DurationMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/DurationMetricProducer.cpp
@@ -559,26 +559,10 @@
         return;
     }
     VLOG("flushing...........");
-    for (auto whatIt = mCurrentSlicedDurationTrackerMap.begin();
-            whatIt != mCurrentSlicedDurationTrackerMap.end();) {
-        for (auto it = whatIt->second.begin(); it != whatIt->second.end();) {
-            if (it->second->flushIfNeeded(eventTimeNs, &mPastBuckets)) {
-                VLOG("erase bucket for key %s %s",
-                     whatIt->first.toString().c_str(), it->first.toString().c_str());
-                it = whatIt->second.erase(it);
-            } else {
-                ++it;
-            }
-        }
-        if (whatIt->second.empty()) {
-            whatIt = mCurrentSlicedDurationTrackerMap.erase(whatIt);
-        } else {
-            whatIt++;
-        }
-    }
-
     int numBucketsForward = 1 + (eventTimeNs - currentBucketEndTimeNs) / mBucketSizeNs;
-    mCurrentBucketStartTimeNs = currentBucketEndTimeNs + (numBucketsForward - 1) * mBucketSizeNs;
+    int64_t nextBucketNs = currentBucketEndTimeNs + (numBucketsForward - 1) * mBucketSizeNs;
+    flushCurrentBucketLocked(eventTimeNs, nextBucketNs);
+
     mCurrentBucketNum += numBucketsForward;
 }
 
@@ -602,6 +586,7 @@
         }
     }
     StatsdStats::getInstance().noteBucketCount(mMetricId);
+    mCurrentBucketStartTimeNs = nextBucketStartTimeNs;
 }
 
 void DurationMetricProducer::dumpStatesLocked(FILE* out, bool verbose) const {
diff --git a/cmds/statsd/src/metrics/GaugeMetricProducer.cpp b/cmds/statsd/src/metrics/GaugeMetricProducer.cpp
index 2b6cac8..2f9afa5 100644
--- a/cmds/statsd/src/metrics/GaugeMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/GaugeMetricProducer.cpp
@@ -529,11 +529,11 @@
         return;
     }
 
-    flushCurrentBucketLocked(eventTimeNs, eventTimeNs);
-
     // Adjusts the bucket start and end times.
     int64_t numBucketsForward = 1 + (eventTimeNs - currentBucketEndTimeNs) / mBucketSizeNs;
-    mCurrentBucketStartTimeNs = currentBucketEndTimeNs + (numBucketsForward - 1) * mBucketSizeNs;
+    int64_t nextBucketNs = currentBucketEndTimeNs + (numBucketsForward - 1) * mBucketSizeNs;
+    flushCurrentBucketLocked(eventTimeNs, nextBucketNs);
+
     mCurrentBucketNum += numBucketsForward;
     VLOG("Gauge metric %lld: new bucket start time: %lld", (long long)mMetricId,
          (long long)mCurrentBucketStartTimeNs);
@@ -578,6 +578,7 @@
 
     StatsdStats::getInstance().noteBucketCount(mMetricId);
     mCurrentSlicedBucket = std::make_shared<DimToGaugeAtomsMap>();
+    mCurrentBucketStartTimeNs = nextBucketStartTimeNs;
 }
 
 size_t GaugeMetricProducer::byteSizeLocked() const {
diff --git a/cmds/statsd/src/metrics/ValueMetricProducer.h b/cmds/statsd/src/metrics/ValueMetricProducer.h
index a0a1348..12cec5d 100644
--- a/cmds/statsd/src/metrics/ValueMetricProducer.h
+++ b/cmds/statsd/src/metrics/ValueMetricProducer.h
@@ -178,7 +178,7 @@
 
     void pullAndMatchEventsLocked(const int64_t timestampNs, ConditionState condition);
 
-    void accumulateEvents(const std::vector<std::shared_ptr<LogEvent>>& allData, 
+    void accumulateEvents(const std::vector<std::shared_ptr<LogEvent>>& allData,
                           int64_t originalPullTimeNs, int64_t eventElapsedTimeNs,
                           ConditionState condition);
 
diff --git a/cmds/statsd/src/shell/ShellSubscriber.cpp b/cmds/statsd/src/shell/ShellSubscriber.cpp
index 52d5ffc..f7e32d4 100644
--- a/cmds/statsd/src/shell/ShellSubscriber.cpp
+++ b/cmds/statsd/src/shell/ShellSubscriber.cpp
@@ -13,7 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-#define DEBUG true  // STOPSHIP if true
+#define DEBUG false  // STOPSHIP if true
 #include "Log.h"
 
 #include "ShellSubscriber.h"
diff --git a/config/hiddenapi-greylist.txt b/config/hiddenapi-greylist.txt
index b3f0037..76d69cd 100644
--- a/config/hiddenapi-greylist.txt
+++ b/config/hiddenapi-greylist.txt
@@ -123,7 +123,6 @@
 Landroid/companion/ICompanionDeviceDiscoveryService$Stub;-><init>()V
 Landroid/companion/ICompanionDeviceDiscoveryServiceCallback;->onDeviceSelected(Ljava/lang/String;ILjava/lang/String;)V
 Landroid/companion/ICompanionDeviceDiscoveryServiceCallback;->onDeviceSelectionCancel()V
-Landroid/companion/IFindDeviceCallback;->onSuccess(Landroid/app/PendingIntent;)V
 Landroid/content/IClipboard$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
 Landroid/content/IClipboard$Stub;->asInterface(Landroid/os/IBinder;)Landroid/content/IClipboard;
 Landroid/content/IContentService$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
@@ -198,8 +197,6 @@
 Landroid/database/IContentObserver;->onChange(ZLandroid/net/Uri;I)V
 Landroid/database/sqlite/SQLiteConnectionPool;->$assertionsDisabled:Z
 Landroid/database/sqlite/SQLiteDatabase;->$assertionsDisabled:Z
-Landroid/filterfw/GraphEnvironment;->addReferences([Ljava/lang/Object;)V
-Landroid/hardware/camera2/utils/HashCodeHelpers;->hashCode([I)I
 Landroid/hardware/display/IDisplayManager$Stub;->asInterface(Landroid/os/IBinder;)Landroid/hardware/display/IDisplayManager;
 Landroid/hardware/fingerprint/IFingerprintService$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
 Landroid/hardware/fingerprint/IFingerprintService$Stub;->asInterface(Landroid/os/IBinder;)Landroid/hardware/fingerprint/IFingerprintService;
@@ -211,8 +208,6 @@
 Landroid/hardware/location/IContextHubService$Stub;->asInterface(Landroid/os/IBinder;)Landroid/hardware/location/IContextHubService;
 Landroid/hardware/usb/IUsbManager$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
 Landroid/hardware/usb/IUsbManager$Stub;->asInterface(Landroid/os/IBinder;)Landroid/hardware/usb/IUsbManager;
-Landroid/inputmethodservice/IInputMethodSessionWrapper;->mCaller:Lcom/android/internal/os/HandlerCaller;
-Landroid/inputmethodservice/IInputMethodWrapper;->mCaller:Lcom/android/internal/os/HandlerCaller;
 Landroid/location/ICountryDetector$Stub;->asInterface(Landroid/os/IBinder;)Landroid/location/ICountryDetector;
 Landroid/location/ICountryListener$Stub;-><init>()V
 Landroid/location/IGeocodeProvider$Stub;-><init>()V
@@ -230,7 +225,6 @@
 Landroid/Manifest$permission;->CAPTURE_SECURE_VIDEO_OUTPUT:Ljava/lang/String;
 Landroid/Manifest$permission;->CAPTURE_VIDEO_OUTPUT:Ljava/lang/String;
 Landroid/Manifest$permission;->READ_FRAME_BUFFER:Ljava/lang/String;
-Landroid/media/effect/SingleFilterEffect;-><init>(Landroid/media/effect/EffectContext;Ljava/lang/String;Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;[Ljava/lang/Object;)V
 Landroid/media/IAudioRoutesObserver$Stub;-><init>()V
 Landroid/media/IAudioService$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
 Landroid/media/IAudioService$Stub;-><init>()V
@@ -266,7 +260,6 @@
 Landroid/net/LinkProperties$ProvisioningChange;->values()[Landroid/net/LinkProperties$ProvisioningChange;
 Landroid/net/MobileLinkQualityInfo;-><init>()V
 Landroid/net/nsd/INsdManager$Stub;->asInterface(Landroid/os/IBinder;)Landroid/net/nsd/INsdManager;
-Landroid/net/nsd/INsdManager;->getMessenger()Landroid/os/Messenger;
 Landroid/net/sip/ISipSession$Stub;->asInterface(Landroid/os/IBinder;)Landroid/net/sip/ISipSession;
 Landroid/net/SntpClient;-><init>()V
 Landroid/net/wifi/IWifiManager$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
@@ -295,7 +288,6 @@
 Landroid/os/IPowerManager$Stub;->asInterface(Landroid/os/IBinder;)Landroid/os/IPowerManager;
 Landroid/os/IPowerManager$Stub;->TRANSACTION_acquireWakeLock:I
 Landroid/os/IPowerManager$Stub;->TRANSACTION_goToSleep:I
-Landroid/os/IPowerManager;->releaseWakeLock(Landroid/os/IBinder;I)V
 Landroid/os/IRecoverySystem$Stub;->asInterface(Landroid/os/IBinder;)Landroid/os/IRecoverySystem;
 Landroid/os/IRemoteCallback$Stub;-><init>()V
 Landroid/os/IUpdateEngine$Stub;-><init>()V
@@ -310,7 +302,6 @@
 Landroid/os/storage/IStorageManager$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
 Landroid/os/storage/IStorageManager$Stub;->asInterface(Landroid/os/IBinder;)Landroid/os/storage/IStorageManager;
 Landroid/os/storage/StorageEventListener;-><init>()V
-Landroid/preference/PreferenceGroupAdapter;->getItem(I)Landroid/preference/Preference;
 Landroid/R$styleable;->ActionBar:[I
 Landroid/R$styleable;->ActionBar_background:I
 Landroid/R$styleable;->ActionBar_backgroundSplit:I
@@ -576,17 +567,6 @@
 Landroid/R$styleable;->Window_windowBackground:I
 Landroid/R$styleable;->Window_windowFrame:I
 Landroid/security/IKeyChainService$Stub;->asInterface(Landroid/os/IBinder;)Landroid/security/IKeyChainService;
-Landroid/security/keymaster/KeymasterBlobArgument;-><init>(ILandroid/os/Parcel;)V
-Landroid/security/keymaster/KeymasterBlobArgument;-><init>(I[B)V
-Landroid/security/keymaster/KeymasterBlobArgument;->blob:[B
-Landroid/security/keymaster/KeymasterBooleanArgument;-><init>(ILandroid/os/Parcel;)V
-Landroid/security/keymaster/KeymasterDateArgument;-><init>(ILandroid/os/Parcel;)V
-Landroid/security/keymaster/KeymasterIntArgument;-><init>(II)V
-Landroid/security/keymaster/KeymasterIntArgument;-><init>(ILandroid/os/Parcel;)V
-Landroid/security/keymaster/KeymasterIntArgument;->value:I
-Landroid/security/keymaster/KeymasterLongArgument;-><init>(IJ)V
-Landroid/security/keymaster/KeymasterLongArgument;-><init>(ILandroid/os/Parcel;)V
-Landroid/security/keymaster/KeymasterLongArgument;->value:J
 Landroid/security/keystore/IKeystoreService$Stub;->asInterface(Landroid/os/IBinder;)Landroid/security/keystore/IKeystoreService;
 Landroid/security/keystore/IKeystoreService;->clear_uid(J)I
 Landroid/security/keystore/IKeystoreService;->del(Ljava/lang/String;I)I
@@ -599,24 +579,17 @@
 Landroid/security/keystore/IKeystoreService;->reset()I
 Landroid/security/keystore/IKeystoreService;->ungrant(Ljava/lang/String;I)I
 Landroid/service/dreams/IDreamManager$Stub;->asInterface(Landroid/os/IBinder;)Landroid/service/dreams/IDreamManager;
-Landroid/service/dreams/IDreamManager;->awaken()V
-Landroid/service/dreams/IDreamManager;->dream()V
 Landroid/service/dreams/IDreamManager;->getDreamComponents()[Landroid/content/ComponentName;
-Landroid/service/dreams/IDreamManager;->isDreaming()Z
-Landroid/service/dreams/IDreamManager;->setDreamComponents([Landroid/content/ComponentName;)V
 Landroid/service/euicc/IEuiccService$Stub;-><init>()V
 Landroid/service/notification/INotificationListener$Stub;-><init>()V
 Landroid/service/persistentdata/IPersistentDataBlockService$Stub;->asInterface(Landroid/os/IBinder;)Landroid/service/persistentdata/IPersistentDataBlockService;
 Landroid/service/vr/IVrManager$Stub;->asInterface(Landroid/os/IBinder;)Landroid/service/vr/IVrManager;
 Landroid/service/wallpaper/IWallpaperConnection$Stub;-><init>()V
 Landroid/service/wallpaper/IWallpaperService$Stub;->asInterface(Landroid/os/IBinder;)Landroid/service/wallpaper/IWallpaperService;
-Landroid/telecom/Log;->i(Ljava/lang/String;Ljava/lang/String;[Ljava/lang/Object;)V
-Landroid/telecom/Log;->w(Ljava/lang/String;Ljava/lang/String;[Ljava/lang/Object;)V
 Landroid/telephony/ims/compat/feature/MMTelFeature;-><init>()V
 Landroid/telephony/ims/compat/ImsService;-><init>()V
 Landroid/telephony/ims/compat/stub/ImsCallSessionImplBase;-><init>()V
 Landroid/telephony/ims/compat/stub/ImsUtListenerImplBase;-><init>()V
-Landroid/telephony/JapanesePhoneNumberFormatter;->format(Landroid/text/Editable;)V
 Landroid/telephony/mbms/IMbmsStreamingSessionCallback$Stub;-><init>()V
 Landroid/telephony/mbms/IStreamingServiceCallback$Stub;-><init>()V
 Landroid/telephony/mbms/vendor/IMbmsStreamingService$Stub;->asInterface(Landroid/os/IBinder;)Landroid/telephony/mbms/vendor/IMbmsStreamingService;
@@ -646,14 +619,8 @@
 Landroid/telephony/SmsCbMessage;->isEmergencyMessage()Z
 Landroid/telephony/TelephonyManager$MultiSimVariants;->values()[Landroid/telephony/TelephonyManager$MultiSimVariants;
 Landroid/util/Singleton;-><init>()V
-Landroid/util/XmlPullAttributes;-><init>(Lorg/xmlpull/v1/XmlPullParser;)V
-Landroid/util/XmlPullAttributes;->mParser:Lorg/xmlpull/v1/XmlPullParser;
-Landroid/view/accessibility/IAccessibilityInteractionConnectionCallback;->setFindAccessibilityNodeInfoResult(Landroid/view/accessibility/AccessibilityNodeInfo;I)V
-Landroid/view/accessibility/IAccessibilityInteractionConnectionCallback;->setFindAccessibilityNodeInfosResult(Ljava/util/List;I)V
-Landroid/view/accessibility/IAccessibilityInteractionConnectionCallback;->setPerformAccessibilityActionResult(ZI)V
 Landroid/view/accessibility/IAccessibilityManager$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
 Landroid/view/accessibility/IAccessibilityManager$Stub;->asInterface(Landroid/os/IBinder;)Landroid/view/accessibility/IAccessibilityManager;
-Landroid/view/accessibility/IAccessibilityManager;->getEnabledAccessibilityServiceList(II)Ljava/util/List;
 Landroid/view/AccessibilityIterators$AbstractTextSegmentIterator;-><init>()V
 Landroid/view/autofill/IAutoFillManager$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
 Landroid/view/autofill/IAutoFillManager$Stub;->asInterface(Landroid/os/IBinder;)Landroid/view/autofill/IAutoFillManager;
diff --git a/core/java/android/accessibilityservice/AccessibilityButtonController.java b/core/java/android/accessibilityservice/AccessibilityButtonController.java
index a70085c..af5af9c 100644
--- a/core/java/android/accessibilityservice/AccessibilityButtonController.java
+++ b/core/java/android/accessibilityservice/AccessibilityButtonController.java
@@ -17,7 +17,6 @@
 package android.accessibilityservice;
 
 import android.annotation.NonNull;
-import android.annotation.Nullable;
 import android.os.Handler;
 import android.os.Looper;
 import android.os.RemoteException;
@@ -76,13 +75,16 @@
      * available to the calling service, {@code false} otherwise
      */
     public boolean isAccessibilityButtonAvailable() {
-        try {
-            return mServiceConnection.isAccessibilityButtonAvailable();
-        } catch (RemoteException re) {
-            Slog.w(LOG_TAG, "Failed to get accessibility button availability.", re);
-            re.rethrowFromSystemServer();
-            return false;
+        if (mServiceConnection != null) {
+            try {
+                return mServiceConnection.isAccessibilityButtonAvailable();
+            } catch (RemoteException re) {
+                Slog.w(LOG_TAG, "Failed to get accessibility button availability.", re);
+                re.rethrowFromSystemServer();
+                return false;
+            }
         }
+        return false;
     }
 
     /**
diff --git a/core/java/android/app/ActivityManagerInternal.java b/core/java/android/app/ActivityManagerInternal.java
index 664f0a3..e8d3293 100644
--- a/core/java/android/app/ActivityManagerInternal.java
+++ b/core/java/android/app/ActivityManagerInternal.java
@@ -329,6 +329,9 @@
     /** Returns true if the given uid is the app in the foreground. */
     public abstract boolean isAppForeground(int uid);
 
+    /** Returns true if the given uid is currently marked 'bad' */
+    public abstract boolean isAppBad(ApplicationInfo info);
+
     /** Remove pending backup for the given userId. */
     public abstract void clearPendingBackup(int userId);
 
@@ -337,4 +340,21 @@
      * like persisting database etc.
      */
     public abstract void prepareForPossibleShutdown();
+
+    /**
+     * Returns {@code true} if {@code uid} is running a foreground service of a specific
+     * {@code foregroundServiceType}.
+     */
+    public abstract boolean hasRunningForegroundService(int uid, int foregroundServiceType);
+
+    /**
+     * Registers the specified {@code processObserver} to be notified of future changes to
+     * process state.
+     */
+    public abstract void registerProcessObserver(IProcessObserver processObserver);
+
+    /**
+     * Unregisters the specified {@code processObserver}.
+     */
+    public abstract void unregisterProcessObserver(IProcessObserver processObserver);
 }
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index c0a702f..08239a1 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -3115,6 +3115,10 @@
         if (!r.stopped) {
             throw new IllegalStateException("Can't start activity that is not stopped.");
         }
+        if (r.activity.mFinished) {
+            // TODO(lifecycler): How can this happen?
+            return;
+        }
 
         // Start
         activity.performStart("handleStartActivity");
@@ -3237,8 +3241,6 @@
             if (!r.activity.mFinished && pendingActions != null) {
                 pendingActions.setOldState(r.state);
                 pendingActions.setRestoreInstanceState(true);
-            }
-            if (pendingActions != null) {
                 pendingActions.setCallOnPostCreate(true);
             }
         } else {
@@ -3940,7 +3942,7 @@
         if (localLOGV) {
             Slog.v(TAG, "Performing resume of " + r + " finished=" + r.activity.mFinished);
         }
-        if (r == null) {
+        if (r == null || r.activity.mFinished) {
             return null;
         }
         if (r.getLifecycleState() == ON_RESUME) {
@@ -4210,6 +4212,12 @@
     private Bundle performPauseActivity(ActivityClientRecord r, boolean finished, String reason,
             PendingTransactionActions pendingActions) {
         if (r.paused) {
+            if (r.activity.mFinished) {
+                // If we are finishing, we won't call onResume() in certain cases.
+                // So here we likewise don't want to call onPause() if the activity
+                // isn't resumed.
+                return null;
+            }
             RuntimeException e = new RuntimeException(
                     "Performing pause of activity that is not resumed: "
                     + r.intent.getComponent().toShortString());
@@ -4329,13 +4337,20 @@
             boolean saveState, boolean finalStateRequest, String reason) {
         if (localLOGV) Slog.v(TAG, "Performing stop of " + r);
         if (r != null) {
-            if (!keepShown && r.stopped && !finalStateRequest) {
-                // Double stop request is possible if activity receives 'sleep' followed by 'stop'.
-                final RuntimeException e = new RuntimeException(
-                        "Performing stop of activity that is already stopped: "
-                                + r.intent.getComponent().toShortString());
-                Slog.e(TAG, e.getMessage(), e);
-                Slog.e(TAG, r.getStateString());
+            if (!keepShown && r.stopped) {
+                if (r.activity.mFinished) {
+                    // If we are finishing, we won't call onResume() in certain
+                    // cases.  So here we likewise don't want to call onStop()
+                    // if the activity isn't resumed.
+                    return;
+                }
+                if (!finalStateRequest) {
+                    final RuntimeException e = new RuntimeException(
+                            "Performing stop of activity that is already stopped: "
+                                    + r.intent.getComponent().toShortString());
+                    Slog.e(TAG, e.getMessage(), e);
+                    Slog.e(TAG, r.getStateString());
+                }
             }
 
             // One must first be paused before stopped...
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index 1066fc7..5ed4428 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -48,7 +48,6 @@
 import android.util.SparseArray;
 
 import com.android.internal.annotations.GuardedBy;
-
 import com.android.internal.annotations.Immutable;
 import com.android.internal.app.IAppOpsActiveCallback;
 import com.android.internal.app.IAppOpsCallback;
@@ -1098,6 +1097,8 @@
     /** @hide Write media of image type. */
     public static final String OPSTR_WRITE_MEDIA_IMAGES = "android:write_media_images";
     /** @hide Has a legacy (non-isolated) view of storage. */
+    @TestApi
+    @SystemApi
     public static final String OPSTR_LEGACY_STORAGE = "android:legacy_storage";
     /** @hide Interact with accessibility. */
     @SystemApi
@@ -2153,6 +2154,7 @@
      *
      * @hide
      */
+    @TestApi
     @SystemApi
     public static int opToDefaultMode(@NonNull String appOp) {
         return opToDefaultMode(strOpToOp(appOp));
@@ -4465,7 +4467,7 @@
      * @hide
      */
     @TestApi
-    @RequiresPermission(android.Manifest.permission.GET_APP_OPS_STATS)
+    @RequiresPermission(Manifest.permission.MANAGE_APPOPS)
     public void getHistoricalOpsFromDiskRaw(@NonNull HistoricalOpsRequest request,
             @Nullable Executor executor, @NonNull Consumer<HistoricalOps> callback) {
         Preconditions.checkNotNull(executor, "executor cannot be null");
@@ -4488,6 +4490,21 @@
     }
 
     /**
+     * Reloads the non historical state to allow testing the read/write path.
+     *
+     * @hide
+     */
+    @TestApi
+    @RequiresPermission(Manifest.permission.MANAGE_APPOPS)
+    public void reloadNonHistoricalState() {
+        try {
+            mService.reloadNonHistoricalState();
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
      * Sets given app op in the specified mode for app ops in the UID.
      * This applies to all apps currently in the UID or installed in
      * this UID in the future.
@@ -4570,6 +4587,7 @@
      * be changed.
      * @hide
      */
+    @TestApi
     @SystemApi
     @RequiresPermission(android.Manifest.permission.MANAGE_APP_OPS_MODES)
     public void setMode(String op, int uid, String packageName, @Mode int mode) {
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java
index a226062..7a0639e 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -3054,9 +3054,9 @@
     }
 
     @Override
-    public String getContentCaptureServicePackageName() {
+    public String getSystemCaptionsServicePackageName() {
         try {
-            return mPM.getContentCaptureServicePackageName();
+            return mPM.getSystemCaptionsServicePackageName();
         } catch (RemoteException e) {
             throw e.rethrowAsRuntimeException();
         }
diff --git a/core/java/android/app/INotificationManager.aidl b/core/java/android/app/INotificationManager.aidl
index 15084de..7884872 100644
--- a/core/java/android/app/INotificationManager.aidl
+++ b/core/java/android/app/INotificationManager.aidl
@@ -70,6 +70,10 @@
     boolean areNotificationsEnabled(String pkg);
     int getPackageImportance(String pkg);
 
+    List<String> getAllowedAssistantCapabilities(String pkg);
+    void allowAssistantCapability(String adjustmentType);
+    void disallowAssistantCapability(String adjustmentType);
+
     boolean shouldHideSilentStatusIcons(String callingPkg);
     void setHideSilentStatusIcons(boolean hide);
 
@@ -86,10 +90,10 @@
     NotificationChannelGroup getPopulatedNotificationChannelGroupForPackage(String pkg, int uid, String groupId, boolean includeDeleted);
     void updateNotificationChannelGroupForPackage(String pkg, int uid, in NotificationChannelGroup group);
     void updateNotificationChannelForPackage(String pkg, int uid, in NotificationChannel channel);
-    NotificationChannel getNotificationChannel(String pkg, String channelId);
+    NotificationChannel getNotificationChannel(String callingPkg, int userId, String pkg, String channelId);
     NotificationChannel getNotificationChannelForPackage(String pkg, int uid, String channelId, boolean includeDeleted);
     void deleteNotificationChannel(String pkg, String channelId);
-    ParceledListSlice getNotificationChannels(String pkg);
+    ParceledListSlice getNotificationChannels(String callingPkg, String targetPkg, int userId);
     ParceledListSlice getNotificationChannelsForPackage(String pkg, int uid, boolean includeDeleted);
     int getNumNotificationChannelsForPackage(String pkg, int uid, boolean includeDeleted);
     int getDeletedChannelCount(String pkg, int uid);
diff --git a/core/java/android/app/IProcessObserver.aidl b/core/java/android/app/IProcessObserver.aidl
index b436aa2..7be3620 100644
--- a/core/java/android/app/IProcessObserver.aidl
+++ b/core/java/android/app/IProcessObserver.aidl
@@ -19,5 +19,6 @@
 /** {@hide} */
 oneway interface IProcessObserver {
     void onForegroundActivitiesChanged(int pid, int uid, boolean foregroundActivities);
+    void onForegroundServicesChanged(int pid, int uid, int serviceTypes);
     void onProcessDied(int pid, int uid);
 }
diff --git a/core/java/android/app/KeyguardManager.java b/core/java/android/app/KeyguardManager.java
index 3ecb587..bcd43a2 100644
--- a/core/java/android/app/KeyguardManager.java
+++ b/core/java/android/app/KeyguardManager.java
@@ -440,7 +440,7 @@
      */
     public boolean isKeyguardSecure() {
         try {
-            return mWM.isKeyguardSecure();
+            return mWM.isKeyguardSecure(mContext.getUserId());
         } catch (RemoteException ex) {
             return false;
         }
diff --git a/core/java/android/app/LoadedApk.java b/core/java/android/app/LoadedApk.java
index db8c905..41a9921 100644
--- a/core/java/android/app/LoadedApk.java
+++ b/core/java/android/app/LoadedApk.java
@@ -781,6 +781,16 @@
             isBundledApp = false;
         }
 
+        // Similar to vendor apks, we should add /product/lib for apks from product partition
+        // and not having /product/lib in the default search path
+        final boolean treatProductApkAsUnbundled = !defaultSearchPaths.contains("/product/lib");
+        if (mApplicationInfo.getCodePath() != null
+                && mApplicationInfo.isProduct() && treatProductApkAsUnbundled
+                // TODO(b/128557860): Change target SDK version when version code R is available.
+                && getTargetSdkVersion() == Build.VERSION_CODES.CUR_DEVELOPMENT) {
+            isBundledApp = false;
+        }
+
         makePaths(mActivityThread, isBundledApp, mApplicationInfo, zipPaths, libPaths);
 
         String libraryPermittedPath = mDataDir;
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 23f64b8..7ba6146 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -16,6 +16,8 @@
 
 package android.app;
 
+import static android.graphics.drawable.Icon.TYPE_BITMAP;
+
 import static com.android.internal.util.ContrastColorUtil.satisfiesTextContrast;
 
 import android.annotation.ColorInt;
@@ -1569,12 +1571,12 @@
          * Builder class for {@link Action} objects.
          */
         public static final class Builder {
-            private final Icon mIcon;
-            private final CharSequence mTitle;
-            private final PendingIntent mIntent;
+            @Nullable private final Icon mIcon;
+            @Nullable private final CharSequence mTitle;
+            @Nullable private final PendingIntent mIntent;
             private boolean mAllowGeneratedReplies = true;
-            private final Bundle mExtras;
-            private ArrayList<RemoteInput> mRemoteInputs;
+            @NonNull private final Bundle mExtras;
+            @Nullable private ArrayList<RemoteInput> mRemoteInputs;
             private @SemanticAction int mSemanticAction;
             private boolean mIsContextual;
 
@@ -1610,9 +1612,10 @@
                         action.getAllowGeneratedReplies(), action.getSemanticAction());
             }
 
-            private Builder(Icon icon, CharSequence title, PendingIntent intent, Bundle extras,
-                    RemoteInput[] remoteInputs, boolean allowGeneratedReplies,
-                            @SemanticAction int semanticAction) {
+            private Builder(@Nullable Icon icon, @Nullable CharSequence title,
+                    @Nullable PendingIntent intent, @NonNull Bundle extras,
+                    @Nullable RemoteInput[] remoteInputs, boolean allowGeneratedReplies,
+                    @SemanticAction int semanticAction) {
                 mIcon = icon;
                 mTitle = title;
                 mIntent = intent;
@@ -1645,6 +1648,7 @@
              *
              * <p>The returned Bundle is shared with this Builder.
              */
+            @NonNull
             public Bundle getExtras() {
                 return mExtras;
             }
@@ -8705,12 +8709,25 @@
              * <p>An icon is required and should be representative of the content within the bubble.
              * If your app produces multiple bubbles, the image should be unique for each of them.
              * </p>
+             *
+             * <p>The shape of a bubble icon is adaptive and can match the device theme.
+             *
+             * If your icon is bitmap-based, you should create it using
+             * {@link Icon#createWithAdaptiveBitmap(Bitmap)}, otherwise this method will throw.
+             *
+             * If your icon is not bitmap-based, you should expect that the icon will be tinted.
+             * </p>
              */
             @NonNull
             public BubbleMetadata.Builder setIcon(@NonNull Icon icon) {
                 if (icon == null) {
                     throw new IllegalArgumentException("Bubbles require non-null icon");
                 }
+                if (icon.getType() == TYPE_BITMAP) {
+                    throw new IllegalArgumentException("When using bitmap based icons, Bubbles "
+                            + "require TYPE_ADAPTIVE_BITMAP, please use"
+                            + " Icon#createWithAdaptiveBitmap instead");
+                }
                 mIcon = icon;
                 return this;
             }
diff --git a/core/java/android/app/NotificationManager.java b/core/java/android/app/NotificationManager.java
index 6a301c9..1aacf96 100644
--- a/core/java/android/app/NotificationManager.java
+++ b/core/java/android/app/NotificationManager.java
@@ -42,6 +42,7 @@
 import android.os.StrictMode;
 import android.os.UserHandle;
 import android.provider.Settings.Global;
+import android.service.notification.Adjustment;
 import android.service.notification.Condition;
 import android.service.notification.StatusBarNotification;
 import android.service.notification.ZenModeConfig;
@@ -715,12 +716,16 @@
     /**
      * Returns the notification channel settings for a given channel id.
      *
-     * The channel must belong to your package, or it will not be returned.
+     * <p>The channel must belong to your package, or to a package you are an approved notification
+     * delegate for (see {@link #canNotifyAsPackage(String)}), or it will not be returned. To query
+     * a channel as a notification delegate, call this method from a context created for that
+     * package (see {@link Context#createPackageContext(String, int)}).</p>
      */
     public NotificationChannel getNotificationChannel(String channelId) {
         INotificationManager service = getService();
         try {
-            return service.getNotificationChannel(mContext.getPackageName(), channelId);
+            return service.getNotificationChannel(mContext.getOpPackageName(),
+                    mContext.getUserId(), mContext.getPackageName(), channelId);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -728,11 +733,17 @@
 
     /**
      * Returns all notification channels belonging to the calling package.
+     *
+     * <p>Approved notification delegates (see {@link #canNotifyAsPackage(String)}) can query
+     * notification channels belonging to packages they are the delegate for. To do so, call this
+     * method from a context created for that package (see
+     * {@link Context#createPackageContext(String, int)}).</p>
      */
     public List<NotificationChannel> getNotificationChannels() {
         INotificationManager service = getService();
         try {
-            return service.getNotificationChannels(mContext.getPackageName()).getList();
+            return service.getNotificationChannels(mContext.getOpPackageName(),
+                    mContext.getPackageName(), mContext.getUserId()).getList();
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -1182,6 +1193,25 @@
         }
     }
 
+    /**
+     * Returns the list of {@link android.service.notification.Adjustment adjustment keys} that can
+     * be modified by the current {@link android.service.notification.NotificationAssistantService}.
+     *
+     * <p>Only callable by the current
+     * {@link android.service.notification.NotificationAssistantService}.
+     * See {@link #isNotificationAssistantAccessGranted(ComponentName)}</p>
+     * @hide
+     */
+    @SystemApi
+    public @NonNull @Adjustment.Keys List<String> getAllowedAssistantCapabilities() {
+        INotificationManager service = getService();
+        try {
+            return service.getAllowedAssistantCapabilities(mContext.getOpPackageName());
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
     /** @hide */
     public boolean isNotificationPolicyAccessGrantedForPackage(String pkg) {
         INotificationManager service = getService();
diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
index 08e0880..4d280b7 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -101,11 +101,9 @@
 import android.net.EthernetManager;
 import android.net.IConnectivityManager;
 import android.net.IEthernetManager;
-import android.net.IIpMemoryStore;
 import android.net.IIpSecService;
 import android.net.INetworkPolicyManager;
 import android.net.ITestNetworkManager;
-import android.net.IpMemoryStore;
 import android.net.IpSecManager;
 import android.net.NetworkPolicyManager;
 import android.net.NetworkScoreManager;
@@ -340,17 +338,6 @@
             }
         });
 
-        registerService(Context.IP_MEMORY_STORE_SERVICE, IpMemoryStore.class,
-                new CachedServiceFetcher<IpMemoryStore>() {
-                    @Override
-                    public IpMemoryStore createService(final ContextImpl ctx)
-                            throws ServiceNotFoundException {
-                        IBinder b = ServiceManager.getServiceOrThrow(
-                                Context.IP_MEMORY_STORE_SERVICE);
-                        IIpMemoryStore service = IIpMemoryStore.Stub.asInterface(b);
-                        return new IpMemoryStore(ctx, service);
-                    }});
-
         registerService(Context.IPSEC_SERVICE, IpSecManager.class,
                 new CachedServiceFetcher<IpSecManager>() {
             @Override
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 9a4e215..20e85e6 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -112,6 +112,7 @@
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
+import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
 import java.util.concurrent.CompletableFuture;
@@ -5171,7 +5172,8 @@
      * </ul>
      * The call will fail if called with the package name of an unsupported VPN app.
      * <p> Enabling lockdown via {@code lockdownEnabled} argument carries the risk that any failure
-     * of the VPN provider could break networking for all apps.
+     * of the VPN provider could break networking for all apps. This method clears any lockdown
+     * whitelist set by {@link #setAlwaysOnVpnPackage(ComponentName, String, boolean, Set)}.
      *
      * @param vpnPackage The package name for an installed VPN app on the device, or {@code null} to
      *        remove an existing always-on VPN configuration.
@@ -5181,11 +5183,11 @@
      * @throws NameNotFoundException if {@code vpnPackage} is not installed.
      * @throws UnsupportedOperationException if {@code vpnPackage} exists but does not support being
      *         set as always-on, or if always-on VPN is not available.
-     * @see #setAlwaysOnVpnPackage(ComponentName, String, boolean, List)
+     * @see #setAlwaysOnVpnPackage(ComponentName, String, boolean, Set)
      */
     public void setAlwaysOnVpnPackage(@NonNull ComponentName admin, @Nullable String vpnPackage,
             boolean lockdownEnabled) throws NameNotFoundException {
-        setAlwaysOnVpnPackage(admin, vpnPackage, lockdownEnabled, Collections.emptyList());
+        setAlwaysOnVpnPackage(admin, vpnPackage, lockdownEnabled, Collections.emptySet());
     }
 
     /**
@@ -5195,6 +5197,11 @@
      * System apps can always bypass VPN.
      * <p> Note that the system doesn't update the whitelist when packages are installed or
      * uninstalled, the admin app must call this method to keep the list up to date.
+     * <p> When {@code lockdownEnabled} is false {@code lockdownWhitelist} is ignored . When
+     * {@code lockdownEnabled} is {@code true} and {@code lockdownWhitelist} is {@code null} or
+     * empty, only system apps can bypass VPN.
+     * <p> Setting always-on VPN package to {@code null} or using
+     * {@link #setAlwaysOnVpnPackage(ComponentName, String, boolean)} clears lockdown whitelist.
      *
      * @param vpnPackage package name for an installed VPN app on the device, or {@code null}
      *         to remove an existing always-on VPN configuration
@@ -5211,13 +5218,13 @@
      *         available.
      */
     public void setAlwaysOnVpnPackage(@NonNull ComponentName admin, @Nullable String vpnPackage,
-            boolean lockdownEnabled, @Nullable List<String> lockdownWhitelist)
+            boolean lockdownEnabled, @Nullable Set<String> lockdownWhitelist)
             throws NameNotFoundException {
         throwIfParentInstance("setAlwaysOnVpnPackage");
         if (mService != null) {
             try {
-                mService.setAlwaysOnVpnPackage(
-                        admin, vpnPackage, lockdownEnabled, lockdownWhitelist);
+                mService.setAlwaysOnVpnPackage(admin, vpnPackage, lockdownEnabled,
+                        lockdownWhitelist == null ? null : new ArrayList<>(lockdownWhitelist));
             } catch (ServiceSpecificException e) {
                 switch (e.errorCode) {
                     case ERROR_VPN_PACKAGE_NOT_FOUND:
@@ -5255,7 +5262,7 @@
     }
 
     /**
-     * Called by device or profile owner to query the list of packages that are allowed to access
+     * Called by device or profile owner to query the set of packages that are allowed to access
      * the network directly when always-on VPN is in lockdown mode but not connected. Returns
      * {@code null} when always-on VPN is not active or not in lockdown mode.
      *
@@ -5263,13 +5270,15 @@
      *
      * @throws SecurityException if {@code admin} is not a device or a profile owner.
      *
-     * @see #setAlwaysOnVpnPackage(ComponentName, String, boolean, List)
+     * @see #setAlwaysOnVpnPackage(ComponentName, String, boolean, Set)
      */
-    public @Nullable List<String> getAlwaysOnVpnLockdownWhitelist(@NonNull ComponentName admin) {
+    public @Nullable Set<String> getAlwaysOnVpnLockdownWhitelist(@NonNull ComponentName admin) {
         throwIfParentInstance("getAlwaysOnVpnLockdownWhitelist");
         if (mService != null) {
             try {
-                return mService.getAlwaysOnVpnLockdownWhitelist(admin);
+                final List<String> whitelist =
+                        mService.getAlwaysOnVpnLockdownWhitelist(admin);
+                return whitelist == null ? null : new HashSet<>(whitelist);
             } catch (RemoteException e) {
                 throw e.rethrowFromSystemServer();
             }
@@ -6339,7 +6348,6 @@
      */
     @RequiresPermission(value = android.Manifest.permission.INTERACT_ACROSS_USERS,
             conditional = true)
-    @SystemApi
     public @Nullable ComponentName getProfileOwnerAsUser(@NonNull UserHandle user) {
         if (mService != null) {
             try {
diff --git a/core/java/android/app/backup/BackupManager.java b/core/java/android/app/backup/BackupManager.java
index bcc4974..25caaaa 100644
--- a/core/java/android/app/backup/BackupManager.java
+++ b/core/java/android/app/backup/BackupManager.java
@@ -16,6 +16,7 @@
 
 package android.app.backup;
 
+import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.RequiresPermission;
 import android.annotation.SystemApi;
@@ -502,32 +503,76 @@
      * @param transportComponent The identity of the transport being described.
      * @param name A {@link String} with the new name for the transport. This is NOT for
      *     identification. MUST NOT be {@code null}.
-     * @param configurationIntent An {@link Intent} that can be passed to
-     *     {@link Context#startActivity} in order to launch the transport's configuration UI. It may
-     *     be {@code null} if the transport does not offer any user-facing configuration UI.
+     * @param configurationIntent An {@link Intent} that can be passed to {@link
+     *     Context#startActivity} in order to launch the transport's configuration UI. It may be
+     *     {@code null} if the transport does not offer any user-facing configuration UI.
      * @param currentDestinationString A {@link String} describing the destination to which the
      *     transport is currently sending data. MUST NOT be {@code null}.
-     * @param dataManagementIntent An {@link Intent} that can be passed to
-     *     {@link Context#startActivity} in order to launch the transport's data-management UI. It
-     *     may be {@code null} if the transport does not offer any user-facing data
-     *     management UI.
+     * @param dataManagementIntent An {@link Intent} that can be passed to {@link
+     *     Context#startActivity} in order to launch the transport's data-management UI. It may be
+     *     {@code null} if the transport does not offer any user-facing data management UI.
      * @param dataManagementLabel A {@link String} to be used as the label for the transport's data
-     *     management affordance. This MUST be {@code null} when dataManagementIntent is
-     *     {@code null} and MUST NOT be {@code null} when dataManagementIntent is not {@code null}.
+     *     management affordance. This MUST be {@code null} when dataManagementIntent is {@code
+     *     null} and MUST NOT be {@code null} when dataManagementIntent is not {@code null}.
      * @throws SecurityException If the UID of the calling process differs from the package UID of
      *     {@code transportComponent} or if the caller does NOT have BACKUP permission.
+     * @deprecated Since Android Q, please use the variant {@link
+     *     #updateTransportAttributes(ComponentName, String, Intent, String, Intent, CharSequence)}
+     *     instead.
+     * @hide
+     */
+    @Deprecated
+    @SystemApi
+    @RequiresPermission(android.Manifest.permission.BACKUP)
+    public void updateTransportAttributes(
+            @NonNull ComponentName transportComponent,
+            @NonNull String name,
+            @Nullable Intent configurationIntent,
+            @NonNull String currentDestinationString,
+            @Nullable Intent dataManagementIntent,
+            @Nullable String dataManagementLabel) {
+        updateTransportAttributes(
+                transportComponent,
+                name,
+                configurationIntent,
+                currentDestinationString,
+                dataManagementIntent,
+                (CharSequence) dataManagementLabel);
+    }
+
+    /**
+     * Update the attributes of the transport identified by {@code transportComponent}. If the
+     * specified transport has not been bound at least once (for registration), this call will be
+     * ignored. Only the host process of the transport can change its description, otherwise a
+     * {@link SecurityException} will be thrown.
      *
+     * @param transportComponent The identity of the transport being described.
+     * @param name A {@link String} with the new name for the transport. This is NOT for
+     *     identification. MUST NOT be {@code null}.
+     * @param configurationIntent An {@link Intent} that can be passed to {@link
+     *     Context#startActivity} in order to launch the transport's configuration UI. It may be
+     *     {@code null} if the transport does not offer any user-facing configuration UI.
+     * @param currentDestinationString A {@link String} describing the destination to which the
+     *     transport is currently sending data. MUST NOT be {@code null}.
+     * @param dataManagementIntent An {@link Intent} that can be passed to {@link
+     *     Context#startActivity} in order to launch the transport's data-management UI. It may be
+     *     {@code null} if the transport does not offer any user-facing data management UI.
+     * @param dataManagementLabel A {@link CharSequence} to be used as the label for the transport's
+     *     data management affordance. This MUST be {@code null} when dataManagementIntent is {@code
+     *     null} and MUST NOT be {@code null} when dataManagementIntent is not {@code null}.
+     * @throws SecurityException If the UID of the calling process differs from the package UID of
+     *     {@code transportComponent} or if the caller does NOT have BACKUP permission.
      * @hide
      */
     @SystemApi
     @RequiresPermission(android.Manifest.permission.BACKUP)
     public void updateTransportAttributes(
-            ComponentName transportComponent,
-            String name,
+            @NonNull ComponentName transportComponent,
+            @NonNull String name,
             @Nullable Intent configurationIntent,
-            String currentDestinationString,
+            @NonNull String currentDestinationString,
             @Nullable Intent dataManagementIntent,
-            @Nullable String dataManagementLabel) {
+            @Nullable CharSequence dataManagementLabel) {
         checkServiceBinder();
         if (sService != null) {
             try {
@@ -796,7 +841,7 @@
     /**
      * Returns an {@link Intent} for the specified transport's configuration UI.
      * This value is set by {@link #updateTransportAttributes(ComponentName, String, Intent, String,
-     * Intent, String)}.
+     * Intent, CharSequence)}.
      * @param transportName The name of the registered transport.
      * @hide
      */
@@ -818,7 +863,7 @@
     /**
      * Returns a {@link String} describing where the specified transport is sending data.
      * This value is set by {@link #updateTransportAttributes(ComponentName, String, Intent, String,
-     * Intent, String)}.
+     * Intent, CharSequence)}.
      * @param transportName The name of the registered transport.
      * @hide
      */
@@ -840,7 +885,7 @@
     /**
      * Returns an {@link Intent} for the specified transport's data management UI.
      * This value is set by {@link #updateTransportAttributes(ComponentName, String, Intent, String,
-     * Intent, String)}.
+     * Intent, CharSequence)}.
      * @param transportName The name of the registered transport.
      * @hide
      */
@@ -861,9 +906,28 @@
 
     /**
      * Returns a {@link String} describing what the specified transport's data management intent is
-     * used for.
-     * This value is set by {@link #updateTransportAttributes(ComponentName, String, Intent, String,
-     * Intent, String)}.
+     * used for. This value is set by {@link #updateTransportAttributes(ComponentName, String,
+     * Intent, String, Intent, CharSequence)}.
+     *
+     * @param transportName The name of the registered transport.
+     * @deprecated Since Android Q, please use the variant {@link
+     *     #getDataManagementIntentLabel(String)} instead.
+     * @hide
+     */
+    @Deprecated
+    @SystemApi
+    @TestApi
+    @RequiresPermission(android.Manifest.permission.BACKUP)
+    @Nullable
+    public String getDataManagementLabel(@NonNull String transportName) {
+        CharSequence label = getDataManagementIntentLabel(transportName);
+        return label == null ? null : label.toString();
+    }
+
+    /**
+     * Returns a {@link CharSequence} describing what the specified transport's data management
+     * intent is used for. This value is set by {@link #updateTransportAttributes(ComponentName,
+     * String, Intent, String, Intent, CharSequence)}.
      *
      * @param transportName The name of the registered transport.
      * @hide
@@ -871,13 +935,14 @@
     @SystemApi
     @TestApi
     @RequiresPermission(android.Manifest.permission.BACKUP)
-    public String getDataManagementLabel(String transportName) {
+    @Nullable
+    public CharSequence getDataManagementIntentLabel(@NonNull String transportName) {
         checkServiceBinder();
         if (sService != null) {
             try {
                 return sService.getDataManagementLabelForUser(mContext.getUserId(), transportName);
             } catch (RemoteException e) {
-                Log.e(TAG, "getDataManagementLabel() couldn't connect");
+                Log.e(TAG, "getDataManagementIntentLabel() couldn't connect");
             }
         }
         return null;
diff --git a/core/java/android/app/backup/BackupTransport.java b/core/java/android/app/backup/BackupTransport.java
index 0963594..c8f2ff3 100644
--- a/core/java/android/app/backup/BackupTransport.java
+++ b/core/java/android/app/backup/BackupTransport.java
@@ -16,6 +16,7 @@
 
 package android.app.backup;
 
+import android.annotation.Nullable;
 import android.annotation.SystemApi;
 import android.content.Intent;
 import android.content.pm.PackageInfo;
@@ -164,19 +165,36 @@
     }
 
     /**
-     * On demand, supply a short string that can be shown to the user as the label
-     * on an overflow menu item used to invoked the data management UI.
+     * On demand, supply a short string that can be shown to the user as the label on an overflow
+     * menu item used to invoke the data management UI.
      *
-     * @return A string to be used as the label for the transport's data management
-     *         affordance.  If the transport supplies a data management intent, this
-     *         method must not return {@code null}.
+     * @return A string to be used as the label for the transport's data management affordance. If
+     *     the transport supplies a data management intent, this method must not return {@code
+     *     null}.
+     * @deprecated Since Android Q, please use the variant {@link #dataManagementIntentLabel()}
+     *     instead.
      */
+    @Deprecated
+    @Nullable
     public String dataManagementLabel() {
         throw new UnsupportedOperationException(
                 "Transport dataManagementLabel() not implemented");
     }
 
     /**
+     * On demand, supply a short CharSequence that can be shown to the user as the label on an
+     * overflow menu item used to invoke the data management UI.
+     *
+     * @return A CharSequence to be used as the label for the transport's data management
+     *     affordance. If the transport supplies a data management intent, this method must not
+     *     return {@code null}.
+     */
+    @Nullable
+    public CharSequence dataManagementIntentLabel() {
+        return dataManagementLabel();
+    }
+
+    /**
      * Ask the transport where, on local device storage, to keep backup state blobs.
      * This is per-transport so that mock transports used for testing can coexist with
      * "live" backup services without interfering with the live bookkeeping.  The
@@ -651,8 +669,8 @@
         }
 
         @Override
-        public String dataManagementLabel() {
-            return BackupTransport.this.dataManagementLabel();
+        public CharSequence dataManagementIntentLabel() {
+            return BackupTransport.this.dataManagementIntentLabel();
         }
 
         @Override
diff --git a/core/java/android/app/backup/IBackupManager.aidl b/core/java/android/app/backup/IBackupManager.aidl
index 70ecdae..2dfaad7 100644
--- a/core/java/android/app/backup/IBackupManager.aidl
+++ b/core/java/android/app/backup/IBackupManager.aidl
@@ -353,16 +353,16 @@
      *     {@link Context#startActivity} in order to launch the transport's data-management UI. It
      *     may be {@code null} if the transport does not offer any user-facing data
      *     management UI.
-     * @param dataManagementLabel A {@link String} to be used as the label for the transport's data
-     *     management affordance. This MUST be {@code null} when dataManagementIntent is
-     *     {@code null} and MUST NOT be {@code null} when dataManagementIntent is not {@code null}.
+     * @param dataManagementLabel A {@link CharSequence} to be used as the label for the transport's
+     *     data management affordance. This MUST be {@code null} when dataManagementIntent is {@code
+     *     null} and MUST NOT be {@code null} when dataManagementIntent is not {@code null}.
      * @throws SecurityException If the UID of the calling process differs from the package UID of
      *     {@code transportComponent} or if the caller does NOT have BACKUP permission.
      */
     void updateTransportAttributesForUser(int userId, in ComponentName transportComponent,
             in String name,
             in Intent configurationIntent, in String currentDestinationString,
-            in Intent dataManagementIntent, in String dataManagementLabel);
+            in Intent dataManagementIntent, in CharSequence dataManagementLabel);
 
     /**
      * Identify the currently selected transport.  Callers must hold the
@@ -525,13 +525,7 @@
      *
      * @param userId User id for which the manage-data menu label should be reported.
      */
-    String getDataManagementLabelForUser(int userId, String transport);
-
-    /**
-     * {@link android.app.backup.IBackupManager.getDataManagementLabelForUser} for the calling user
-     * id.
-     */
-    String getDataManagementLabel(String transport);
+    CharSequence getDataManagementLabelForUser(int userId, String transport);
 
     /**
      * Begin a restore session.  Either or both of packageName and transportID
diff --git a/core/java/android/app/prediction/AppPredictionContext.java b/core/java/android/app/prediction/AppPredictionContext.java
index b6f37f6..298b003 100644
--- a/core/java/android/app/prediction/AppPredictionContext.java
+++ b/core/java/android/app/prediction/AppPredictionContext.java
@@ -26,7 +26,8 @@
 import android.os.Parcelable;
 
 /**
- * TODO(b/111701043): Add java docs
+ * Class that provides contextual information about the environment in which the app prediction is
+ * used, such as package name, UI in which the app targets are shown, and number of targets.
  *
  * @hide
  */
@@ -57,20 +58,32 @@
         mExtras = parcel.readBundle();
     }
 
+    /**
+     * Returns the UI surface of the prediction context.
+     */
     @NonNull
     public String getUiSurface() {
         return mUiSurface;
     }
 
+    /**
+     * Returns the predicted target count
+     */
     public @IntRange(from = 0) int getPredictedTargetCount() {
         return mPredictedTargetCount;
     }
 
+    /**
+     * Returns the package name of the prediction context.
+     */
     @NonNull
     public String getPackageName() {
         return mPackageName;
     }
 
+    /**
+     * Returns the extras of the prediction context.
+     */
     @Nullable
     public Bundle getExtras() {
         return mExtras;
@@ -100,9 +113,6 @@
         dest.writeBundle(mExtras);
     }
 
-    /**
-     * @see Parcelable.Creator
-     */
     public static final @android.annotation.NonNull Parcelable.Creator<AppPredictionContext> CREATOR =
             new Parcelable.Creator<AppPredictionContext>() {
                 public AppPredictionContext createFromParcel(Parcel parcel) {
@@ -132,7 +142,7 @@
         private Bundle mExtras;
 
         /**
-         * TODO(b/123591863): Add java docs
+         * @param context The {@link Context} of the prediction client.
          *
          * @hide
          */
diff --git a/core/java/android/app/prediction/AppPredictionManager.java b/core/java/android/app/prediction/AppPredictionManager.java
index 45825cf..cb5b7e7 100644
--- a/core/java/android/app/prediction/AppPredictionManager.java
+++ b/core/java/android/app/prediction/AppPredictionManager.java
@@ -23,7 +23,8 @@
 import com.android.internal.util.Preconditions;
 
 /**
- * TODO (b/111701043) : Add java doc
+ * Class that provides methods to create prediction clients.
+ *
  * @hide
  */
 @SystemApi
diff --git a/core/java/android/app/prediction/AppPredictionSessionId.java b/core/java/android/app/prediction/AppPredictionSessionId.java
index 1c5d8b4..281a16f 100644
--- a/core/java/android/app/prediction/AppPredictionSessionId.java
+++ b/core/java/android/app/prediction/AppPredictionSessionId.java
@@ -22,7 +22,7 @@
 import android.os.Parcelable;
 
 /**
- * TODO (b/111701043) : Add java doc
+ * The id for an app prediction session. See {@link AppPredictor}.
  *
  * @hide
  */
@@ -33,6 +33,8 @@
     private final String mId;
 
     /**
+     * Creates a new id for a prediction session.
+     *
      * @hide
      */
     public AppPredictionSessionId(@NonNull String id) {
@@ -58,7 +60,6 @@
 
     @Override
     public int hashCode() {
-        // Ensure that the id has a consistent hash
         return mId.hashCode();
     }
 
@@ -72,9 +73,6 @@
         dest.writeString(mId);
     }
 
-    /**
-     * @see Parcelable.Creator
-     */
     public static final @android.annotation.NonNull Parcelable.Creator<AppPredictionSessionId> CREATOR =
             new Parcelable.Creator<AppPredictionSessionId>() {
                 public AppPredictionSessionId createFromParcel(Parcel parcel) {
diff --git a/core/java/android/app/prediction/AppPredictor.java b/core/java/android/app/prediction/AppPredictor.java
index 284327d..3e4e8dc 100644
--- a/core/java/android/app/prediction/AppPredictor.java
+++ b/core/java/android/app/prediction/AppPredictor.java
@@ -39,7 +39,7 @@
 import java.util.function.Consumer;
 
 /**
- * TODO (b/111701043) : Add java doc
+ * Class that represents an App Prediction client.
  *
  * <p>
  * Usage: <pre> {@code
@@ -49,14 +49,20 @@
  *
  *    void onCreate() {
  *         mClient = new AppPredictor(...)
+ *         mClient.registerPredictionUpdates(...)
  *    }
  *
  *    void onStart() {
- *        mClient.requestPredictionUpdate();
+ *        mClient.requestPredictionUpdate()
+ *    }
+ *
+ *    void onClick(...) {
+ *        mClient.notifyAppTargetEvent(...)
  *    }
  *
  *    void onDestroy() {
- *        mClient.close();
+ *        mClient.unregisterPredictionUpdates()
+ *        mClient.close()
  *    }
  *
  * }</pre>
@@ -83,7 +89,8 @@
      * The caller should call {@link AppPredictor#destroy()} to dispose the client once it
      * no longer used.
      *
-     * @param predictionContext The prediction context
+     * @param context The {@link Context} of the user of this {@link AppPredictor}.
+     * @param predictionContext The prediction context.
      */
     AppPredictor(@NonNull Context context, @NonNull AppPredictionContext predictionContext) {
         IBinder b = ServiceManager.getService(Context.APP_PREDICTION_SERVICE);
@@ -102,6 +109,8 @@
 
     /**
      * Notifies the prediction service of an app target event.
+     *
+     * @param event The {@link AppTargetEvent} that represents the app target event.
      */
     public void notifyAppTargetEvent(@NonNull AppTargetEvent event) {
         if (mIsClosed.get()) {
@@ -118,6 +127,9 @@
 
     /**
      * Notifies the prediction service when the targets in a launch location are shown to the user.
+     *
+     * @param launchLocation The launch location where the targets are shown to the user.
+     * @param targetIds List of {@link AppTargetId}s that are shown to the user.
      */
     public void notifyLocationShown(@NonNull String launchLocation,
             @NonNull List<AppTargetId> targetIds) {
@@ -138,7 +150,10 @@
      * Requests the prediction service provide continuous updates of App predictions via the
      * provided callback, until the given callback is unregistered.
      *
-     * @see Callback#onTargetsAvailable(List)
+     * @see Callback#onTargetsAvailable(List).
+     *
+     * @param callbackExecutor The callback executor to use when calling the callback.
+     * @param callback The Callback to be called when updates of App predictions are available.
      */
     public void registerPredictionUpdates(@NonNull @CallbackExecutor Executor callbackExecutor,
             @NonNull AppPredictor.Callback callback) {
@@ -164,6 +179,10 @@
     /**
      * Requests the prediction service to stop providing continuous updates to the provided
      * callback until the callback is re-registered.
+     *
+     * @see {@link AppPredictor#registerPredictionUpdates(Executor, Callback)}.
+     *
+     * @param callback The callback to be unregistered.
      */
     public void unregisterPredictionUpdates(@NonNull AppPredictor.Callback callback) {
         if (mIsClosed.get()) {
@@ -187,7 +206,7 @@
      * Requests the prediction service to dispatch a new set of App predictions via the provided
      * callback.
      *
-     * @see Callback#onTargetsAvailable(List)
+     * @see Callback#onTargetsAvailable(List).
      */
     public void requestPredictionUpdate() {
         if (mIsClosed.get()) {
@@ -205,6 +224,10 @@
     /**
      * Returns a new list of AppTargets sorted based on prediction rank or {@code null} if the
      * ranker is not available.
+     *
+     * @param targets List of app targets to be sorted.
+     * @param callbackExecutor The callback executor to use when calling the callback.
+     * @param callback The callback to return the sorted list of app targets.
      */
     @Nullable
     public void sortTargets(@NonNull List<AppTarget> targets,
@@ -255,7 +278,7 @@
     }
 
     /**
-     * TODO(b/123591863): Add java docs
+     * Returns the id of this prediction session.
      *
      * @hide
      */
@@ -271,7 +294,7 @@
 
         /**
          * Called when a new set of predicted app targets are available.
-         * @param targets Sorted list of predicted targets
+         * @param targets Sorted list of predicted targets.
          */
         void onTargetsAvailable(@NonNull List<AppTarget> targets);
     }
diff --git a/core/java/android/app/prediction/AppTarget.java b/core/java/android/app/prediction/AppTarget.java
index 6f09d34..bb1b96c 100644
--- a/core/java/android/app/prediction/AppTarget.java
+++ b/core/java/android/app/prediction/AppTarget.java
@@ -29,6 +29,7 @@
 
 /**
  * A representation of a launchable target.
+ *
  * @hide
  */
 @SystemApi
@@ -45,7 +46,12 @@
     private int mRank;
 
     /**
-     * TODO(b/123591863): Add java docs
+     * Creates an instance of AppTarget that represent a launchable component.
+     *
+     * @param id A unique id for this launchable target.
+     * @param packageName Package name of the target.
+     * @param className Class name of the target.
+     * @param user The UserHandle of the user which this target belongs to.
      *
      * @hide
      */
@@ -62,7 +68,11 @@
     }
 
     /**
-     * TODO(b/123591863): Add java docs
+     * Creates an instance of AppTarget that represent a launchable shortcut.
+     *
+     * @param id A unique id for this launchable target.
+     * @param shortcutInfo The {@link ShortcutInfo} that is represented with this target.
+     * @param className Class name fo the target.
      *
      * @hide
      */
@@ -186,9 +196,6 @@
         dest.writeInt(mRank);
     }
 
-    /**
-     * @see Parcelable.Creator
-     */
     public static final @android.annotation.NonNull Parcelable.Creator<AppTarget> CREATOR =
             new Parcelable.Creator<AppTarget>() {
                 public AppTarget createFromParcel(Parcel parcel) {
diff --git a/core/java/android/app/prediction/AppTargetEvent.java b/core/java/android/app/prediction/AppTargetEvent.java
index f6964f3..54b9563 100644
--- a/core/java/android/app/prediction/AppTargetEvent.java
+++ b/core/java/android/app/prediction/AppTargetEvent.java
@@ -28,6 +28,7 @@
 
 /**
  * A representation of an app target event.
+ *
  * @hide
  */
 @SystemApi
@@ -118,9 +119,6 @@
         dest.writeInt(mAction);
     }
 
-    /**
-     * @see Creator
-     */
     public static final @android.annotation.NonNull Creator<AppTargetEvent> CREATOR =
             new Creator<AppTargetEvent>() {
                 public AppTargetEvent createFromParcel(Parcel parcel) {
@@ -134,6 +132,7 @@
 
     /**
      * A builder for app target events.
+     *
      * @hide
      */
     @SystemApi
@@ -143,6 +142,10 @@
         private String mLocation;
         private @ActionType int mAction;
 
+        /**
+         * @param target The app target that is associated with this event.
+         * @param actionType The event type, which is one of the values in {@link ActionType}.
+         */
         public Builder(@Nullable AppTarget target, @ActionType int actionType) {
             mTarget = target;
             mAction = actionType;
diff --git a/core/java/android/app/prediction/AppTargetId.java b/core/java/android/app/prediction/AppTargetId.java
index aa2ec1f..3603f5f 100644
--- a/core/java/android/app/prediction/AppTargetId.java
+++ b/core/java/android/app/prediction/AppTargetId.java
@@ -22,7 +22,8 @@
 import android.os.Parcelable;
 
 /**
- * The id for a prediction target.
+ * The id for a prediction target. See {@link AppTarget}.
+ *
  * @hide
  */
 @SystemApi
@@ -33,7 +34,7 @@
     private final String mId;
 
     /**
-     * TODO(b/123591863): Add java docs
+     * Creates a new id for a prediction target.
      *
      * @hide
      */
@@ -49,6 +50,7 @@
 
     /**
      * Returns the id.
+     *
      * @hide
      */
     @NonNull
@@ -66,7 +68,6 @@
 
     @Override
     public int hashCode() {
-        // Ensure that the id has a consistent hash
         return mId.hashCode();
     }
 
@@ -80,9 +81,6 @@
         dest.writeString(mId);
     }
 
-    /**
-     * @see Creator
-     */
     public static final @android.annotation.NonNull Creator<AppTargetId> CREATOR =
             new Creator<AppTargetId>() {
                 public AppTargetId createFromParcel(Parcel parcel) {
diff --git a/core/java/android/bluetooth/BluetoothHearingAid.java b/core/java/android/bluetooth/BluetoothHearingAid.java
index b4eaab2..d6edb90 100644
--- a/core/java/android/bluetooth/BluetoothHearingAid.java
+++ b/core/java/android/bluetooth/BluetoothHearingAid.java
@@ -22,7 +22,6 @@
 import android.annotation.RequiresPermission;
 import android.annotation.SdkConstant;
 import android.annotation.SdkConstant.SdkConstantType;
-import android.annotation.UnsupportedAppUsage;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
@@ -92,7 +91,6 @@
      * @hide
      */
     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
-    @UnsupportedAppUsage
     public static final String ACTION_ACTIVE_DEVICE_CHANGED =
             "android.bluetooth.hearingaid.profile.action.ACTIVE_DEVICE_CHANGED";
 
@@ -324,7 +322,8 @@
     /**
      * {@inheritDoc}
      */
-    @Override public @NonNull List<BluetoothDevice> getDevicesMatchingConnectionStates(
+    @Override
+    public @NonNull List<BluetoothDevice> getDevicesMatchingConnectionStates(
     @NonNull int[] states) {
         if (VDBG) log("getDevicesMatchingStates()");
         try {
@@ -346,7 +345,8 @@
      * {@inheritDoc}
      */
     @Override
-    public int getConnectionState(@NonNull BluetoothDevice device) {
+    public @BluetoothProfile.BtProfileState int getConnectionState(
+    @NonNull BluetoothDevice device) {
         if (VDBG) log("getState(" + device + ")");
         try {
             mServiceLock.readLock().lock();
@@ -386,7 +386,6 @@
      * @return false on immediate error, true otherwise
      * @hide
      */
-    @UnsupportedAppUsage
     public boolean setActiveDevice(@Nullable BluetoothDevice device) {
         if (DBG) log("setActiveDevice(" + device + ")");
         try {
@@ -418,7 +417,6 @@
      * @hide
      */
     @RequiresPermission(Manifest.permission.BLUETOOTH)
-    @UnsupportedAppUsage
     public List<BluetoothDevice> getActiveDevices() {
         if (VDBG) log("getActiveDevices()");
         try {
diff --git a/core/java/android/bluetooth/BluetoothProfile.java b/core/java/android/bluetooth/BluetoothProfile.java
index ef77596..dabe0fd 100644
--- a/core/java/android/bluetooth/BluetoothProfile.java
+++ b/core/java/android/bluetooth/BluetoothProfile.java
@@ -276,7 +276,7 @@
      * #STATE_CONNECTING}, {@link #STATE_DISCONNECTED}, {@link #STATE_DISCONNECTING}
      */
     @RequiresPermission(Manifest.permission.BLUETOOTH)
-    public int getConnectionState(BluetoothDevice device);
+    @BtProfileState int getConnectionState(BluetoothDevice device);
 
     /**
      * An interface for notifying BluetoothProfile IPC clients when they have
diff --git a/core/java/android/companion/IFindDeviceCallback.aidl b/core/java/android/companion/IFindDeviceCallback.aidl
index 919e1519..4e9fa19 100644
--- a/core/java/android/companion/IFindDeviceCallback.aidl
+++ b/core/java/android/companion/IFindDeviceCallback.aidl
@@ -20,6 +20,7 @@
 
 /** @hide */
 interface IFindDeviceCallback {
+    @UnsupportedAppUsage
     void onSuccess(in PendingIntent launcher);
     void onFailure(in CharSequence reason);
 }
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 49a29f0a..fb933b1 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -3703,14 +3703,6 @@
 
     /**
      * Use with {@link #getSystemService(String)} to retrieve a
-     * {@link android.net.IpMemoryStore} to store and read information about
-     * known networks.
-     * @hide
-     */
-    public static final String IP_MEMORY_STORE_SERVICE = "ipmemorystore";
-
-    /**
-     * Use with {@link #getSystemService(String)} to retrieve a
      * {@link android.net.IpSecManager} for encrypting Sockets or Networks with
      * IPSec.
      *
@@ -4016,6 +4008,16 @@
 
     /**
      * Use with {@link #getSystemService(String)} to retrieve a
+     * {@link com.android.server.attention.AttentionManagerService} for attention services.
+     *
+     * @see #getSystemService(String)
+     * @see android.server.attention.AttentionManagerService
+     * @hide
+     */
+    public static final String ATTENTION_SERVICE = "attention";
+
+    /**
+     * Use with {@link #getSystemService(String)} to retrieve a
      * {@link android.view.inputmethod.InputMethodManager} for accessing input
      * methods.
      *
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index a2d3f6a..6bb9498 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -1997,7 +1997,8 @@
     public static final String EXTRA_LAUNCHER_EXTRAS = "android.intent.extra.LAUNCHER_EXTRAS";
 
     /**
-     * Intent extra: ID of the shortcut used to send the share intent.
+     * Intent extra: ID of the shortcut used to send the share intent. Will be sent with
+     * {@link #ACTION_SEND}.
      *
      * @see ShortcutInfo#getId()
      *
@@ -2077,6 +2078,9 @@
      * <p>
      * Output: Nothing.
      * </p>
+     * <p class="note">
+     * This requires {@link android.Manifest.permission#GRANT_RUNTIME_PERMISSIONS} permission.
+     * </p>
      *
      * @see #EXTRA_PERMISSION_NAME
      * @see #EXTRA_PERMISSION_GROUP_NAME
@@ -2085,11 +2089,35 @@
      * @hide
      */
     @SystemApi
+    @RequiresPermission(android.Manifest.permission.GRANT_RUNTIME_PERMISSIONS)
     @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
     public static final String ACTION_REVIEW_PERMISSION_USAGE =
             "android.intent.action.REVIEW_PERMISSION_USAGE";
 
     /**
+     * Activity action: Launch UI to review ongoing app uses of permissions.
+     * <p>
+     * Input: {@link #EXTRA_DURATION_MILLIS} specifies the minimum number of milliseconds of recent
+     * activity to show (optional).  Must be non-negative.
+     * </p>
+     * <p>
+     * Output: Nothing.
+     * </p>
+     * <p class="note">
+     * This requires {@link android.Manifest.permission#GRANT_RUNTIME_PERMISSIONS} permission.
+     * </p>
+     *
+     * @see #EXTRA_DURATION_MILLIS
+     *
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(android.Manifest.permission.GRANT_RUNTIME_PERMISSIONS)
+    @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+    public static final String ACTION_REVIEW_ONGOING_PERMISSION_USAGE =
+            "android.intent.action.REVIEW_ONGOING_PERMISSION_USAGE";
+
+    /**
      * Activity action: Launch UI to review uses of permissions for a single app.
      * <p>
      * Input: {@link #EXTRA_PACKAGE_NAME} specifies the package whose
@@ -2437,7 +2465,7 @@
      * Broadcast Action: A rollback has been committed.
      *
      * <p class="note">This is a protected intent that can only be sent
-     * by the system.
+     * by the system. The receiver must hold MANAGE_ROLLBACK permission.
      *
      * @hide
      */
diff --git a/core/java/android/content/om/OverlayManager.java b/core/java/android/content/om/OverlayManager.java
index 8e72fa5..ceea043 100644
--- a/core/java/android/content/om/OverlayManager.java
+++ b/core/java/android/content/om/OverlayManager.java
@@ -16,12 +16,14 @@
 
 package android.content.om;
 
+import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.SystemApi;
 import android.annotation.SystemService;
 import android.content.Context;
 import android.os.RemoteException;
 import android.os.ServiceManager;
+import android.os.UserHandle;
 
 import java.util.List;
 
@@ -96,6 +98,28 @@
     }
 
     /**
+     * Returns information about the overlay with the given package name for
+     * the specified user.
+     *
+     * @param packageName The name of the package.
+     * @param userHandle The user to get the OverlayInfos for.
+     * @return An OverlayInfo object; if no overlays exist with the
+     *         requested package name, null is returned.
+     *
+     * @hide
+     */
+    @SystemApi
+    @Nullable
+    public OverlayInfo getOverlayInfo(@NonNull final String packageName,
+            @NonNull final UserHandle userHandle) {
+        try {
+            return mService.getOverlayInfo(packageName, userHandle.myUserId());
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
      * Returns information about all overlays for the given target package for
      * the specified user. The returned list is ordered according to the
      * overlay priority with the highest priority at the end of the list.
diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java
index 706cbbf..068a93a 100644
--- a/core/java/android/content/pm/ApplicationInfo.java
+++ b/core/java/android/content/pm/ApplicationInfo.java
@@ -671,6 +671,14 @@
      */
     public static final int PRIVATE_FLAG_ALLOW_AUDIO_PLAYBACK_CAPTURE  = 1 << 27;
 
+    /**
+     * Indicates whether this package is in fact a runtime resource overlay.
+     *
+     * @hide
+     */
+    public static final int PRIVATE_FLAG_IS_RESOURCE_OVERLAY = 1 << 28;
+
+
     /** @hide */
     @IntDef(flag = true, prefix = { "PRIVATE_FLAG_" }, value = {
             PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_RESIZEABLE,
@@ -683,6 +691,7 @@
             PRIVATE_FLAG_HAS_DOMAIN_URLS,
             PRIVATE_FLAG_HIDDEN,
             PRIVATE_FLAG_INSTANT,
+            PRIVATE_FLAG_IS_RESOURCE_OVERLAY,
             PRIVATE_FLAG_ISOLATED_SPLIT_LOADING,
             PRIVATE_FLAG_OEM,
             PRIVATE_FLAG_PARTIALLY_DIRECT_BOOT_AWARE,
@@ -2023,6 +2032,14 @@
     }
 
     /**
+     * Returns true if the package has declared in its manifest that it is a
+     * runtime resource overlay.
+     */
+    public boolean isResourceOverlay() {
+        return (privateFlags & ApplicationInfo.PRIVATE_FLAG_IS_RESOURCE_OVERLAY) != 0;
+    }
+
+    /**
      * @hide
      */
     @Override protected ApplicationInfo getApplicationInfo() {
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index fd3529b..464e866 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -742,7 +742,7 @@
 
     String getAppPredictionServicePackageName();
 
-    String getContentCaptureServicePackageName();
+    String getSystemCaptionsServicePackageName();
 
     String getIncidentReportApproverPackageName();
 
diff --git a/core/java/android/content/pm/LauncherApps.java b/core/java/android/content/pm/LauncherApps.java
index 2a19763..954deac 100644
--- a/core/java/android/content/pm/LauncherApps.java
+++ b/core/java/android/content/pm/LauncherApps.java
@@ -142,17 +142,6 @@
     public static final String EXTRA_PIN_ITEM_REQUEST =
             "android.content.pm.extra.PIN_ITEM_REQUEST";
 
-    /**
-     * Metadata key that specifies vouched certs, so any apps signed by a cert in vouched certs
-     * will not show hidden icon in launcher even it does not have a launcher visible activity.
-     *
-     * If an app has this metadata in manifest, it won't be eligible to hide its icon even if its
-     * cert is in vouched certs list.
-     *
-     * @hide
-     */
-    public static final String VOUCHED_CERTS_KEY = "vouched_certs";
-
     private final Context mContext;
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     private final ILauncherApps mService;
diff --git a/core/java/android/content/pm/PackageInstaller.java b/core/java/android/content/pm/PackageInstaller.java
index 33b9c72..3edd17a 100644
--- a/core/java/android/content/pm/PackageInstaller.java
+++ b/core/java/android/content/pm/PackageInstaller.java
@@ -1448,19 +1448,6 @@
         }
 
         /**
-         * Request that rollbacks be enabled for the given upgrade.
-         *
-         * @removed
-         * @deprecated use {@link #setEnableRollback(boolean)} instead.
-         * @hide
-         */
-        @Deprecated
-        @SystemApi
-        public void setEnableRollback() {
-            installFlags |= PackageManager.INSTALL_ENABLE_ROLLBACK;
-        }
-
-        /**
          * Request that rollbacks be enabled or disabled for the given upgrade.
          *
          * @param enable set to {@code true} to enable, {@code false} to disable
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 99324ba..73e6f67 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -2589,14 +2589,6 @@
     public static final String FEATURE_PC = "android.hardware.type.pc";
 
     /**
-     * Feature for {@link #getSystemAvailableFeatures} and
-     * {@link #hasSystemFeature}: This is a foldable device. Properties such as
-     * the display size may change in response to being folded.
-     */
-    @SdkConstant(SdkConstantType.FEATURE)
-    public static final String FEATURE_FOLDABLE = "android.hardware.type.foldable";
-
-    /**
      * Feature for {@link #getSystemAvailableFeatures} and {@link #hasSystemFeature}:
      * The device supports printing.
      */
@@ -3073,6 +3065,15 @@
     public static final int FLAG_PERMISSION_USER_SENSITIVE_WHEN_DENIED =  1 << 9;
 
     /**
+     * Permission flag: The permission should not be shown in the UI.
+     *
+     * @hide
+     */
+    @SystemApi
+    @TestApi
+    public static final int FLAG_PERMISSION_HIDDEN =  1 << 10;
+
+    /**
      * Mask for all permission flags present in Android P
      *
      * @deprecated This constant does not contain useful information and should never have been
@@ -3090,7 +3091,7 @@
      *
      * @hide
      */
-    public static final int MASK_PERMISSION_FLAGS_ALL = 0x3FF;
+    public static final int MASK_PERMISSION_FLAGS_ALL = 0x7FF;
 
     /**
      * Injected activity in app that forwards user to setting activity of that app.
@@ -3801,6 +3802,7 @@
             FLAG_PERMISSION_GRANTED_BY_DEFAULT,
             FLAG_PERMISSION_USER_SENSITIVE_WHEN_GRANTED,
             FLAG_PERMISSION_USER_SENSITIVE_WHEN_DENIED,
+            FLAG_PERMISSION_HIDDEN,
             /*
             FLAG_PERMISSION_REVOKE_WHEN_REQUESED
             */
@@ -5651,7 +5653,9 @@
      * @deprecated This function no longer does anything. It is the platform's
      * responsibility to assign preferred activities and this cannot be modified
      * directly. To determine the activities resolved by the platform, use
-     * {@link #resolveActivity} or {@link #queryIntentActivities}.
+     * {@link #resolveActivity} or {@link #queryIntentActivities}. To configure
+     * an app to be responsible for a particular role and to check current role
+     * holders, see {@link android.app.role.RoleManager}.
      */
     @Deprecated
     public abstract void addPackageToPreferred(String packageName);
@@ -5660,7 +5664,9 @@
      * @deprecated This function no longer does anything. It is the platform's
      * responsibility to assign preferred activities and this cannot be modified
      * directly. To determine the activities resolved by the platform, use
-     * {@link #resolveActivity} or {@link #queryIntentActivities}.
+     * {@link #resolveActivity} or {@link #queryIntentActivities}. To configure
+     * an app to be responsible for a particular role and to check current role
+     * holders, see {@link android.app.role.RoleManager}.
      */
     @Deprecated
     public abstract void removePackageFromPreferred(String packageName);
@@ -5677,7 +5683,9 @@
      * @deprecated This function no longer does anything. It is the platform's
      * responsibility to assign preferred activities and this cannot be modified
      * directly. To determine the activities resolved by the platform, use
-     * {@link #resolveActivity} or {@link #queryIntentActivities}.
+     * {@link #resolveActivity} or {@link #queryIntentActivities}. To configure
+     * an app to be responsible for a particular role and to check current role
+     * holders, see {@link android.app.role.RoleManager}.
      */
     @Deprecated
     public abstract List<PackageInfo> getPreferredPackages(@PackageInfoFlags int flags);
@@ -5700,7 +5708,9 @@
      * @deprecated This function no longer does anything. It is the platform's
      * responsibility to assign preferred activities and this cannot be modified
      * directly. To determine the activities resolved by the platform, use
-     * {@link #resolveActivity} or {@link #queryIntentActivities}.
+     * {@link #resolveActivity} or {@link #queryIntentActivities}. To configure
+     * an app to be responsible for a particular role and to check current role
+     * holders, see {@link android.app.role.RoleManager}.
      */
     @Deprecated
     public abstract void addPreferredActivity(IntentFilter filter, int match,
@@ -5715,7 +5725,9 @@
      * @deprecated This function no longer does anything. It is the platform's
      * responsibility to assign preferred activities and this cannot be modified
      * directly. To determine the activities resolved by the platform, use
-     * {@link #resolveActivity} or {@link #queryIntentActivities}.
+     * {@link #resolveActivity} or {@link #queryIntentActivities}. To configure
+     * an app to be responsible for a particular role and to check current role
+     * holders, see {@link android.app.role.RoleManager}.
      */
     @Deprecated
     @UnsupportedAppUsage
@@ -5745,7 +5757,9 @@
      * @deprecated This function no longer does anything. It is the platform's
      * responsibility to assign preferred activities and this cannot be modified
      * directly. To determine the activities resolved by the platform, use
-     * {@link #resolveActivity} or {@link #queryIntentActivities}.
+     * {@link #resolveActivity} or {@link #queryIntentActivities}. To configure
+     * an app to be responsible for a particular role and to check current role
+     * holders, see {@link android.app.role.RoleManager}.
      */
     @Deprecated
     @UnsupportedAppUsage
@@ -5771,7 +5785,9 @@
      * @deprecated This function no longer does anything. It is the platform's
      * responsibility to assign preferred activities and this cannot be modified
      * directly. To determine the activities resolved by the platform, use
-     * {@link #resolveActivity} or {@link #queryIntentActivities}.
+     * {@link #resolveActivity} or {@link #queryIntentActivities}. To configure
+     * an app to be responsible for a particular role and to check current role
+     * holders, see {@link android.app.role.RoleManager}.
      */
     @Deprecated
     @SystemApi
@@ -5786,7 +5802,9 @@
      * @deprecated This function no longer does anything. It is the platform's
      * responsibility to assign preferred activities and this cannot be modified
      * directly. To determine the activities resolved by the platform, use
-     * {@link #resolveActivity} or {@link #queryIntentActivities}.
+     * {@link #resolveActivity} or {@link #queryIntentActivities}. To configure
+     * an app to be responsible for a particular role and to check current role
+     * holders, see {@link android.app.role.RoleManager}.
      */
     @Deprecated
     @UnsupportedAppUsage
@@ -5807,7 +5825,9 @@
      * @deprecated This function no longer does anything. It is the platform's
      * responsibility to assign preferred activities and this cannot be modified
      * directly. To determine the activities resolved by the platform, use
-     * {@link #resolveActivity} or {@link #queryIntentActivities}.
+     * {@link #resolveActivity} or {@link #queryIntentActivities}. To configure
+     * an app to be responsible for a particular role and to check current role
+     * holders, see {@link android.app.role.RoleManager}.
      */
     @Deprecated
     public abstract void clearPackagePreferredActivities(String packageName);
@@ -5832,7 +5852,9 @@
      * @deprecated This function no longer does anything. It is the platform's
      * responsibility to assign preferred activities and this cannot be modified
      * directly. To determine the activities resolved by the platform, use
-     * {@link #resolveActivity} or {@link #queryIntentActivities}.
+     * {@link #resolveActivity} or {@link #queryIntentActivities}. To configure
+     * an app to be responsible for a particular role and to check current role
+     * holders, see {@link android.app.role.RoleManager}.
      */
     @Deprecated
     public abstract int getPreferredActivities(@NonNull List<IntentFilter> outFilters,
@@ -5899,9 +5921,8 @@
      * @param packageName The package name of the app
      * @return Returns the enabled state for the synthetic app details activity.
      *
-     * @hide
+     *
      */
-    @SystemApi
     public boolean getSyntheticAppDetailsActivityEnabled(@NonNull String packageName) {
         throw new UnsupportedOperationException(
                 "getSyntheticAppDetailsActivityEnabled not implemented");
@@ -6594,6 +6615,7 @@
             case FLAG_PERMISSION_REVOKE_WHEN_REQUESTED: return "REVOKE_WHEN_REQUESTED";
             case FLAG_PERMISSION_USER_SENSITIVE_WHEN_GRANTED: return "USER_SENSITIVE_WHEN_GRANTED";
             case FLAG_PERMISSION_USER_SENSITIVE_WHEN_DENIED: return "USER_SENSITIVE_WHEN_DENIED";
+            case FLAG_PERMISSION_HIDDEN: return "HIDDEN";
             default: return Integer.toString(flag);
         }
     }
@@ -6863,9 +6885,9 @@
      *
      * @hide
      */
-    public String getContentCaptureServicePackageName() {
+    public String getSystemCaptionsServicePackageName() {
         throw new UnsupportedOperationException(
-                "getContentCaptureServicePackageName not implemented in subclass");
+                "getSystemCaptionsServicePackageName not implemented in subclass");
     }
 
     /**
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index 9d0ece0..743a302 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -2108,6 +2108,9 @@
                     return null;
                 }
 
+                pkg.applicationInfo.privateFlags |=
+                    ApplicationInfo.PRIVATE_FLAG_IS_RESOURCE_OVERLAY;
+
                 XmlUtils.skipCurrentTag(parser);
 
             } else if (tagName.equals(TAG_KEY_SETS)) {
diff --git a/core/java/android/content/pm/SharedLibraryInfo.java b/core/java/android/content/pm/SharedLibraryInfo.java
index 13c49a0..3488cc3 100644
--- a/core/java/android/content/pm/SharedLibraryInfo.java
+++ b/core/java/android/content/pm/SharedLibraryInfo.java
@@ -307,9 +307,9 @@
 
     @Override
     public String toString() {
-        return "SharedLibraryInfo[name:" + mName + ", type:" + typeToString(mType)
+        return "SharedLibraryInfo{name:" + mName + ", type:" + typeToString(mType)
                 + ", version:" + mVersion + (!getDependentPackages().isEmpty()
-                ? " has dependents" : "");
+                ? " has dependents" : "") + "}";
     }
 
     @Override
diff --git a/core/java/android/content/pm/ShortcutInfo.java b/core/java/android/content/pm/ShortcutInfo.java
index 7b61807..1f82fa6 100644
--- a/core/java/android/content/pm/ShortcutInfo.java
+++ b/core/java/android/content/pm/ShortcutInfo.java
@@ -1270,8 +1270,8 @@
          * system services even after it has been unpublished as a dynamic shortcut.
          */
         @NonNull
-        public Builder setLongLived() {
-            mIsLongLived = true;
+        public Builder setLongLived(boolean londLived) {
+            mIsLongLived = londLived;
             return this;
         }
 
diff --git a/core/java/android/content/res/Resources.java b/core/java/android/content/res/Resources.java
index 6729242..6b8416d 100644
--- a/core/java/android/content/res/Resources.java
+++ b/core/java/android/content/res/Resources.java
@@ -191,9 +191,9 @@
 
     /**
      * Return a global shared Resources object that provides access to only
-     * system resources (no application resources), and is not configured for
-     * the current screen (can not use dimension units, does not change based
-     * on orientation, etc).
+     * system resources (no application resources), is not configured for the
+     * current screen (can not use dimension units, does not change based on
+     * orientation, etc), and is not affected by Runtime Resource Overlay.
      */
     public static Resources getSystem() {
         synchronized (sSync) {
diff --git a/core/java/android/content/rollback/RollbackManager.java b/core/java/android/content/rollback/RollbackManager.java
index 9038b03..d54a6fe 100644
--- a/core/java/android/content/rollback/RollbackManager.java
+++ b/core/java/android/content/rollback/RollbackManager.java
@@ -24,6 +24,7 @@
 import android.annotation.TestApi;
 import android.content.Context;
 import android.content.IntentSender;
+import android.content.pm.PackageInstaller;
 import android.content.pm.ParceledListSlice;
 import android.content.pm.VersionedPackage;
 import android.os.RemoteException;
@@ -48,6 +49,24 @@
     private final String mCallerPackageName;
     private final IRollbackManager mBinder;
 
+    /**
+     * Lifetime duration of rollback packages in millis. A rollback will be available for
+     * at most that duration of time after a package is installed with
+     * {@link PackageInstaller.SessionParams#setEnableRollback()}.
+     *
+     * <p>If flag value is negative, the default value will be assigned.
+     *
+     * @see RollbackManager
+     *
+     * Flag type: {@code long}
+     * Namespace: NAMESPACE_ROLLBACK_BOOT
+     *
+     * @hide
+     */
+    @TestApi
+    public static final String PROPERTY_ROLLBACK_LIFETIME_MILLIS =
+            "rollback_lifetime_in_millis";
+
     /** {@hide} */
     public RollbackManager(Context context, IRollbackManager binder) {
         mCallerPackageName = context.getPackageName();
@@ -57,10 +76,12 @@
     /**
      * Returns a list of all currently available rollbacks.
      *
-     * @throws SecurityException if the caller does not have the
-     *            MANAGE_ROLLBACKS permission.
+     * @throws SecurityException if the caller does not have appropriate permissions.
      */
-    @RequiresPermission(android.Manifest.permission.MANAGE_ROLLBACKS)
+    @RequiresPermission(anyOf = {
+            android.Manifest.permission.MANAGE_ROLLBACKS,
+            android.Manifest.permission.TEST_MANAGE_ROLLBACKS
+    })
     @NonNull
     public List<RollbackInfo> getAvailableRollbacks() {
         try {
@@ -85,10 +106,12 @@
      * rolled back from.
      *
      * @return the recently committed rollbacks
-     * @throws SecurityException if the caller does not have the
-     *            MANAGE_ROLLBACKS permission.
+     * @throws SecurityException if the caller does not have appropriate permissions.
      */
-    @RequiresPermission(android.Manifest.permission.MANAGE_ROLLBACKS)
+    @RequiresPermission(anyOf = {
+            android.Manifest.permission.MANAGE_ROLLBACKS,
+            android.Manifest.permission.TEST_MANAGE_ROLLBACKS
+    })
     public @NonNull List<RollbackInfo> getRecentlyCommittedRollbacks() {
         try {
             return mBinder.getRecentlyExecutedRollbacks().getList();
@@ -171,10 +194,12 @@
      * @param statusReceiver where to deliver the results. Intents sent to
      *                       this receiver contain {@link #EXTRA_STATUS}
      *                       and {@link #EXTRA_STATUS_MESSAGE}.
-     * @throws SecurityException if the caller does not have the
-     *            MANAGE_ROLLBACKS permission.
+     * @throws SecurityException if the caller does not have appropriate permissions.
      */
-    @RequiresPermission(android.Manifest.permission.MANAGE_ROLLBACKS)
+    @RequiresPermission(anyOf = {
+            android.Manifest.permission.MANAGE_ROLLBACKS,
+            android.Manifest.permission.TEST_MANAGE_ROLLBACKS
+    })
     public void commitRollback(int rollbackId, @NonNull List<VersionedPackage> causePackages,
             @NonNull IntentSender statusReceiver) {
         try {
@@ -191,12 +216,11 @@
      * across device reboot, by simulating what happens on reboot without
      * actually rebooting the device.
      *
-     * @throws SecurityException if the caller does not have the
-     *            MANAGE_ROLLBACKS permission.
+     * @throws SecurityException if the caller does not have appropriate permissions.
      *
      * @hide
      */
-    @RequiresPermission(android.Manifest.permission.MANAGE_ROLLBACKS)
+    @RequiresPermission(android.Manifest.permission.TEST_MANAGE_ROLLBACKS)
     @TestApi
     public void reloadPersistedData() {
         try {
@@ -213,12 +237,11 @@
      * recently committed rollbacks that contain the given package.
      *
      * @param packageName the name of the package to expire data for.
-     * @throws SecurityException if the caller does not have the
-     *            MANAGE_ROLLBACKS permission.
+     * @throws SecurityException if the caller does not have appropriate permissions.
      *
      * @hide
      */
-    @RequiresPermission(android.Manifest.permission.MANAGE_ROLLBACKS)
+    @RequiresPermission(android.Manifest.permission.TEST_MANAGE_ROLLBACKS)
     @TestApi
     public void expireRollbackForPackage(@NonNull String packageName) {
         try {
diff --git a/core/java/android/database/sqlite/SQLiteGlobal.java b/core/java/android/database/sqlite/SQLiteGlobal.java
index d796003..5e2875d 100644
--- a/core/java/android/database/sqlite/SQLiteGlobal.java
+++ b/core/java/android/database/sqlite/SQLiteGlobal.java
@@ -176,6 +176,6 @@
 
     /** @hide */
     public static boolean checkDbWipe() {
-        return true;
+        return false;
     }
 }
diff --git a/core/java/android/hardware/biometrics/BiometricFaceConstants.java b/core/java/android/hardware/biometrics/BiometricFaceConstants.java
index 6ea35f0..bae0fd3 100644
--- a/core/java/android/hardware/biometrics/BiometricFaceConstants.java
+++ b/core/java/android/hardware/biometrics/BiometricFaceConstants.java
@@ -315,7 +315,7 @@
     /**
      * The sensor is dirty. The user should be informed to clean the sensor.
      */
-    public static final int SENSOR_DIRTY = 21;
+    public static final int FACE_ACQUIRED_SENSOR_DIRTY = 21;
 
     /**
      * Hardware vendors may extend this list if there are conditions that do not fall under one of
diff --git a/core/java/android/hardware/biometrics/BiometricPrompt.java b/core/java/android/hardware/biometrics/BiometricPrompt.java
index e751b2c..08035972 100644
--- a/core/java/android/hardware/biometrics/BiometricPrompt.java
+++ b/core/java/android/hardware/biometrics/BiometricPrompt.java
@@ -523,6 +523,11 @@
      * cancelled notification through {@link AuthenticationCallback#onAuthenticationError(int,
      * CharSequence)}.
      *
+     * Note: Applications generally should not cancel and start authentication in quick succession.
+     * For example, to properly handle authentication across configuration changes, it's recommended
+     * to use BiometricPrompt in a fragment with setRetainInstance(true). By doing so, the
+     * application will not need to cancel/restart authentication during the configuration change.
+     *
      * @throws IllegalArgumentException If any of the arguments are null
      *
      * @param crypto Object associated with the call
@@ -568,6 +573,11 @@
      * authentication. The interrupted client will receive a cancelled notification through {@link
      * AuthenticationCallback#onAuthenticationError(int, CharSequence)}.
      *
+     * Note: Applications generally should not cancel and start authentication in quick succession.
+     * For example, to properly handle authentication across configuration changes, it's recommended
+     * to use BiometricPrompt in a fragment with setRetainInstance(true). By doing so, the
+     * application will not need to cancel/restart authentication during the configuration change.
+     *
      * @throws IllegalArgumentException If any of the arguments are null
      *
      * @param cancel An object that can be used to cancel authentication
diff --git a/core/java/android/hardware/camera2/CameraCharacteristics.java b/core/java/android/hardware/camera2/CameraCharacteristics.java
index 7ae673c..c39796b 100644
--- a/core/java/android/hardware/camera2/CameraCharacteristics.java
+++ b/core/java/android/hardware/camera2/CameraCharacteristics.java
@@ -336,6 +336,7 @@
      * <li>{@link RecommendedStreamConfigurationMap#USECASE_SNAPSHOT}</li>
      * <li>{@link RecommendedStreamConfigurationMap#USECASE_RAW}</li>
      * <li>{@link RecommendedStreamConfigurationMap#USECASE_ZSL}</li>
+     * <li>{@link RecommendedStreamConfigurationMap#USECASE_LOW_LATENCY_SNAPSHOT}</li>
      * </ul>
      * </p>
      *
@@ -400,7 +401,7 @@
     public @Nullable RecommendedStreamConfigurationMap getRecommendedStreamConfigurationMap(
             @RecommendedStreamConfigurationMap.RecommendedUsecase int usecase) {
         if (((usecase >= RecommendedStreamConfigurationMap.USECASE_PREVIEW) &&
-                (usecase <= RecommendedStreamConfigurationMap.USECASE_RAW)) ||
+                (usecase <= RecommendedStreamConfigurationMap.USECASE_LOW_LATENCY_SNAPSHOT)) ||
                 ((usecase >= RecommendedStreamConfigurationMap.USECASE_VENDOR_START) &&
                 (usecase < RecommendedStreamConfigurationMap.MAX_USECASE_COUNT))) {
             if (mRecommendedConfigurations == null) {
diff --git a/core/java/android/hardware/camera2/impl/CameraMetadataNative.java b/core/java/android/hardware/camera2/impl/CameraMetadataNative.java
index 1cdf235..e909c00 100644
--- a/core/java/android/hardware/camera2/impl/CameraMetadataNative.java
+++ b/core/java/android/hardware/camera2/impl/CameraMetadataNative.java
@@ -1113,8 +1113,10 @@
                         depthStreamDurationList.get(i), depthStreamStallList.get(i), depthScData);
             }
 
-            if ((scData.streamConfigurationArray == null) &&
-                    (depthScData.streamConfigurationArray == null)) {
+            if ((scData.streamConfigurationArray == null ||
+                    scData.streamConfigurationArray.length == 0) &&
+                    (depthScData.streamConfigurationArray == null ||
+                     depthScData.streamConfigurationArray.length == 0)) {
                 recommendedConfigurations.add(null);
                 continue;
             }
@@ -1125,6 +1127,7 @@
             switch (i) {
                 case RecommendedStreamConfigurationMap.USECASE_PREVIEW:
                 case RecommendedStreamConfigurationMap.USECASE_RAW:
+                case RecommendedStreamConfigurationMap.USECASE_LOW_LATENCY_SNAPSHOT:
                 case RecommendedStreamConfigurationMap.USECASE_VIDEO_SNAPSHOT:
                     map = new StreamConfigurationMap(scData.streamConfigurationArray,
                             scData.minDurationArray, scData.stallDurationArray,
diff --git a/core/java/android/hardware/camera2/params/RecommendedStreamConfigurationMap.java b/core/java/android/hardware/camera2/params/RecommendedStreamConfigurationMap.java
index 068c0ce..2d72598 100644
--- a/core/java/android/hardware/camera2/params/RecommendedStreamConfigurationMap.java
+++ b/core/java/android/hardware/camera2/params/RecommendedStreamConfigurationMap.java
@@ -21,6 +21,7 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.graphics.ImageFormat;
+import android.graphics.ImageFormat.Format;
 import android.graphics.PixelFormat;
 import android.hardware.camera2.CameraCharacteristics;
 import android.hardware.camera2.CameraDevice;
@@ -137,6 +138,17 @@
     public static final int USECASE_RAW = 0x5;
 
     /**
+     * The recommended stream configuration map for use case low latency snapshot must contain
+     * subset of configurations with end-to-end latency that does not exceed 200 ms. under standard
+     * operating conditions (reasonable light levels, not loaded system). The expected output format
+     * will be primarily {@link android.graphics.ImageFormat#JPEG} however other image formats can
+     * be present as well.  Even if available for the camera device, high speed and input
+     * configurations will be absent. This suggested configuration map may be absent on some devices
+     * that can not support any low latency requests.
+     */
+    public static final int USECASE_LOW_LATENCY_SNAPSHOT = 0x6;
+
+    /**
      * Device specific use cases.
      * @hide
      */
@@ -150,7 +162,8 @@
         USECASE_VIDEO_SNAPSHOT,
         USECASE_SNAPSHOT,
         USECASE_ZSL,
-        USECASE_RAW })
+        USECASE_RAW,
+        USECASE_LOW_LATENCY_SNAPSHOT})
      public @interface RecommendedUsecase {};
 
     /**
@@ -214,7 +227,7 @@
      *
      * @return a non-modifiable set of Integer formats
      */
-    public @Nullable Set<Integer> getValidOutputFormatsForInput(int inputFormat) {
+    public @Nullable Set<Integer> getValidOutputFormatsForInput(@Format int inputFormat) {
         return getUnmodifiableIntegerSet(mRecommendedMap.getValidOutputFormatsForInput(
                     inputFormat));
     }
@@ -250,7 +263,7 @@
      * @param format a format from {@link #getInputFormats}
      * @return a non-modifiable set of sizes, or {@code null} if the format was not available.
      */
-    public @Nullable Set<Size> getInputSizes(int format) {
+    public @Nullable Set<Size> getInputSizes(@Format int format) {
         return getUnmodifiableSizeSet(mRecommendedMap.getInputSizes(format));
     }
 
@@ -272,7 +285,7 @@
      *          if the image format was not a defined named constant
      *          from either {@link ImageFormat} or {@link PixelFormat}
      */
-    public boolean isOutputSupportedFor(int format) {
+    public boolean isOutputSupportedFor(@Format int format) {
         return mRecommendedMap.isOutputSupportedFor(format);
     }
 
@@ -288,7 +301,7 @@
      * @return  a non-modifiable set of supported sizes,
      *          or {@code null} if the {@code format} is not a supported output
      */
-    public @Nullable Set<Size> getOutputSizes(int format) {
+    public @Nullable Set<Size> getOutputSizes(@Format int format) {
         return getUnmodifiableSizeSet(mRecommendedMap.getOutputSizes(format));
     }
 
@@ -372,7 +385,7 @@
      * @return a non-modifiable set of supported slower high-resolution sizes, or {@code null} if
      *         the BURST_CAPTURE capability is not supported
      */
-    public @Nullable Set<Size> getHighResolutionOutputSizes(int format) {
+    public @Nullable Set<Size> getHighResolutionOutputSizes(@Format int format) {
         return getUnmodifiableSizeSet(mRecommendedMap.getHighResolutionOutputSizes(format));
     }
 
@@ -392,7 +405,8 @@
      *
      * @throws IllegalArgumentException if {@code format} or {@code size} was not supported
      */
-    public @IntRange(from = 0) long getOutputMinFrameDuration(int format, @NonNull Size size) {
+    public @IntRange(from = 0) long getOutputMinFrameDuration(@Format int format,
+            @NonNull Size size) {
         return mRecommendedMap.getOutputMinFrameDuration(format, size);
     }
 
@@ -409,7 +423,7 @@
      *
      * @throws IllegalArgumentException if {@code format} or {@code size} was not supported
      */
-    public @IntRange(from = 0) long getOutputStallDuration(int format, @NonNull Size size) {
+    public @IntRange(from = 0) long getOutputStallDuration(@Format int format, @NonNull Size size) {
         return mRecommendedMap.getOutputStallDuration(format, size);
     }
 
@@ -425,7 +439,7 @@
      *          a non-modifiable set of supported sizes for {@link ImageFormat#PRIVATE} format,
      *          or {@code null} if the {@code klass} is not a supported output.
      */
-    public <T> @Nullable Set<Size> getOutputSizes(@NonNull Class<T> klass) {
+    public @Nullable <T> Set<Size> getOutputSizes(@NonNull Class<T> klass) {
         if (mSupportsPrivate) {
             return getUnmodifiableSizeSet(mRecommendedMap.getOutputSizes(klass));
         }
@@ -448,7 +462,7 @@
      *
      * @throws IllegalArgumentException if {@code klass} or {@code size} was not supported
      */
-    public <T> @IntRange(from = 0) long getOutputMinFrameDuration(@NonNull final Class<T> klass,
+    public @IntRange(from = 0) <T> long getOutputMinFrameDuration(@NonNull final Class<T> klass,
             @NonNull final Size size) {
         if (mSupportsPrivate) {
             return mRecommendedMap.getOutputMinFrameDuration(klass, size);
@@ -471,7 +485,7 @@
      *
      * @throws IllegalArgumentException if {@code klass} or {@code size} was not supported
      */
-    public <T> @IntRange(from = 0) long getOutputStallDuration(@NonNull final Class<T> klass,
+    public @IntRange(from = 0) <T> long getOutputStallDuration(@NonNull final Class<T> klass,
             @NonNull final Size size) {
         if (mSupportsPrivate) {
             return mRecommendedMap.getOutputStallDuration(klass, size);
diff --git a/core/java/android/hardware/camera2/utils/HashCodeHelpers.java b/core/java/android/hardware/camera2/utils/HashCodeHelpers.java
index 731da8b..526f086 100644
--- a/core/java/android/hardware/camera2/utils/HashCodeHelpers.java
+++ b/core/java/android/hardware/camera2/utils/HashCodeHelpers.java
@@ -16,6 +16,8 @@
 
 package android.hardware.camera2.utils;
 
+import android.annotation.UnsupportedAppUsage;
+
 /**
  * Provide hashing functions using the Modified Bernstein hash
  */
@@ -30,6 +32,7 @@
      *
      * @return the numeric hash code
      */
+    @UnsupportedAppUsage
     public static int hashCode(int... array) {
         if (array == null) {
             return 0;
diff --git a/core/java/android/hardware/display/BrightnessChangeEvent.java b/core/java/android/hardware/display/BrightnessChangeEvent.java
index 7fa1cfb..21fcc63 100644
--- a/core/java/android/hardware/display/BrightnessChangeEvent.java
+++ b/core/java/android/hardware/display/BrightnessChangeEvent.java
@@ -80,15 +80,23 @@
      * Histogram counting how many times a pixel of a given value was displayed onscreen for the
      * Value component of HSV if the device supports color sampling, if the device does not support
      * color sampling the value will be null.
+     *
      * The buckets of the histogram are evenly weighted, the number of buckets is device specific.
-     * For example if we had {10, 6, 4, 1} this means that 10 pixels were in the range
-     * [0x00,0x3f], 6 pixels were in the range [0x40,0x7f] etc.
+     * The units are in pixels * milliseconds, with 1 pixel millisecond being 1 pixel displayed
+     * for 1 millisecond.
+     * For example if we had {100, 50, 30, 20}, value component was onscreen for 100 pixel
+     * milliseconds in range 0x00->0x3F, 30 pixel milliseconds in range 0x40->0x7F, etc.
+     *
+     * {@see #colorSampleDuration}
      */
     @Nullable
     public final long[] colorValueBuckets;
 
     /**
-     * How many milliseconds of data are contained in the colorValueBuckets.
+     * How many milliseconds of data are contained in the colorValueBuckets, if the device does
+     * not support color sampling the value will be 0L.
+     *
+     * {@see #colorValueBuckets}
      */
     public final long colorSampleDuration;
 
@@ -283,7 +291,8 @@
             return this;
         }
 
-        /** {@see BrightnessChangeEvent#valueBuckets} */
+        /** {@see BrightnessChangeEvent#colorValueBuckets}
+         *  {@see BrightnessChangeEvent#colorSampleDuration} */
         public Builder setColorValues(@NonNull long[] colorValueBuckets, long colorSampleDuration) {
             Objects.requireNonNull(colorValueBuckets);
             mColorValueBuckets = colorValueBuckets;
diff --git a/core/java/android/hardware/display/DisplayedContentSample.java b/core/java/android/hardware/display/DisplayedContentSample.java
index 0610377..4a429bb 100644
--- a/core/java/android/hardware/display/DisplayedContentSample.java
+++ b/core/java/android/hardware/display/DisplayedContentSample.java
@@ -30,12 +30,14 @@
      * Construct an object representing a color histogram of pixels that were displayed on screen.
      *
      * @param numFrames The number of frames represented by this sample.
-     * @param mSamplesComponent0 is a histogram counting how many times a pixel of a given value
-     * was displayed onscreen for FORMAT_COMPONENT_0. The buckets of the histogram are evenly
-     * weighted, the number of buckets is device specific.
-     * eg, for RGBA_8888, if sampleComponent0 is {10, 6, 4, 1} this means that 10 red pixels were
-     * displayed onscreen in range 0x00->0x3F, 6 red pixels were displayed onscreen in range
-     * 0x40->0x7F, etc.
+     * @param mSamplesComponent0 is a histogram counting how many times and for how long a pixel
+     * of a given value was displayed onscreen for FORMAT_COMPONENT_0. The buckets of the
+     * histogram are evenly weighted, the number of buckets is device specific.
+     * The units are in pixels * milliseconds, with 1 pixel millisecond being 1 pixel displayed
+     * onscreen for 1ms.
+     * eg, for RGBA_8888, if sampleComponent0 is {100, 50, 30, 20},  then red component was
+     * onscreen for 100 pixel milliseconds in range 0x00->0x3F, 30 pixel milliseconds in
+     * range 0x40->0x7F, etc.
      * @param mSamplesComponent1 is the same sample definition as sampleComponent0, but for the
      * second component of format.
      * @param mSamplesComponent2 is the same sample definition as sampleComponent0, but for the
diff --git a/core/java/android/hardware/face/FaceManager.java b/core/java/android/hardware/face/FaceManager.java
index 139a5ee..3e8c334 100644
--- a/core/java/android/hardware/face/FaceManager.java
+++ b/core/java/android/hardware/face/FaceManager.java
@@ -634,6 +634,8 @@
                 return context.getString(R.string.face_acquired_obscured);
             case FACE_ACQUIRED_START:
                 return null;
+            case FACE_ACQUIRED_SENSOR_DIRTY:
+                return context.getString(R.string.face_acquired_sensor_dirty);
             case FACE_ACQUIRED_VENDOR: {
                 String[] msgArray = context.getResources().getStringArray(
                         R.array.face_acquired_vendor);
diff --git a/core/java/android/inputmethodservice/IInputMethodSessionWrapper.java b/core/java/android/inputmethodservice/IInputMethodSessionWrapper.java
index ffae361e..7d4849f 100644
--- a/core/java/android/inputmethodservice/IInputMethodSessionWrapper.java
+++ b/core/java/android/inputmethodservice/IInputMethodSessionWrapper.java
@@ -16,6 +16,7 @@
 
 package android.inputmethodservice;
 
+import android.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.graphics.Rect;
 import android.os.Bundle;
@@ -53,6 +54,7 @@
     private static final int DO_VIEW_CLICKED = 115;
     private static final int DO_NOTIFY_IME_HIDDEN = 120;
 
+    @UnsupportedAppUsage
     HandlerCaller mCaller;
     InputMethodSession mInputMethodSession;
     InputChannel mChannel;
diff --git a/core/java/android/inputmethodservice/IInputMethodWrapper.java b/core/java/android/inputmethodservice/IInputMethodWrapper.java
index 37b25c8..a47f601 100644
--- a/core/java/android/inputmethodservice/IInputMethodWrapper.java
+++ b/core/java/android/inputmethodservice/IInputMethodWrapper.java
@@ -18,6 +18,7 @@
 
 import android.annotation.BinderThread;
 import android.annotation.MainThread;
+import android.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.content.pm.PackageManager;
 import android.os.Binder;
@@ -74,6 +75,7 @@
 
     final WeakReference<AbstractInputMethodService> mTarget;
     final Context mContext;
+    @UnsupportedAppUsage
     final HandlerCaller mCaller;
     final WeakReference<InputMethod> mInputMethod;
     final int mTargetSdkVersion;
diff --git a/core/java/android/net/CaptivePortal.java b/core/java/android/net/CaptivePortal.java
index f208724..3e4e35a 100644
--- a/core/java/android/net/CaptivePortal.java
+++ b/core/java/android/net/CaptivePortal.java
@@ -15,6 +15,7 @@
  */
 package android.net;
 
+import android.annotation.NonNull;
 import android.annotation.SystemApi;
 import android.annotation.TestApi;
 import android.os.IBinder;
@@ -29,15 +30,33 @@
  * {@code ACTION_CAPTIVE_PORTAL_SIGN_IN} activity.
  */
 public class CaptivePortal implements Parcelable {
-    /** @hide */
+    /**
+     * Response code from the captive portal application, indicating that the portal was dismissed
+     * and the network should be re-validated.
+     * @see ICaptivePortal#appResponse(int)
+     * @see android.net.INetworkMonitor#notifyCaptivePortalAppFinished(int)
+     * @hide
+     */
     @SystemApi
     @TestApi
     public static final int APP_RETURN_DISMISSED    = 0;
-    /** @hide */
+    /**
+     * Response code from the captive portal application, indicating that the user did not login and
+     * does not want to use the captive portal network.
+     * @see ICaptivePortal#appResponse(int)
+     * @see android.net.INetworkMonitor#notifyCaptivePortalAppFinished(int)
+     * @hide
+     */
     @SystemApi
     @TestApi
     public static final int APP_RETURN_UNWANTED     = 1;
-    /** @hide */
+    /**
+     * Response code from the captive portal application, indicating that the user does not wish to
+     * login but wants to use the captive portal network as-is.
+     * @see ICaptivePortal#appResponse(int)
+     * @see android.net.INetworkMonitor#notifyCaptivePortalAppFinished(int)
+     * @hide
+     */
     @SystemApi
     @TestApi
     public static final int APP_RETURN_WANTED_AS_IS = 2;
@@ -47,7 +66,7 @@
     /** @hide */
     @SystemApi
     @TestApi
-    public CaptivePortal(IBinder binder) {
+    public CaptivePortal(@NonNull IBinder binder) {
         mBinder = binder;
     }
 
@@ -124,7 +143,7 @@
      */
     @SystemApi
     @TestApi
-    public void logEvent(int eventId, String packageName) {
+    public void logEvent(int eventId, @NonNull String packageName) {
         try {
             ICaptivePortal.Stub.asInterface(mBinder).logEvent(eventId, packageName);
         } catch (RemoteException e) {
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index d08379f..1632235 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -2816,23 +2816,6 @@
     }
 
     /**
-     * @removed
-     * @deprecated This API would be removed when all of caller has been updated.
-     * */
-    @Deprecated
-    public abstract static class TetheringEntitlementValueListener  {
-        /**
-         * Called to notify entitlement result.
-         *
-         * @param resultCode a int value of entitlement result. It may be one of
-         *         {@link #TETHER_ERROR_NO_ERROR},
-         *         {@link #TETHER_ERROR_PROVISION_FAILED}, or
-         *         {@link #TETHER_ERROR_ENTITLEMENT_UNKONWN}.
-         */
-        public void onEntitlementResult(int resultCode) {}
-    }
-
-    /**
      * Get the last value of the entitlement check on this downstream. If the cached value is
      * {@link #TETHER_ERROR_NO_ERROR} or showEntitlementUi argument is false, it just return the
      * cached value. Otherwise, a UI-based entitlement check would be performed. It is not
@@ -2878,31 +2861,6 @@
     }
 
     /**
-     * @removed
-     * @deprecated This API would be removed when all of caller has been updated.
-     * */
-    @Deprecated
-    public void getLatestTetheringEntitlementValue(int type, boolean showEntitlementUi,
-            @NonNull final TetheringEntitlementValueListener listener, @Nullable Handler handler) {
-        Preconditions.checkNotNull(listener, "TetheringEntitlementValueListener cannot be null.");
-        ResultReceiver wrappedListener = new ResultReceiver(handler) {
-            @Override
-            protected void onReceiveResult(int resultCode, Bundle resultData) {
-                listener.onEntitlementResult(resultCode);
-            }
-        };
-
-        try {
-            String pkgName = mContext.getOpPackageName();
-            Log.i(TAG, "getLatestTetheringEntitlementValue:" + pkgName);
-            mService.getLatestTetheringEntitlementResult(type, wrappedListener,
-                    showEntitlementUi, pkgName);
-        } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
-        }
-    }
-
-    /**
      * Report network connectivity status.  This is currently used only
      * to alter status bar UI.
      * <p>This method requires the caller to hold the permission
@@ -4130,7 +4088,7 @@
     @SystemApi
     @TestApi
     @RequiresPermission(NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK)
-    public void startCaptivePortalApp(Network network, Bundle appExtras) {
+    public void startCaptivePortalApp(@NonNull Network network, @NonNull Bundle appExtras) {
         try {
             mService.startCaptivePortalAppInternal(network, appExtras);
         } catch (RemoteException e) {
diff --git a/core/java/android/net/DnsPacket.java b/core/java/android/net/DnsPacket.java
index 0ac02b1..83e57e0 100644
--- a/core/java/android/net/DnsPacket.java
+++ b/core/java/android/net/DnsPacket.java
@@ -71,7 +71,7 @@
     }
 
     /**
-     * It's used both for DNS questions and DNS resource records.
+     * Superclass for DNS questions and DNS resource records.
      *
      * DNS questions (No TTL/RDATA)
      * DNS resource records (With TTL/RDATA)
@@ -96,12 +96,13 @@
         /**
          * Create a new DnsRecord from a positioned ByteBuffer.
          *
-         * @param ByteBuffer input of record, must be in network byte order
-         *         (which is the default).
          * Reads the passed ByteBuffer from its current position and decodes a DNS record.
          * When this constructor returns, the reading position of the ByteBuffer has been
          * advanced to the end of the DNS header record.
          * This is meant to chain with other methods reading a DNS response in sequence.
+         *
+         * @param ByteBuffer input of record, must be in network byte order
+         *         (which is the default).
          */
         DnsRecord(int recordType, @NonNull ByteBuffer buf)
                 throws BufferUnderflowException, ParseException {
@@ -205,16 +206,6 @@
     protected final DnsHeader mHeader;
     protected final List<DnsRecord>[] mRecords;
 
-    public static class ParseException extends Exception {
-        public ParseException(String msg) {
-            super(msg);
-        }
-
-        public ParseException(String msg, Throwable cause) {
-            super(msg, cause);
-        }
-    }
-
     protected DnsPacket(@NonNull byte[] data) throws ParseException {
         if (null == data) throw new ParseException("Parse header failed, null input data");
         final ByteBuffer buffer;
diff --git a/core/java/android/net/DnsResolver.java b/core/java/android/net/DnsResolver.java
index d3bc3e6..93b8cf8 100644
--- a/core/java/android/net/DnsResolver.java
+++ b/core/java/android/net/DnsResolver.java
@@ -22,11 +22,11 @@
 import static android.os.MessageQueue.OnFileDescriptorEventListener.EVENT_ERROR;
 import static android.os.MessageQueue.OnFileDescriptorEventListener.EVENT_INPUT;
 
+import android.annotation.CallbackExecutor;
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.os.Handler;
-import android.os.MessageQueue;
+import android.os.Looper;
 import android.system.ErrnoException;
 import android.util.Log;
 
@@ -37,8 +37,7 @@
 import java.net.UnknownHostException;
 import java.util.ArrayList;
 import java.util.List;
-import java.util.function.Consumer;
-
+import java.util.concurrent.Executor;
 
 /**
  * Dns resolver class for asynchronous dns querying
@@ -81,66 +80,137 @@
     public static final int FLAG_NO_CACHE_STORE = 1 << 1;
     public static final int FLAG_NO_CACHE_LOOKUP = 1 << 2;
 
-    private static final int DNS_RAW_RESPONSE = 1;
-
     private static final int NETID_UNSET = 0;
 
     private static final DnsResolver sInstance = new DnsResolver();
 
     /**
-     * listener for receiving raw answers
-     */
-    public interface RawAnswerListener {
-        /**
-         * {@code byte[]} is {@code null} if query timed out
-         */
-        void onAnswer(@Nullable byte[] answer);
-    }
-
-    /**
-     * listener for receiving parsed answers
-     */
-    public interface InetAddressAnswerListener {
-        /**
-         * Will be called exactly once with all the answers to the query.
-         * size of addresses will be zero if no available answer could be parsed.
-         */
-        void onAnswer(@NonNull List<InetAddress> addresses);
-    }
-
-    /**
      * Get instance for DnsResolver
      */
-    public static DnsResolver getInstance() {
+    public static @NonNull DnsResolver getInstance() {
         return sInstance;
     }
 
     private DnsResolver() {}
 
     /**
-     * Pass in a blob and corresponding setting,
-     * get a blob back asynchronously with the entire raw answer.
+     * Answer parser for parsing raw answers
+     *
+     * @param <T> The type of the parsed answer
+     */
+    public interface AnswerParser<T> {
+        /**
+         * Creates a <T> answer by parsing the given raw answer.
+         *
+         * @param rawAnswer the raw answer to be parsed
+         * @return a parsed <T> answer
+         * @throws ParseException if parsing failed
+         */
+        @NonNull T parse(@NonNull byte[] rawAnswer) throws ParseException;
+    }
+
+    /**
+     * Base class for answer callbacks
+     *
+     * @param <T> The type of the parsed answer
+     */
+    public abstract static class AnswerCallback<T> {
+        /** @hide */
+        public final AnswerParser<T> parser;
+
+        public AnswerCallback(@NonNull AnswerParser<T> parser) {
+            this.parser = parser;
+        };
+
+        /**
+         * Success response to
+         * {@link android.net.DnsResolver#query query()}.
+         *
+         * Invoked when the answer to a query was successfully parsed.
+         *
+         * @param answer parsed answer to the query.
+         *
+         * {@see android.net.DnsResolver#query query()}
+         */
+        public abstract void onAnswer(@NonNull T answer);
+
+        /**
+         * Error response to
+         * {@link android.net.DnsResolver#query query()}.
+         *
+         * Invoked when there is no valid answer to
+         * {@link android.net.DnsResolver#query query()}
+         *
+         * @param exception a {@link ParseException} object with additional
+         *    detail regarding the failure
+         */
+        public abstract void onParseException(@NonNull ParseException exception);
+
+        /**
+         * Error response to
+         * {@link android.net.DnsResolver#query query()}.
+         *
+         * Invoked if an error happens when
+         * issuing the DNS query or receiving the result.
+         * {@link android.net.DnsResolver#query query()}
+         *
+         * @param exception an {@link ErrnoException} object with additional detail
+         *    regarding the failure
+         */
+        public abstract void onQueryException(@NonNull ErrnoException exception);
+    }
+
+    /**
+     * Callback for receiving raw answers
+     */
+    public abstract static class RawAnswerCallback extends AnswerCallback<byte[]> {
+        public RawAnswerCallback() {
+            super(rawAnswer -> rawAnswer);
+        }
+    }
+
+    /**
+     * Callback for receiving parsed {@link InetAddress} answers
+     *
+     * Note that if the answer does not contain any IP addresses,
+     * onAnswer will be called with an empty list.
+     */
+    public abstract static class InetAddressAnswerCallback
+            extends AnswerCallback<List<InetAddress>> {
+        public InetAddressAnswerCallback() {
+            super(rawAnswer -> new DnsAddressAnswer(rawAnswer).getAddresses());
+        }
+    }
+
+    /**
+     * Send a raw DNS query.
+     * The answer will be provided asynchronously through the provided {@link AnswerCallback}.
      *
      * @param network {@link Network} specifying which network for querying.
      *         {@code null} for query on default network.
      * @param query blob message
      * @param flags flags as a combination of the FLAGS_* constants
-     * @param handler {@link Handler} to specify the thread
-     *         upon which the {@link RawAnswerListener} will be invoked.
-     * @param listener a {@link RawAnswerListener} which will be called to notify the caller
+     * @param executor The {@link Executor} that the callback should be executed on.
+     * @param callback an {@link AnswerCallback} which will be called to notify the caller
      *         of the result of dns query.
      */
-    public void query(@Nullable Network network, @NonNull byte[] query, @QueryFlag int flags,
-            @NonNull Handler handler, @NonNull RawAnswerListener listener) throws ErrnoException {
-        final FileDescriptor queryfd = resNetworkSend((network != null
+    public <T> void query(@Nullable Network network, @NonNull byte[] query, @QueryFlag int flags,
+            @NonNull @CallbackExecutor Executor executor, @NonNull AnswerCallback<T> callback) {
+        final FileDescriptor queryfd;
+        try {
+            queryfd = resNetworkSend((network != null
                 ? network.netId : NETID_UNSET), query, query.length, flags);
-        registerFDListener(handler.getLooper().getQueue(), queryfd,
-                answerbuf -> listener.onAnswer(answerbuf));
+        } catch (ErrnoException e) {
+            callback.onQueryException(e);
+            return;
+        }
+
+        registerFDListener(executor, queryfd, callback);
     }
 
     /**
-     * Pass in a domain name and corresponding setting,
-     * get a blob back asynchronously with the entire raw answer.
+     * Send a DNS query with the specified name, class and query type.
+     * The answer will be provided asynchronously through the provided {@link AnswerCallback}.
      *
      * @param network {@link Network} specifying which network for querying.
      *         {@code null} for query on default network.
@@ -148,74 +218,53 @@
      * @param nsClass dns class as one of the CLASS_* constants
      * @param nsType dns resource record (RR) type as one of the TYPE_* constants
      * @param flags flags as a combination of the FLAGS_* constants
-     * @param handler {@link Handler} to specify the thread
-     *         upon which the {@link RawAnswerListener} will be invoked.
-     * @param listener a {@link RawAnswerListener} which will be called to notify the caller
+     * @param executor The {@link Executor} that the callback should be executed on.
+     * @param callback an {@link AnswerCallback} which will be called to notify the caller
      *         of the result of dns query.
      */
-    public void query(@Nullable Network network, @NonNull String domain, @QueryClass int nsClass,
-            @QueryType int nsType, @QueryFlag int flags,
-            @NonNull Handler handler, @NonNull RawAnswerListener listener) throws ErrnoException {
-        final FileDescriptor queryfd = resNetworkQuery((network != null
-                ? network.netId : NETID_UNSET), domain, nsClass, nsType, flags);
-        registerFDListener(handler.getLooper().getQueue(), queryfd,
-                answerbuf -> listener.onAnswer(answerbuf));
+    public <T> void query(@Nullable Network network, @NonNull String domain,
+            @QueryClass int nsClass, @QueryType int nsType, @QueryFlag int flags,
+            @NonNull @CallbackExecutor Executor executor, @NonNull AnswerCallback<T> callback) {
+        final FileDescriptor queryfd;
+        try {
+            queryfd = resNetworkQuery((network != null
+                    ? network.netId : NETID_UNSET), domain, nsClass, nsType, flags);
+        } catch (ErrnoException e) {
+            callback.onQueryException(e);
+            return;
+        }
+        registerFDListener(executor, queryfd, callback);
     }
 
-    /**
-     * Pass in a domain name and corresponding setting,
-     * get back a set of InetAddresses asynchronously.
-     *
-     * @param network {@link Network} specifying which network for querying.
-     *         {@code null} for query on default network.
-     * @param domain domain name for querying
-     * @param flags flags as a combination of the FLAGS_* constants
-     * @param handler {@link Handler} to specify the thread
-     *         upon which the {@link InetAddressAnswerListener} will be invoked.
-     * @param listener an {@link InetAddressAnswerListener} which will be called to
-     *         notify the caller of the result of dns query.
-     *
-     */
-    public void query(@Nullable Network network, @NonNull String domain, @QueryFlag int flags,
-            @NonNull Handler handler, @NonNull InetAddressAnswerListener listener)
-            throws ErrnoException {
-        final FileDescriptor v4fd = resNetworkQuery((network != null
-                ? network.netId : NETID_UNSET), domain, CLASS_IN, TYPE_A, flags);
-        final FileDescriptor v6fd = resNetworkQuery((network != null
-                ? network.netId : NETID_UNSET), domain, CLASS_IN, TYPE_AAAA, flags);
-
-        final InetAddressAnswerAccumulator accmulator =
-                new InetAddressAnswerAccumulator(2, listener);
-        final Consumer<byte[]> consumer = answerbuf ->
-                accmulator.accumulate(parseAnswers(answerbuf));
-
-        registerFDListener(handler.getLooper().getQueue(), v4fd, consumer);
-        registerFDListener(handler.getLooper().getQueue(), v6fd, consumer);
-    }
-
-    private void registerFDListener(@NonNull MessageQueue queue,
-            @NonNull FileDescriptor queryfd, @NonNull Consumer<byte[]> answerConsumer) {
-        queue.addOnFileDescriptorEventListener(
+    private <T> void registerFDListener(@NonNull Executor executor,
+            @NonNull FileDescriptor queryfd, @NonNull AnswerCallback<T> answerCallback) {
+        Looper.getMainLooper().getQueue().addOnFileDescriptorEventListener(
                 queryfd,
                 FD_EVENTS,
                 (fd, events) -> {
-                    byte[] answerbuf = null;
-                    try {
-                    // TODO: Implement result function in Java side instead of using JNI
-                    //       Because JNI method close fd prior than unregistering fd on
-                    //       event listener.
-                        answerbuf = resNetworkResult(fd);
-                    } catch (ErrnoException e) {
-                        Log.e(TAG, "resNetworkResult:" + e.toString());
-                    }
-                    answerConsumer.accept(answerbuf);
+                    executor.execute(() -> {
+                        byte[] answerbuf = null;
+                        try {
+                            answerbuf = resNetworkResult(fd);
+                        } catch (ErrnoException e) {
+                            Log.e(TAG, "resNetworkResult:" + e.toString());
+                            answerCallback.onQueryException(e);
+                            return;
+                        }
 
+                        try {
+                            answerCallback.onAnswer(
+                                    answerCallback.parser.parse(answerbuf));
+                        } catch (ParseException e) {
+                            answerCallback.onParseException(e);
+                        }
+                    });
                     // Unregister this fd listener
                     return 0;
                 });
     }
 
-    private class DnsAddressAnswer extends DnsPacket {
+    private static class DnsAddressAnswer extends DnsPacket {
         private static final String TAG = "DnsResolver.DnsAddressAnswer";
         private static final boolean DBG = false;
 
@@ -226,12 +275,6 @@
             if ((mHeader.flags & (1 << 15)) == 0) {
                 throw new ParseException("Not an answer packet");
             }
-            if (mHeader.rcode != 0) {
-                throw new ParseException("Response error, rcode:" + mHeader.rcode);
-            }
-            if (mHeader.getRecordCount(ANSECTION) == 0) {
-                throw new ParseException("No available answer");
-            }
             if (mHeader.getRecordCount(QDSECTION) == 0) {
                 throw new ParseException("No question found");
             }
@@ -241,6 +284,8 @@
 
         public @NonNull List<InetAddress> getAddresses() {
             final List<InetAddress> results = new ArrayList<InetAddress>();
+            if (mHeader.getRecordCount(ANSECTION) == 0) return results;
+
             for (final DnsRecord ansSec : mRecords[ANSECTION]) {
                 // Only support A and AAAA, also ignore answers if query type != answer type.
                 int nsType = ansSec.nsType;
@@ -259,34 +304,4 @@
         }
     }
 
-    private @Nullable List<InetAddress> parseAnswers(@Nullable byte[] data) {
-        try {
-            return (data == null) ? null : new DnsAddressAnswer(data).getAddresses();
-        } catch (DnsPacket.ParseException e) {
-            Log.e(TAG, "Parse answer fail " + e.getMessage());
-            return null;
-        }
-    }
-
-    private class InetAddressAnswerAccumulator {
-        private final List<InetAddress> mAllAnswers;
-        private final InetAddressAnswerListener mAnswerListener;
-        private final int mTargetAnswerCount;
-        private int mReceivedAnswerCount = 0;
-
-        InetAddressAnswerAccumulator(int size, @NonNull InetAddressAnswerListener listener) {
-            mTargetAnswerCount = size;
-            mAllAnswers = new ArrayList<>();
-            mAnswerListener = listener;
-        }
-
-        public void accumulate(@Nullable List<InetAddress> answer) {
-            if (null != answer) {
-                mAllAnswers.addAll(answer);
-            }
-            if (++mReceivedAnswerCount == mTargetAnswerCount) {
-                mAnswerListener.onAnswer(mAllAnswers);
-            }
-        }
-    }
 }
diff --git a/media/java/android/media/session/SessionLink.aidl b/core/java/android/net/IIpMemoryStoreCallbacks.aidl
similarity index 69%
copy from media/java/android/media/session/SessionLink.aidl
copy to core/java/android/net/IIpMemoryStoreCallbacks.aidl
index c3be23e..53108db 100644
--- a/media/java/android/media/session/SessionLink.aidl
+++ b/core/java/android/net/IIpMemoryStoreCallbacks.aidl
@@ -1,5 +1,5 @@
 /*
- * Copyright 2019 The Android Open Source Project
+ * 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.
@@ -14,6 +14,11 @@
  * limitations under the License.
  */
 
-package android.media.session;
+package android.net;
 
-parcelable SessionLink;
+import android.net.IIpMemoryStore;
+
+/** {@hide} */
+oneway interface IIpMemoryStoreCallbacks {
+    void onIpMemoryStoreFetched(in IIpMemoryStore ipMemoryStore);
+}
diff --git a/core/java/android/net/INetworkMonitor.aidl b/core/java/android/net/INetworkMonitor.aidl
index 5d1ab98..1b0e1d7 100644
--- a/core/java/android/net/INetworkMonitor.aidl
+++ b/core/java/android/net/INetworkMonitor.aidl
@@ -41,7 +41,7 @@
     void start();
     void launchCaptivePortalApp();
     void notifyCaptivePortalAppFinished(int response);
-    void notifyAcceptPartialConnectivity();
+    void setAcceptPartialConnectivity();
     void forceReevaluation(int uid);
     void notifyPrivateDnsChanged(in PrivateDnsConfigParcel config);
     void notifyDnsResponse(int returnCode);
diff --git a/core/java/android/net/INetworkStackConnector.aidl b/core/java/android/net/INetworkStackConnector.aidl
index edb9df6..3751c36 100644
--- a/core/java/android/net/INetworkStackConnector.aidl
+++ b/core/java/android/net/INetworkStackConnector.aidl
@@ -15,6 +15,7 @@
  */
 package android.net;
 
+import android.net.IIpMemoryStoreCallbacks;
 import android.net.INetworkMonitorCallbacks;
 import android.net.Network;
 import android.net.dhcp.DhcpServingParamsParcel;
@@ -27,4 +28,5 @@
         in IDhcpServerCallbacks cb);
     void makeNetworkMonitor(in Network network, String name, in INetworkMonitorCallbacks cb);
     void makeIpClient(in String ifName, in IIpClientCallbacks callbacks);
-}
\ No newline at end of file
+    void fetchIpMemoryStore(in IIpMemoryStoreCallbacks cb);
+}
diff --git a/core/java/android/net/InterfaceConfiguration.java b/core/java/android/net/InterfaceConfiguration.java
index c638491..c97b37b 100644
--- a/core/java/android/net/InterfaceConfiguration.java
+++ b/core/java/android/net/InterfaceConfiguration.java
@@ -19,11 +19,9 @@
 import android.annotation.UnsupportedAppUsage;
 import android.os.Parcel;
 import android.os.Parcelable;
-import android.text.TextUtils;
 
 import com.google.android.collect.Sets;
 
-import java.net.InetAddress;
 import java.util.HashSet;
 
 /**
@@ -117,40 +115,6 @@
     }
 
     /**
-     * Construct InterfaceConfiguration from InterfaceConfigurationParcel.
-     */
-    public static InterfaceConfiguration fromParcel(InterfaceConfigurationParcel p) {
-        InterfaceConfiguration cfg = new InterfaceConfiguration();
-        cfg.setHardwareAddress(p.hwAddr);
-
-        final InetAddress addr = NetworkUtils.numericToInetAddress(p.ipv4Addr);
-        cfg.setLinkAddress(new LinkAddress(addr, p.prefixLength));
-        for (String flag : p.flags) {
-            cfg.setFlag(flag);
-        }
-
-        return cfg;
-    }
-
-    /**
-     * Convert InterfaceConfiguration to InterfaceConfigurationParcel with given ifname.
-     */
-    public InterfaceConfigurationParcel toParcel(String iface) {
-        InterfaceConfigurationParcel cfgParcel = new InterfaceConfigurationParcel();
-        cfgParcel.ifName = iface;
-        if (!TextUtils.isEmpty(mHwAddr)) {
-            cfgParcel.hwAddr = mHwAddr;
-        } else {
-            cfgParcel.hwAddr = "";
-        }
-        cfgParcel.ipv4Addr = mAddr.getAddress().getHostAddress();
-        cfgParcel.prefixLength = mAddr.getPrefixLength();
-        cfgParcel.flags = mFlags.toArray(EMPTY_STRING_ARRAY);
-
-        return cfgParcel;
-    }
-
-    /**
      * This function determines if the interface is up and has a valid IP
      * configuration (IP address has a non zero octet).
      *
diff --git a/core/java/android/net/IpPrefix.java b/core/java/android/net/IpPrefix.java
index 21bbd30..402bffd 100644
--- a/core/java/android/net/IpPrefix.java
+++ b/core/java/android/net/IpPrefix.java
@@ -16,6 +16,7 @@
 
 package android.net;
 
+import android.annotation.NonNull;
 import android.annotation.SystemApi;
 import android.annotation.TestApi;
 import android.os.Parcel;
@@ -70,7 +71,7 @@
      *
      * @hide
      */
-    public IpPrefix(byte[] address, int prefixLength) {
+    public IpPrefix(@NonNull byte[] address, int prefixLength) {
         this.address = address.clone();
         this.prefixLength = prefixLength;
         checkAndMaskAddressAndPrefixLength();
@@ -87,7 +88,7 @@
      */
     @SystemApi
     @TestApi
-    public IpPrefix(InetAddress address, int prefixLength) {
+    public IpPrefix(@NonNull InetAddress address, int prefixLength) {
         // We don't reuse the (byte[], int) constructor because it calls clone() on the byte array,
         // which is unnecessary because getAddress() already returns a clone.
         this.address = address.getAddress();
@@ -106,7 +107,7 @@
      */
     @SystemApi
     @TestApi
-    public IpPrefix(String prefix) {
+    public IpPrefix(@NonNull String prefix) {
         // We don't reuse the (InetAddress, int) constructor because "error: call to this must be
         // first statement in constructor". We could factor out setting the member variables to an
         // init() method, but if we did, then we'd have to make the members non-final, or "error:
diff --git a/core/java/android/net/LinkAddress.java b/core/java/android/net/LinkAddress.java
index 78a4e72..333603f 100644
--- a/core/java/android/net/LinkAddress.java
+++ b/core/java/android/net/LinkAddress.java
@@ -26,6 +26,7 @@
 import static android.system.OsConstants.RT_SCOPE_UNIVERSE;
 
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.annotation.SystemApi;
 import android.annotation.TestApi;
 import android.annotation.UnsupportedAppUsage;
@@ -107,8 +108,8 @@
      *
      * Per RFC 4193 section 8, fc00::/7 identifies these addresses.
      */
-    private boolean isIPv6ULA() {
-        if (isIPv6()) {
+    private boolean isIpv6ULA() {
+        if (isIpv6()) {
             byte[] bytes = address.getAddress();
             return ((bytes[0] & (byte)0xfe) == (byte)0xfc);
         }
@@ -121,17 +122,29 @@
      */
     @TestApi
     @SystemApi
-    public boolean isIPv6() {
+    public boolean isIpv6() {
         return address instanceof Inet6Address;
     }
 
     /**
+     * For backward compatibility.
+     * This was annotated with @UnsupportedAppUsage in P, so we can't remove the method completely
+     * just yet.
+     * @return true if the address is IPv6.
+     * @hide
+     */
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
+    public boolean isIPv6() {
+        return isIpv6();
+    }
+
+    /**
      * @return true if the address is IPv4 or is a mapped IPv4 address.
      * @hide
      */
     @TestApi
     @SystemApi
-    public boolean isIPv4() {
+    public boolean isIpv4() {
         return address instanceof Inet4Address;
     }
 
@@ -217,7 +230,7 @@
      */
     @SystemApi
     @TestApi
-    public LinkAddress(String address, int flags, int scope) {
+    public LinkAddress(@NonNull String address, int flags, int scope) {
         // This may throw an IllegalArgumentException; catching it is the caller's responsibility.
         // TODO: consider rejecting mapped IPv4 addresses such as "::ffff:192.0.2.5/24".
         Pair<InetAddress, Integer> ipAndMask = NetworkUtils.parseIpAndMask(address);
@@ -276,7 +289,10 @@
      */
     @TestApi
     @SystemApi
-    public boolean isSameAddressAs(LinkAddress other) {
+    public boolean isSameAddressAs(@Nullable LinkAddress other) {
+        if (other == null) {
+            return false;
+        }
         return address.equals(other.address) && prefixLength == other.prefixLength;
     }
 
@@ -331,10 +347,10 @@
          * state has cleared either DAD has succeeded or failed, and both
          * flags are cleared regardless).
          */
-        return (scope == RT_SCOPE_UNIVERSE &&
-                !isIPv6ULA() &&
-                (flags & (IFA_F_DADFAILED | IFA_F_DEPRECATED)) == 0L &&
-                ((flags & IFA_F_TENTATIVE) == 0L || (flags & IFA_F_OPTIMISTIC) != 0L));
+        return (scope == RT_SCOPE_UNIVERSE
+                && !isIpv6ULA()
+                && (flags & (IFA_F_DADFAILED | IFA_F_DEPRECATED)) == 0L
+                && ((flags & IFA_F_TENTATIVE) == 0L || (flags & IFA_F_OPTIMISTIC) != 0L));
     }
 
     /**
diff --git a/core/java/android/net/LinkProperties.java b/core/java/android/net/LinkProperties.java
index b52b15e..d5ca664 100644
--- a/core/java/android/net/LinkProperties.java
+++ b/core/java/android/net/LinkProperties.java
@@ -54,11 +54,11 @@
     // The interface described by the network link.
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     private String mIfaceName;
-    private ArrayList<LinkAddress> mLinkAddresses = new ArrayList<>();
-    private ArrayList<InetAddress> mDnses = new ArrayList<>();
+    private final ArrayList<LinkAddress> mLinkAddresses = new ArrayList<>();
+    private final ArrayList<InetAddress> mDnses = new ArrayList<>();
     // PCSCF addresses are addresses of SIP proxies that only exist for the IMS core service.
-    private ArrayList<InetAddress> mPcscfs = new ArrayList<InetAddress>();
-    private ArrayList<InetAddress> mValidatedPrivateDnses = new ArrayList<>();
+    private final ArrayList<InetAddress> mPcscfs = new ArrayList<InetAddress>();
+    private final ArrayList<InetAddress> mValidatedPrivateDnses = new ArrayList<>();
     private boolean mUsePrivateDns;
     private String mPrivateDnsServerName;
     private String mDomains;
@@ -150,8 +150,8 @@
             // connections getting stuck until timeouts fire and other
             // baffling failures. Therefore, loss of either IPv4 or IPv6 on a
             // previously dual-stack network is deemed a lost of provisioning.
-            if ((before.isIPv4Provisioned() && !after.isIPv4Provisioned()) ||
-                (before.isIPv6Provisioned() && !after.isIPv6Provisioned())) {
+            if ((before.isIpv4Provisioned() && !after.isIpv4Provisioned())
+                    || (before.isIpv6Provisioned() && !after.isIpv6Provisioned())) {
                 return ProvisioningChange.LOST_PROVISIONING;
             }
             return ProvisioningChange.STILL_PROVISIONED;
@@ -165,9 +165,8 @@
     }
 
     /**
-     * @hide
+     * Constructs a new {@code LinkProperties} with default values.
      */
-    @SystemApi
     public LinkProperties() {
     }
 
@@ -176,7 +175,7 @@
      */
     @SystemApi
     @TestApi
-    public LinkProperties(LinkProperties source) {
+    public LinkProperties(@Nullable LinkProperties source) {
         if (source != null) {
             mIfaceName = source.mIfaceName;
             mLinkAddresses.addAll(source.mLinkAddresses);
@@ -202,10 +201,8 @@
      * will have their interface changed to match this new value.
      *
      * @param iface The name of the network interface used for this link.
-     * @hide
      */
-    @SystemApi
-    public void setInterfaceName(String iface) {
+    public void setInterfaceName(@Nullable String iface) {
         mIfaceName = iface;
         ArrayList<RouteInfo> newRoutes = new ArrayList<>(mRoutes.size());
         for (RouteInfo route : mRoutes) {
@@ -227,7 +224,7 @@
      * @hide
      */
     @UnsupportedAppUsage
-    public List<String> getAllInterfaceNames() {
+    public @NonNull List<String> getAllInterfaceNames() {
         List<String> interfaceNames = new ArrayList<>(mStackedLinks.size() + 1);
         if (mIfaceName != null) interfaceNames.add(mIfaceName);
         for (LinkProperties stacked: mStackedLinks.values()) {
@@ -247,8 +244,8 @@
      * @hide
      */
     @UnsupportedAppUsage
-    public List<InetAddress> getAddresses() {
-        List<InetAddress> addresses = new ArrayList<>();
+    public @NonNull List<InetAddress> getAddresses() {
+        final List<InetAddress> addresses = new ArrayList<>();
         for (LinkAddress linkAddress : mLinkAddresses) {
             addresses.add(linkAddress.getAddress());
         }
@@ -260,7 +257,7 @@
      * @hide
      */
     @UnsupportedAppUsage
-    public List<InetAddress> getAllAddresses() {
+    public @NonNull List<InetAddress> getAllAddresses() {
         List<InetAddress> addresses = new ArrayList<>();
         for (LinkAddress linkAddress : mLinkAddresses) {
             addresses.add(linkAddress.getAddress());
@@ -289,7 +286,7 @@
      */
     @SystemApi
     @TestApi
-    public boolean addLinkAddress(LinkAddress address) {
+    public boolean addLinkAddress(@NonNull LinkAddress address) {
         if (address == null) {
             return false;
         }
@@ -318,7 +315,10 @@
      */
     @SystemApi
     @TestApi
-    public boolean removeLinkAddress(LinkAddress toRemove) {
+    public boolean removeLinkAddress(@NonNull LinkAddress toRemove) {
+        if (toRemove == null) {
+            return false;
+        }
         int i = findLinkAddressIndex(toRemove);
         if (i >= 0) {
             mLinkAddresses.remove(i);
@@ -333,7 +333,7 @@
      *
      * @return An unmodifiable {@link List} of {@link LinkAddress} for this link.
      */
-    public List<LinkAddress> getLinkAddresses() {
+    public @NonNull List<LinkAddress> getLinkAddresses() {
         return Collections.unmodifiableList(mLinkAddresses);
     }
 
@@ -356,10 +356,8 @@
      *
      * @param addresses The {@link Collection} of {@link LinkAddress} to set in this
      *                  object.
-     * @hide
      */
-    @SystemApi
-    public void setLinkAddresses(Collection<LinkAddress> addresses) {
+    public void setLinkAddresses(@NonNull Collection<LinkAddress> addresses) {
         mLinkAddresses.clear();
         for (LinkAddress address: addresses) {
             addLinkAddress(address);
@@ -375,7 +373,7 @@
      */
     @TestApi
     @SystemApi
-    public boolean addDnsServer(InetAddress dnsServer) {
+    public boolean addDnsServer(@NonNull InetAddress dnsServer) {
         if (dnsServer != null && !mDnses.contains(dnsServer)) {
             mDnses.add(dnsServer);
             return true;
@@ -392,7 +390,7 @@
      */
     @TestApi
     @SystemApi
-    public boolean removeDnsServer(InetAddress dnsServer) {
+    public boolean removeDnsServer(@NonNull InetAddress dnsServer) {
         if (dnsServer != null) {
             return mDnses.remove(dnsServer);
         }
@@ -404,10 +402,8 @@
      * the given {@link Collection} of {@link InetAddress} objects.
      *
      * @param dnsServers The {@link Collection} of DNS servers to set in this object.
-     * @hide
      */
-    @SystemApi
-    public void setDnsServers(Collection<InetAddress> dnsServers) {
+    public void setDnsServers(@NonNull Collection<InetAddress> dnsServers) {
         mDnses.clear();
         for (InetAddress dnsServer: dnsServers) {
             addDnsServer(dnsServer);
@@ -420,7 +416,7 @@
      * @return An unmodifiable {@link List} of {@link InetAddress} for DNS servers on
      *         this link.
      */
-    public List<InetAddress> getDnsServers() {
+    public @NonNull List<InetAddress> getDnsServers() {
         return Collections.unmodifiableList(mDnses);
     }
 
@@ -490,7 +486,7 @@
      * @return true if the DNS server was added, false if it was already present.
      * @hide
      */
-    public boolean addValidatedPrivateDnsServer(InetAddress dnsServer) {
+    public boolean addValidatedPrivateDnsServer(@NonNull InetAddress dnsServer) {
         if (dnsServer != null && !mValidatedPrivateDnses.contains(dnsServer)) {
             mValidatedPrivateDnses.add(dnsServer);
             return true;
@@ -506,11 +502,8 @@
      * @return true if the DNS server was removed, false if it did not exist.
      * @hide
      */
-    public boolean removeValidatedPrivateDnsServer(InetAddress dnsServer) {
-        if (dnsServer != null) {
-            return mValidatedPrivateDnses.remove(dnsServer);
-        }
-        return false;
+    public boolean removeValidatedPrivateDnsServer(@NonNull InetAddress dnsServer) {
+        return mValidatedPrivateDnses.remove(dnsServer);
     }
 
     /**
@@ -523,7 +516,7 @@
      */
     @TestApi
     @SystemApi
-    public void setValidatedPrivateDnsServers(Collection<InetAddress> dnsServers) {
+    public void setValidatedPrivateDnsServers(@NonNull Collection<InetAddress> dnsServers) {
         mValidatedPrivateDnses.clear();
         for (InetAddress dnsServer: dnsServers) {
             addValidatedPrivateDnsServer(dnsServer);
@@ -534,13 +527,13 @@
      * Returns all the {@link InetAddress} for validated private DNS servers on this link.
      * These are resolved from the private DNS server name.
      *
-     * @return An umodifiable {@link List} of {@link InetAddress} for validated private
+     * @return An unmodifiable {@link List} of {@link InetAddress} for validated private
      *         DNS servers on this link.
      * @hide
      */
     @TestApi
     @SystemApi
-    public List<InetAddress> getValidatedPrivateDnsServers() {
+    public @NonNull List<InetAddress> getValidatedPrivateDnsServers() {
         return Collections.unmodifiableList(mValidatedPrivateDnses);
     }
 
@@ -551,7 +544,7 @@
      * @return true if the PCSCF server was added, false otherwise.
      * @hide
      */
-    public boolean addPcscfServer(InetAddress pcscfServer) {
+    public boolean addPcscfServer(@NonNull InetAddress pcscfServer) {
         if (pcscfServer != null && !mPcscfs.contains(pcscfServer)) {
             mPcscfs.add(pcscfServer);
             return true;
@@ -562,27 +555,24 @@
     /**
      * Removes the given {@link InetAddress} from the list of PCSCF servers.
      *
-     * @param pcscf Server The {@link InetAddress} to remove from the list of PCSCF servers.
+     * @param pcscfServer The {@link InetAddress} to remove from the list of PCSCF servers.
      * @return true if the PCSCF server was removed, false otherwise.
      * @hide
      */
-    public boolean removePcscfServer(InetAddress pcscfServer) {
-        if (pcscfServer != null) {
-            return mPcscfs.remove(pcscfServer);
-        }
-        return false;
+    public boolean removePcscfServer(@NonNull InetAddress pcscfServer) {
+        return mPcscfs.remove(pcscfServer);
     }
 
     /**
      * Replaces the PCSCF servers in this {@code LinkProperties} with
      * the given {@link Collection} of {@link InetAddress} objects.
      *
-     * @param addresses The {@link Collection} of PCSCF servers to set in this object.
+     * @param pcscfServers The {@link Collection} of PCSCF servers to set in this object.
      * @hide
      */
     @SystemApi
     @TestApi
-    public void setPcscfServers(Collection<InetAddress> pcscfServers) {
+    public void setPcscfServers(@NonNull Collection<InetAddress> pcscfServers) {
         mPcscfs.clear();
         for (InetAddress pcscfServer: pcscfServers) {
             addPcscfServer(pcscfServer);
@@ -598,7 +588,7 @@
      */
     @SystemApi
     @TestApi
-    public List<InetAddress> getPcscfServers() {
+    public @NonNull List<InetAddress> getPcscfServers() {
         return Collections.unmodifiableList(mPcscfs);
     }
 
@@ -607,20 +597,18 @@
      *
      * @param domains A {@link String} listing in priority order the comma separated
      *                domains to search when resolving host names on this link.
-     * @hide
      */
-    @SystemApi
-    public void setDomains(String domains) {
+    public void setDomains(@Nullable String domains) {
         mDomains = domains;
     }
 
     /**
-     * Get the DNS domains search path set for this link.
+     * Get the DNS domains search path set for this link. May be {@code null} if not set.
      *
-     * @return A {@link String} containing the comma separated domains to search when resolving
-     *         host names on this link.
+     * @return A {@link String} containing the comma separated domains to search when resolving host
+     *         names on this link or {@code null}.
      */
-    public String getDomains() {
+    public @Nullable String getDomains() {
         return mDomains;
     }
 
@@ -630,9 +618,7 @@
      * 10000 will be ignored.
      *
      * @param mtu The MTU to use for this link.
-     * @hide
      */
-    @SystemApi
     public void setMtu(int mtu) {
         mMtu = mtu;
     }
@@ -657,20 +643,20 @@
      */
     @TestApi
     @SystemApi
-    public void setTcpBufferSizes(String tcpBufferSizes) {
+    public void setTcpBufferSizes(@Nullable String tcpBufferSizes) {
         mTcpBufferSizes = tcpBufferSizes;
     }
 
     /**
-     * Gets the tcp buffer sizes.
+     * Gets the tcp buffer sizes. May be {@code null} if not set.
      *
-     * @return the tcp buffer sizes to use when this link is the system default.
+     * @return the tcp buffer sizes to use when this link is the system default or {@code null}.
      *
      * @hide
      */
     @TestApi
     @SystemApi
-    public String getTcpBufferSizes() {
+    public @Nullable String getTcpBufferSizes() {
         return mTcpBufferSizes;
     }
 
@@ -690,23 +676,18 @@
      *
      * @param route A {@link RouteInfo} to add to this object.
      * @return {@code false} if the route was already present, {@code true} if it was added.
-     *
-     * @hide
      */
-    @SystemApi
-    public boolean addRoute(RouteInfo route) {
-        if (route != null) {
-            String routeIface = route.getInterface();
-            if (routeIface != null && !routeIface.equals(mIfaceName)) {
-                throw new IllegalArgumentException(
-                   "Route added with non-matching interface: " + routeIface +
-                   " vs. " + mIfaceName);
-            }
-            route = routeWithInterface(route);
-            if (!mRoutes.contains(route)) {
-                mRoutes.add(route);
-                return true;
-            }
+    public boolean addRoute(@NonNull RouteInfo route) {
+        String routeIface = route.getInterface();
+        if (routeIface != null && !routeIface.equals(mIfaceName)) {
+            throw new IllegalArgumentException(
+                    "Route added with non-matching interface: " + routeIface
+                            + " vs. " + mIfaceName);
+        }
+        route = routeWithInterface(route);
+        if (!mRoutes.contains(route)) {
+            mRoutes.add(route);
+            return true;
         }
         return false;
     }
@@ -722,10 +703,8 @@
      */
     @TestApi
     @SystemApi
-    public boolean removeRoute(RouteInfo route) {
-        return route != null &&
-                Objects.equals(mIfaceName, route.getInterface()) &&
-                mRoutes.remove(route);
+    public boolean removeRoute(@NonNull RouteInfo route) {
+        return Objects.equals(mIfaceName, route.getInterface()) && mRoutes.remove(route);
     }
 
     /**
@@ -733,7 +712,7 @@
      *
      * @return An unmodifiable {@link List} of {@link RouteInfo} for this link.
      */
-    public List<RouteInfo> getRoutes() {
+    public @NonNull List<RouteInfo> getRoutes() {
         return Collections.unmodifiableList(mRoutes);
     }
 
@@ -753,7 +732,7 @@
      * @hide
      */
     @UnsupportedAppUsage
-    public List<RouteInfo> getAllRoutes() {
+    public @NonNull List<RouteInfo> getAllRoutes() {
         List<RouteInfo> routes = new ArrayList<>(mRoutes);
         for (LinkProperties stacked: mStackedLinks.values()) {
             routes.addAll(stacked.getAllRoutes());
@@ -767,26 +746,24 @@
      * not enforce it and applications may ignore them.
      *
      * @param proxy A {@link ProxyInfo} defining the HTTP Proxy to use on this link.
-     * @hide
      */
-    @SystemApi
-    public void setHttpProxy(ProxyInfo proxy) {
+    public void setHttpProxy(@Nullable ProxyInfo proxy) {
         mHttpProxy = proxy;
     }
 
     /**
      * Gets the recommended {@link ProxyInfo} (or {@code null}) set on this link.
      *
-     * @return The {@link ProxyInfo} set on this link
+     * @return The {@link ProxyInfo} set on this link or {@code null}.
      */
-    public ProxyInfo getHttpProxy() {
+    public @Nullable ProxyInfo getHttpProxy() {
         return mHttpProxy;
     }
 
     /**
      * Returns the NAT64 prefix in use on this link, if any.
      *
-     * @return the NAT64 prefix.
+     * @return the NAT64 prefix or {@code null}.
      * @hide
      */
     @SystemApi
@@ -799,14 +776,14 @@
      * Sets the NAT64 prefix in use on this link.
      *
      * Currently, only 96-bit prefixes (i.e., where the 32-bit IPv4 address is at the end of the
-     * 128-bit IPv6 address) are supported.
+     * 128-bit IPv6 address) are supported or {@code null} for no prefix.
      *
      * @param prefix the NAT64 prefix.
      * @hide
      */
     @SystemApi
     @TestApi
-    public void setNat64Prefix(IpPrefix prefix) {
+    public void setNat64Prefix(@Nullable IpPrefix prefix) {
         if (prefix != null && prefix.getPrefixLength() != 96) {
             throw new IllegalArgumentException("Only 96-bit prefixes are supported: " + prefix);
         }
@@ -818,15 +795,15 @@
      *
      * If there is already a stacked link with the same interface name as link,
      * that link is replaced with link. Otherwise, link is added to the list
-     * of stacked links. If link is null, nothing changes.
+     * of stacked links.
      *
      * @param link The link to add.
      * @return true if the link was stacked, false otherwise.
      * @hide
      */
     @UnsupportedAppUsage
-    public boolean addStackedLink(LinkProperties link) {
-        if (link != null && link.getInterfaceName() != null) {
+    public boolean addStackedLink(@NonNull LinkProperties link) {
+        if (link.getInterfaceName() != null) {
             mStackedLinks.put(link.getInterfaceName(), link);
             return true;
         }
@@ -843,12 +820,9 @@
      * @return true if the link was removed, false otherwise.
      * @hide
      */
-    public boolean removeStackedLink(String iface) {
-        if (iface != null) {
-            LinkProperties removed = mStackedLinks.remove(iface);
-            return removed != null;
-        }
-        return false;
+    public boolean removeStackedLink(@NonNull String iface) {
+        LinkProperties removed = mStackedLinks.remove(iface);
+        return removed != null;
     }
 
     /**
@@ -860,7 +834,7 @@
         if (mStackedLinks.isEmpty()) {
             return Collections.emptyList();
         }
-        List<LinkProperties> stacked = new ArrayList<>();
+        final List<LinkProperties> stacked = new ArrayList<>();
         for (LinkProperties link : mStackedLinks.values()) {
             stacked.add(new LinkProperties(link));
         }
@@ -869,9 +843,7 @@
 
     /**
      * Clears this object to its initial state.
-     * @hide
      */
-    @SystemApi
     public void clear() {
         mIfaceName = null;
         mLinkAddresses.clear();
@@ -988,7 +960,7 @@
      */
     @TestApi
     @SystemApi
-    public boolean hasIPv4Address() {
+    public boolean hasIpv4Address() {
         for (LinkAddress address : mLinkAddresses) {
             if (address.getAddress() instanceof Inet4Address) {
                 return true;
@@ -998,15 +970,27 @@
     }
 
     /**
+     * For backward compatibility.
+     * This was annotated with @UnsupportedAppUsage in P, so we can't remove the method completely
+     * just yet.
+     * @return {@code true} if there is an IPv4 address, {@code false} otherwise.
+     * @hide
+     */
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
+    public boolean hasIPv4Address() {
+        return hasIpv4Address();
+    }
+
+    /**
      * Returns true if this link or any of its stacked interfaces has an IPv4 address.
      *
      * @return {@code true} if there is an IPv4 address, {@code false} otherwise.
      */
-    private boolean hasIPv4AddressOnInterface(String iface) {
+    private boolean hasIpv4AddressOnInterface(String iface) {
         // mIfaceName can be null.
-        return (Objects.equals(iface, mIfaceName) && hasIPv4Address()) ||
-                (iface != null && mStackedLinks.containsKey(iface) &&
-                        mStackedLinks.get(iface).hasIPv4Address());
+        return (Objects.equals(iface, mIfaceName) && hasIpv4Address())
+                || (iface != null && mStackedLinks.containsKey(iface)
+                        && mStackedLinks.get(iface).hasIpv4Address());
     }
 
     /**
@@ -1017,7 +1001,7 @@
      */
     @TestApi
     @SystemApi
-    public boolean hasGlobalIPv6Address() {
+    public boolean hasGlobalIpv6Address() {
         for (LinkAddress address : mLinkAddresses) {
           if (address.getAddress() instanceof Inet6Address && address.isGlobalPreferred()) {
             return true;
@@ -1027,13 +1011,25 @@
     }
 
     /**
+     * For backward compatibility.
+     * This was annotated with @UnsupportedAppUsage in P, so we can't remove the method completely
+     * just yet.
+     * @return {@code true} if there is a global preferred IPv6 address, {@code false} otherwise.
+     * @hide
+     */
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
+    public boolean hasGlobalIPv6Address() {
+        return hasGlobalIpv6Address();
+    }
+
+    /**
      * Returns true if this link has an IPv4 default route.
      *
      * @return {@code true} if there is an IPv4 default route, {@code false} otherwise.
      * @hide
      */
     @UnsupportedAppUsage
-    public boolean hasIPv4DefaultRoute() {
+    public boolean hasIpv4DefaultRoute() {
         for (RouteInfo r : mRoutes) {
             if (r.isIPv4Default()) {
                 return true;
@@ -1043,6 +1039,18 @@
     }
 
     /**
+     * For backward compatibility.
+     * This was annotated with @UnsupportedAppUsage in P, so we can't remove the method completely
+     * just yet.
+     * @return {@code true} if there is an IPv4 default route, {@code false} otherwise.
+     * @hide
+     */
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
+    public boolean hasIPv4DefaultRoute() {
+        return hasIpv4DefaultRoute();
+    }
+
+    /**
      * Returns true if this link has an IPv6 default route.
      *
      * @return {@code true} if there is an IPv6 default route, {@code false} otherwise.
@@ -1050,7 +1058,7 @@
      */
     @TestApi
     @SystemApi
-    public boolean hasIPv6DefaultRoute() {
+    public boolean hasIpv6DefaultRoute() {
         for (RouteInfo r : mRoutes) {
             if (r.isIPv6Default()) {
                 return true;
@@ -1060,13 +1068,25 @@
     }
 
     /**
+     * For backward compatibility.
+     * This was annotated with @UnsupportedAppUsage in P, so we can't remove the method completely
+     * just yet.
+     * @return {@code true} if there is an IPv6 default route, {@code false} otherwise.
+     * @hide
+     */
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
+    public boolean hasIPv6DefaultRoute() {
+        return hasIpv6DefaultRoute();
+    }
+
+    /**
      * Returns true if this link has an IPv4 DNS server.
      *
      * @return {@code true} if there is an IPv4 DNS server, {@code false} otherwise.
      * @hide
      */
     @UnsupportedAppUsage
-    public boolean hasIPv4DnsServer() {
+    public boolean hasIpv4DnsServer() {
         for (InetAddress ia : mDnses) {
             if (ia instanceof Inet4Address) {
                 return true;
@@ -1076,13 +1096,25 @@
     }
 
     /**
+     * For backward compatibility.
+     * This was annotated with @UnsupportedAppUsage in P, so we can't remove the method completely
+     * just yet.
+     * @return {@code true} if there is an IPv4 DNS server, {@code false} otherwise.
+     * @hide
+     */
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
+    public boolean hasIPv4DnsServer() {
+        return hasIpv4DnsServer();
+    }
+
+    /**
      * Returns true if this link has an IPv6 DNS server.
      *
      * @return {@code true} if there is an IPv6 DNS server, {@code false} otherwise.
      * @hide
      */
     @UnsupportedAppUsage
-    public boolean hasIPv6DnsServer() {
+    public boolean hasIpv6DnsServer() {
         for (InetAddress ia : mDnses) {
             if (ia instanceof Inet6Address) {
                 return true;
@@ -1092,12 +1124,24 @@
     }
 
     /**
+     * For backward compatibility.
+     * This was annotated with @UnsupportedAppUsage in P, so we can't remove the method completely
+     * just yet.
+     * @return {@code true} if there is an IPv6 DNS server, {@code false} otherwise.
+     * @hide
+     */
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
+    public boolean hasIPv6DnsServer() {
+        return hasIpv6DnsServer();
+    }
+
+    /**
      * Returns true if this link has an IPv4 PCSCF server.
      *
      * @return {@code true} if there is an IPv4 PCSCF server, {@code false} otherwise.
      * @hide
      */
-    public boolean hasIPv4PcscfServer() {
+    public boolean hasIpv4PcscfServer() {
         for (InetAddress ia : mPcscfs) {
           if (ia instanceof Inet4Address) {
             return true;
@@ -1112,7 +1156,7 @@
      * @return {@code true} if there is an IPv6 PCSCF server, {@code false} otherwise.
      * @hide
      */
-    public boolean hasIPv6PcscfServer() {
+    public boolean hasIpv6PcscfServer() {
         for (InetAddress ia : mPcscfs) {
           if (ia instanceof Inet6Address) {
             return true;
@@ -1130,10 +1174,10 @@
      */
     @TestApi
     @SystemApi
-    public boolean isIPv4Provisioned() {
-        return (hasIPv4Address() &&
-                hasIPv4DefaultRoute() &&
-                hasIPv4DnsServer());
+    public boolean isIpv4Provisioned() {
+        return (hasIpv4Address()
+                && hasIpv4DefaultRoute()
+                && hasIpv4DnsServer());
     }
 
     /**
@@ -1145,13 +1189,26 @@
      */
     @TestApi
     @SystemApi
-    public boolean isIPv6Provisioned() {
-        return (hasGlobalIPv6Address() &&
-                hasIPv6DefaultRoute() &&
-                hasIPv6DnsServer());
+    public boolean isIpv6Provisioned() {
+        return (hasGlobalIpv6Address()
+                && hasIpv6DefaultRoute()
+                && hasIpv6DnsServer());
     }
 
     /**
+     * For backward compatibility.
+     * This was annotated with @UnsupportedAppUsage in P, so we can't remove the method completely
+     * just yet.
+     * @return {@code true} if the link is provisioned, {@code false} otherwise.
+     * @hide
+     */
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
+    public boolean isIPv6Provisioned() {
+        return isIpv6Provisioned();
+    }
+
+
+    /**
      * Returns true if this link is provisioned for global connectivity,
      * for at least one Internet Protocol family.
      *
@@ -1161,7 +1218,7 @@
     @TestApi
     @SystemApi
     public boolean isProvisioned() {
-        return (isIPv4Provisioned() || isIPv6Provisioned());
+        return (isIpv4Provisioned() || isIpv6Provisioned());
     }
 
     /**
@@ -1173,7 +1230,7 @@
      */
     @TestApi
     @SystemApi
-    public boolean isReachable(InetAddress ip) {
+    public boolean isReachable(@NonNull InetAddress ip) {
         final List<RouteInfo> allRoutes = getAllRoutes();
         // If we don't have a route to this IP address, it's not reachable.
         final RouteInfo bestRoute = RouteInfo.selectBestRoute(allRoutes, ip);
@@ -1185,7 +1242,7 @@
 
         if (ip instanceof Inet4Address) {
             // For IPv4, it suffices for now to simply have any address.
-            return hasIPv4AddressOnInterface(bestRoute.getInterface());
+            return hasIpv4AddressOnInterface(bestRoute.getInterface());
         } else if (ip instanceof Inet6Address) {
             if (ip.isLinkLocalAddress()) {
                 // For now, just make sure link-local destinations have
@@ -1196,7 +1253,7 @@
                 // For non-link-local destinations check that either the best route
                 // is directly connected or that some global preferred address exists.
                 // TODO: reconsider all cases (disconnected ULA networks, ...).
-                return (!bestRoute.hasGateway() || hasGlobalIPv6Address());
+                return (!bestRoute.hasGateway() || hasGlobalIpv6Address());
             }
         }
 
@@ -1211,7 +1268,7 @@
      * @hide
      */
     @UnsupportedAppUsage
-    public boolean isIdenticalInterfaceName(LinkProperties target) {
+    public boolean isIdenticalInterfaceName(@NonNull LinkProperties target) {
         return TextUtils.equals(getInterfaceName(), target.getInterfaceName());
     }
 
@@ -1223,7 +1280,7 @@
      * @hide
      */
     @UnsupportedAppUsage
-    public boolean isIdenticalAddresses(LinkProperties target) {
+    public boolean isIdenticalAddresses(@NonNull LinkProperties target) {
         Collection<InetAddress> targetAddresses = target.getAddresses();
         Collection<InetAddress> sourceAddresses = getAddresses();
         return (sourceAddresses.size() == targetAddresses.size()) ?
@@ -1238,7 +1295,7 @@
      * @hide
      */
     @UnsupportedAppUsage
-    public boolean isIdenticalDnses(LinkProperties target) {
+    public boolean isIdenticalDnses(@NonNull LinkProperties target) {
         Collection<InetAddress> targetDnses = target.getDnsServers();
         String targetDomains = target.getDomains();
         if (mDomains == null) {
@@ -1258,7 +1315,7 @@
      * @return {@code true} if both are identical, {@code false} otherwise.
      * @hide
      */
-    public boolean isIdenticalPrivateDns(LinkProperties target) {
+    public boolean isIdenticalPrivateDns(@NonNull LinkProperties target) {
         return (isPrivateDnsActive() == target.isPrivateDnsActive()
                 && TextUtils.equals(getPrivateDnsServerName(),
                 target.getPrivateDnsServerName()));
@@ -1272,7 +1329,7 @@
      * @return {@code true} if both are identical, {@code false} otherwise.
      * @hide
      */
-    public boolean isIdenticalValidatedPrivateDnses(LinkProperties target) {
+    public boolean isIdenticalValidatedPrivateDnses(@NonNull LinkProperties target) {
         Collection<InetAddress> targetDnses = target.getValidatedPrivateDnsServers();
         return (mValidatedPrivateDnses.size() == targetDnses.size())
                 ? mValidatedPrivateDnses.containsAll(targetDnses) : false;
@@ -1285,7 +1342,7 @@
      * @return {@code true} if both are identical, {@code false} otherwise.
      * @hide
      */
-    public boolean isIdenticalPcscfs(LinkProperties target) {
+    public boolean isIdenticalPcscfs(@NonNull LinkProperties target) {
         Collection<InetAddress> targetPcscfs = target.getPcscfServers();
         return (mPcscfs.size() == targetPcscfs.size()) ?
                     mPcscfs.containsAll(targetPcscfs) : false;
@@ -1299,7 +1356,7 @@
      * @hide
      */
     @UnsupportedAppUsage
-    public boolean isIdenticalRoutes(LinkProperties target) {
+    public boolean isIdenticalRoutes(@NonNull LinkProperties target) {
         Collection<RouteInfo> targetRoutes = target.getRoutes();
         return (mRoutes.size() == targetRoutes.size()) ?
                 mRoutes.containsAll(targetRoutes) : false;
@@ -1313,7 +1370,7 @@
      * @hide
      */
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
-    public boolean isIdenticalHttpProxy(LinkProperties target) {
+    public boolean isIdenticalHttpProxy(@NonNull LinkProperties target) {
         return getHttpProxy() == null ? target.getHttpProxy() == null :
                 getHttpProxy().equals(target.getHttpProxy());
     }
@@ -1326,7 +1383,7 @@
      * @hide
      */
     @UnsupportedAppUsage
-    public boolean isIdenticalStackedLinks(LinkProperties target) {
+    public boolean isIdenticalStackedLinks(@NonNull LinkProperties target) {
         if (!mStackedLinks.keySet().equals(target.mStackedLinks.keySet())) {
             return false;
         }
@@ -1347,7 +1404,7 @@
      * @return {@code true} if both are identical, {@code false} otherwise.
      * @hide
      */
-    public boolean isIdenticalMtu(LinkProperties target) {
+    public boolean isIdenticalMtu(@NonNull LinkProperties target) {
         return getMtu() == target.getMtu();
     }
 
@@ -1358,7 +1415,7 @@
      * @return {@code true} if both are identical, {@code false} otherwise.
      * @hide
      */
-    public boolean isIdenticalTcpBufferSizes(LinkProperties target) {
+    public boolean isIdenticalTcpBufferSizes(@NonNull LinkProperties target) {
         return Objects.equals(mTcpBufferSizes, target.mTcpBufferSizes);
     }
 
@@ -1369,7 +1426,7 @@
      * @return {@code true} if both are identical, {@code false} otherwise.
      * @hide
      */
-    public boolean isIdenticalNat64Prefix(LinkProperties target) {
+    public boolean isIdenticalNat64Prefix(@NonNull LinkProperties target) {
         return Objects.equals(mNat64Prefix, target.mNat64Prefix);
     }
 
@@ -1421,7 +1478,7 @@
      * @return the differences between the addresses.
      * @hide
      */
-    public CompareResult<LinkAddress> compareAddresses(LinkProperties target) {
+    public @NonNull CompareResult<LinkAddress> compareAddresses(@Nullable LinkProperties target) {
         /*
          * Duplicate the LinkAddresses into removed, we will be removing
          * address which are common between mLinkAddresses and target
@@ -1441,7 +1498,7 @@
      * @return the differences between the DNS addresses.
      * @hide
      */
-    public CompareResult<InetAddress> compareDnses(LinkProperties target) {
+    public @NonNull CompareResult<InetAddress> compareDnses(@Nullable LinkProperties target) {
         /*
          * Duplicate the InetAddresses into removed, we will be removing
          * dns address which are common between mDnses and target
@@ -1460,7 +1517,8 @@
      * @return the differences between the DNS addresses.
      * @hide
      */
-    public CompareResult<InetAddress> compareValidatedPrivateDnses(LinkProperties target) {
+    public @NonNull CompareResult<InetAddress> compareValidatedPrivateDnses(
+            @Nullable LinkProperties target) {
         return new CompareResult<>(mValidatedPrivateDnses,
                 target != null ? target.getValidatedPrivateDnsServers() : null);
     }
@@ -1473,7 +1531,7 @@
      * @return the differences between the routes.
      * @hide
      */
-    public CompareResult<RouteInfo> compareAllRoutes(LinkProperties target) {
+    public @NonNull CompareResult<RouteInfo> compareAllRoutes(@Nullable LinkProperties target) {
         /*
          * Duplicate the RouteInfos into removed, we will be removing
          * routes which are common between mRoutes and target
@@ -1491,7 +1549,8 @@
      * @return the differences between the interface names.
      * @hide
      */
-    public CompareResult<String> compareAllInterfaceNames(LinkProperties target) {
+    public @NonNull CompareResult<String> compareAllInterfaceNames(
+            @Nullable LinkProperties target) {
         /*
          * Duplicate the interface names into removed, we will be removing
          * interface names which are common between this and target
diff --git a/core/java/android/net/Network.java b/core/java/android/net/Network.java
index 0fafdf7..3f56def 100644
--- a/core/java/android/net/Network.java
+++ b/core/java/android/net/Network.java
@@ -16,6 +16,7 @@
 
 package android.net;
 
+import android.annotation.NonNull;
 import android.annotation.SystemApi;
 import android.annotation.TestApi;
 import android.annotation.UnsupportedAppUsage;
@@ -125,7 +126,7 @@
      */
     @SystemApi
     @TestApi
-    public Network(Network that) {
+    public Network(@NonNull Network that) {
         this(that.netId, that.mPrivateDnsBypass);
     }
 
@@ -163,7 +164,7 @@
      */
     @TestApi
     @SystemApi
-    public Network getPrivateDnsBypassingCopy() {
+    public @NonNull Network getPrivateDnsBypassingCopy() {
         return new Network(netId, true);
     }
 
diff --git a/core/java/android/net/NetworkCapabilities.java b/core/java/android/net/NetworkCapabilities.java
index c57ae0c..02145f2 100644
--- a/core/java/android/net/NetworkCapabilities.java
+++ b/core/java/android/net/NetworkCapabilities.java
@@ -17,6 +17,7 @@
 package android.net;
 
 import android.annotation.IntDef;
+import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.SystemApi;
 import android.annotation.TestApi;
@@ -91,7 +92,7 @@
      * Set all contents of this object to the contents of a NetworkCapabilities.
      * @hide
      */
-    public void set(NetworkCapabilities nc) {
+    public void set(@NonNull NetworkCapabilities nc) {
         mNetworkCapabilities = nc.mNetworkCapabilities;
         mTransportTypes = nc.mTransportTypes;
         mLinkUpBandwidthKbps = nc.mLinkUpBandwidthKbps;
@@ -405,7 +406,7 @@
      * @hide
      */
     @UnsupportedAppUsage
-    public NetworkCapabilities addCapability(@NetCapability int capability) {
+    public @NonNull NetworkCapabilities addCapability(@NetCapability int capability) {
         checkValidCapability(capability);
         mNetworkCapabilities |= 1 << capability;
         mUnwantedNetworkCapabilities &= ~(1 << capability);  // remove from unwanted capability list
@@ -442,7 +443,7 @@
      * @hide
      */
     @UnsupportedAppUsage
-    public NetworkCapabilities removeCapability(@NetCapability int capability) {
+    public @NonNull NetworkCapabilities removeCapability(@NetCapability int capability) {
         checkValidCapability(capability);
         final long mask = ~(1 << capability);
         mNetworkCapabilities &= mask;
@@ -456,7 +457,8 @@
      *
      * @hide
      */
-    public NetworkCapabilities setCapability(@NetCapability int capability, boolean value) {
+    public @NonNull NetworkCapabilities setCapability(@NetCapability int capability,
+            boolean value) {
         if (value) {
             addCapability(capability);
         } else {
@@ -534,7 +536,7 @@
     }
 
     /** Note this method may result in having the same capability in wanted and unwanted lists. */
-    private void combineNetCapabilities(NetworkCapabilities nc) {
+    private void combineNetCapabilities(@NonNull NetworkCapabilities nc) {
         this.mNetworkCapabilities |= nc.mNetworkCapabilities;
         this.mUnwantedNetworkCapabilities |= nc.mUnwantedNetworkCapabilities;
     }
@@ -546,7 +548,7 @@
      *
      * @hide
      */
-    public String describeFirstNonRequestableCapability() {
+    public @Nullable String describeFirstNonRequestableCapability() {
         final long nonRequestable = (mNetworkCapabilities | mUnwantedNetworkCapabilities)
                 & NON_REQUESTABLE_CAPABILITIES;
 
@@ -558,7 +560,8 @@
         return null;
     }
 
-    private boolean satisfiedByNetCapabilities(NetworkCapabilities nc, boolean onlyImmutable) {
+    private boolean satisfiedByNetCapabilities(@NonNull NetworkCapabilities nc,
+            boolean onlyImmutable) {
         long requestedCapabilities = mNetworkCapabilities;
         long requestedUnwantedCapabilities = mUnwantedNetworkCapabilities;
         long providedCapabilities = nc.mNetworkCapabilities;
@@ -572,12 +575,12 @@
     }
 
     /** @hide */
-    public boolean equalsNetCapabilities(NetworkCapabilities nc) {
+    public boolean equalsNetCapabilities(@NonNull NetworkCapabilities nc) {
         return (nc.mNetworkCapabilities == this.mNetworkCapabilities)
                 && (nc.mUnwantedNetworkCapabilities == this.mUnwantedNetworkCapabilities);
     }
 
-    private boolean equalsNetCapabilitiesRequestable(NetworkCapabilities that) {
+    private boolean equalsNetCapabilitiesRequestable(@NonNull NetworkCapabilities that) {
         return ((this.mNetworkCapabilities & ~NON_REQUESTABLE_CAPABILITIES) ==
                 (that.mNetworkCapabilities & ~NON_REQUESTABLE_CAPABILITIES))
                 && ((this.mUnwantedNetworkCapabilities & ~NON_REQUESTABLE_CAPABILITIES) ==
@@ -713,7 +716,7 @@
      * @hide
      */
     @UnsupportedAppUsage
-    public NetworkCapabilities addTransportType(@Transport int transportType) {
+    public @NonNull NetworkCapabilities addTransportType(@Transport int transportType) {
         checkValidTransportType(transportType);
         mTransportTypes |= 1 << transportType;
         setNetworkSpecifier(mNetworkSpecifier); // used for exception checking
@@ -727,7 +730,7 @@
      * @return This NetworkCapabilities instance, to facilitate chaining.
      * @hide
      */
-    public NetworkCapabilities removeTransportType(@Transport int transportType) {
+    public @NonNull NetworkCapabilities removeTransportType(@Transport int transportType) {
         checkValidTransportType(transportType);
         mTransportTypes &= ~(1 << transportType);
         setNetworkSpecifier(mNetworkSpecifier); // used for exception checking
@@ -740,7 +743,8 @@
      *
      * @hide
      */
-    public NetworkCapabilities setTransportType(@Transport int transportType, boolean value) {
+    public @NonNull NetworkCapabilities setTransportType(@Transport int transportType,
+            boolean value) {
         if (value) {
             addTransportType(transportType);
         } else {
@@ -757,7 +761,7 @@
      */
     @TestApi
     @SystemApi
-    public @Transport int[] getTransportTypes() {
+    @NonNull public @Transport int[] getTransportTypes() {
         return BitUtils.unpackBits(mTransportTypes);
     }
 
@@ -847,7 +851,7 @@
      * @param upKbps the estimated first hop upstream (device to network) bandwidth.
      * @hide
      */
-    public NetworkCapabilities setLinkUpstreamBandwidthKbps(int upKbps) {
+    public @NonNull NetworkCapabilities setLinkUpstreamBandwidthKbps(int upKbps) {
         mLinkUpBandwidthKbps = upKbps;
         return this;
     }
@@ -877,7 +881,7 @@
      * @param downKbps the estimated first hop downstream (network to device) bandwidth.
      * @hide
      */
-    public NetworkCapabilities setLinkDownstreamBandwidthKbps(int downKbps) {
+    public @NonNull NetworkCapabilities setLinkDownstreamBandwidthKbps(int downKbps) {
         mLinkDownBandwidthKbps = downKbps;
         return this;
     }
@@ -936,7 +940,7 @@
      * @return This NetworkCapabilities instance, to facilitate chaining.
      * @hide
      */
-    public NetworkCapabilities setNetworkSpecifier(NetworkSpecifier networkSpecifier) {
+    public @NonNull NetworkCapabilities setNetworkSpecifier(NetworkSpecifier networkSpecifier) {
         if (networkSpecifier != null && Long.bitCount(mTransportTypes) != 1) {
             throw new IllegalStateException("Must have a single transport specified to use " +
                     "setNetworkSpecifier");
@@ -955,20 +959,20 @@
      * @return This NetworkCapabilities instance, to facilitate chaining.
      * @hide
      */
-    public NetworkCapabilities setTransportInfo(TransportInfo transportInfo) {
+    public @NonNull NetworkCapabilities setTransportInfo(TransportInfo transportInfo) {
         mTransportInfo = transportInfo;
         return this;
     }
 
     /**
-     * Gets the optional bearer specific network specifier.
+     * Gets the optional bearer specific network specifier. May be {@code null} if not set.
      *
      * @return The optional {@link NetworkSpecifier} specifying the bearer specific network
-     *         specifier. See {@link #setNetworkSpecifier}.
+     *         specifier or {@code null}. See {@link #setNetworkSpecifier}.
      * @hide
      */
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
-    public NetworkSpecifier getNetworkSpecifier() {
+    public @Nullable NetworkSpecifier getNetworkSpecifier() {
         return mNetworkSpecifier;
     }
 
@@ -1015,8 +1019,6 @@
     /**
      * Magic value that indicates no signal strength provided. A request specifying this value is
      * always satisfied.
-     *
-     * @hide
      */
     public static final int SIGNAL_STRENGTH_UNSPECIFIED = Integer.MIN_VALUE;
 
@@ -1024,7 +1026,7 @@
      * Signal strength. This is a signed integer, and higher values indicate better signal.
      * The exact units are bearer-dependent. For example, Wi-Fi uses RSSI.
      */
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
     private int mSignalStrength = SIGNAL_STRENGTH_UNSPECIFIED;
 
     /**
@@ -1041,7 +1043,7 @@
      * @hide
      */
     @UnsupportedAppUsage
-    public NetworkCapabilities setSignalStrength(int signalStrength) {
+    public @NonNull NetworkCapabilities setSignalStrength(int signalStrength) {
         mSignalStrength = signalStrength;
         return this;
     }
@@ -1060,9 +1062,7 @@
      * Retrieves the signal strength.
      *
      * @return The bearer-specific signal strength.
-     * @hide
      */
-    @SystemApi
     public int getSignalStrength() {
         return mSignalStrength;
     }
@@ -1120,7 +1120,7 @@
      * Convenience method to set the UIDs this network applies to to a single UID.
      * @hide
      */
-    public NetworkCapabilities setSingleUid(int uid) {
+    public @NonNull NetworkCapabilities setSingleUid(int uid) {
         final ArraySet<UidRange> identity = new ArraySet<>(1);
         identity.add(new UidRange(uid, uid));
         setUids(identity);
@@ -1132,7 +1132,7 @@
      * This makes a copy of the set so that callers can't modify it after the call.
      * @hide
      */
-    public NetworkCapabilities setUids(Set<UidRange> uids) {
+    public @NonNull NetworkCapabilities setUids(Set<UidRange> uids) {
         if (null == uids) {
             mUids = null;
         } else {
@@ -1146,7 +1146,7 @@
      * This returns a copy of the set so that callers can't modify the original object.
      * @hide
      */
-    public Set<UidRange> getUids() {
+    public @Nullable Set<UidRange> getUids() {
         return null == mUids ? null : new ArraySet<>(mUids);
     }
 
@@ -1179,7 +1179,7 @@
      * @hide
      */
     @VisibleForTesting
-    public boolean equalsUids(NetworkCapabilities nc) {
+    public boolean equalsUids(@NonNull NetworkCapabilities nc) {
         Set<UidRange> comparedUids = nc.mUids;
         if (null == comparedUids) return null == mUids;
         if (null == mUids) return false;
@@ -1212,7 +1212,7 @@
      * @see #appliesToUid
      * @hide
      */
-    public boolean satisfiedByUids(NetworkCapabilities nc) {
+    public boolean satisfiedByUids(@NonNull NetworkCapabilities nc) {
         if (null == nc.mUids || null == mUids) return true; // The network satisfies everything.
         for (UidRange requiredRange : mUids) {
             if (requiredRange.contains(nc.mEstablishingVpnAppUid)) return true;
@@ -1232,7 +1232,7 @@
      * @hide
      */
     @VisibleForTesting
-    public boolean appliesToUidRange(UidRange requiredRange) {
+    public boolean appliesToUidRange(@Nullable UidRange requiredRange) {
         if (null == mUids) return true;
         for (UidRange uidRange : mUids) {
             if (uidRange.containsRange(requiredRange)) {
@@ -1247,7 +1247,7 @@
      * NetworkCapabilities apply to.
      * nc is assumed nonnull.
      */
-    private void combineUids(NetworkCapabilities nc) {
+    private void combineUids(@NonNull NetworkCapabilities nc) {
         if (null == nc.mUids || null == mUids) {
             mUids = null;
             return;
@@ -1268,7 +1268,7 @@
      * Sets the SSID of this network.
      * @hide
      */
-    public NetworkCapabilities setSSID(String ssid) {
+    public @NonNull NetworkCapabilities setSSID(@Nullable String ssid) {
         mSSID = ssid;
         return this;
     }
@@ -1277,7 +1277,7 @@
      * Gets the SSID of this network, or null if none or unknown.
      * @hide
      */
-    public String getSSID() {
+    public @Nullable String getSSID() {
         return mSSID;
     }
 
@@ -1285,7 +1285,7 @@
      * Tests if the SSID of this network is the same as the SSID of the passed network.
      * @hide
      */
-    public boolean equalsSSID(NetworkCapabilities nc) {
+    public boolean equalsSSID(@NonNull NetworkCapabilities nc) {
         return Objects.equals(mSSID, nc.mSSID);
     }
 
@@ -1293,7 +1293,7 @@
      * Check if the SSID requirements of this object are matched by the passed object.
      * @hide
      */
-    public boolean satisfiedBySSID(NetworkCapabilities nc) {
+    public boolean satisfiedBySSID(@NonNull NetworkCapabilities nc) {
         return mSSID == null || mSSID.equals(nc.mSSID);
     }
 
@@ -1304,7 +1304,7 @@
      * equal.
      * @hide
      */
-    private void combineSSIDs(NetworkCapabilities nc) {
+    private void combineSSIDs(@NonNull NetworkCapabilities nc) {
         if (mSSID != null && !mSSID.equals(nc.mSSID)) {
             throw new IllegalStateException("Can't combine two SSIDs");
         }
@@ -1319,7 +1319,7 @@
      * both lists will never be satisfied.
      * @hide
      */
-    public void combineCapabilities(NetworkCapabilities nc) {
+    public void combineCapabilities(@NonNull NetworkCapabilities nc) {
         combineNetCapabilities(nc);
         combineTransportTypes(nc);
         combineLinkBandwidths(nc);
@@ -1359,7 +1359,7 @@
      */
     @TestApi
     @SystemApi
-    public boolean satisfiedByNetworkCapabilities(NetworkCapabilities nc) {
+    public boolean satisfiedByNetworkCapabilities(@Nullable NetworkCapabilities nc) {
         return satisfiedByNetworkCapabilities(nc, false);
     }
 
@@ -1370,7 +1370,7 @@
      *
      * @hide
      */
-    public boolean satisfiedByImmutableNetworkCapabilities(NetworkCapabilities nc) {
+    public boolean satisfiedByImmutableNetworkCapabilities(@Nullable NetworkCapabilities nc) {
         return satisfiedByNetworkCapabilities(nc, true);
     }
 
@@ -1381,7 +1381,7 @@
      *
      * @hide
      */
-    public String describeImmutableDifferences(NetworkCapabilities that) {
+    public String describeImmutableDifferences(@Nullable NetworkCapabilities that) {
         if (that == null) {
             return "other NetworkCapabilities was null";
         }
@@ -1420,7 +1420,7 @@
      *
      * @hide
      */
-    public boolean equalRequestableCapabilities(NetworkCapabilities nc) {
+    public boolean equalRequestableCapabilities(@Nullable NetworkCapabilities nc) {
         if (nc == null) return false;
         return (equalsNetCapabilitiesRequestable(nc) &&
                 equalsTransportTypes(nc) &&
@@ -1428,7 +1428,7 @@
     }
 
     @Override
-    public boolean equals(Object obj) {
+    public boolean equals(@Nullable Object obj) {
         if (obj == null || (obj instanceof NetworkCapabilities == false)) return false;
         NetworkCapabilities that = (NetworkCapabilities) obj;
         return (equalsNetCapabilities(that)
@@ -1502,7 +1502,7 @@
         };
 
     @Override
-    public String toString() {
+    public @NonNull String toString() {
         final StringBuilder sb = new StringBuilder("[");
         if (0 != mTransportTypes) {
             sb.append(" Transports: ");
@@ -1561,8 +1561,8 @@
     /**
      * @hide
      */
-    public static void appendStringRepresentationOfBitMaskToStringBuilder(StringBuilder sb,
-            long bitMask, NameOf nameFetcher, String separator) {
+    public static void appendStringRepresentationOfBitMaskToStringBuilder(@NonNull StringBuilder sb,
+            long bitMask, @NonNull NameOf nameFetcher, @NonNull String separator) {
         int bitPos = 0;
         boolean firstElementAdded = false;
         while (bitMask != 0) {
@@ -1580,7 +1580,7 @@
     }
 
     /** @hide */
-    public void writeToProto(ProtoOutputStream proto, long fieldId) {
+    public void writeToProto(@NonNull ProtoOutputStream proto, long fieldId) {
         final long token = proto.start(fieldId);
 
         for (int transport : getTransportTypes()) {
@@ -1610,7 +1610,7 @@
     /**
      * @hide
      */
-    public static String capabilityNamesOf(@NetCapability int[] capabilities) {
+    public static @NonNull String capabilityNamesOf(@Nullable @NetCapability int[] capabilities) {
         StringJoiner joiner = new StringJoiner("|");
         if (capabilities != null) {
             for (int c : capabilities) {
@@ -1623,7 +1623,7 @@
     /**
      * @hide
      */
-    public static String capabilityNameOf(@NetCapability int capability) {
+    public static @NonNull String capabilityNameOf(@NetCapability int capability) {
         switch (capability) {
             case NET_CAPABILITY_MMS:                  return "MMS";
             case NET_CAPABILITY_SUPL:                 return "SUPL";
@@ -1658,7 +1658,7 @@
      * @hide
      */
     @UnsupportedAppUsage
-    public static String transportNamesOf(@Transport int[] types) {
+    public static @NonNull String transportNamesOf(@Nullable @Transport int[] types) {
         StringJoiner joiner = new StringJoiner("|");
         if (types != null) {
             for (int t : types) {
@@ -1671,7 +1671,7 @@
     /**
      * @hide
      */
-    public static String transportNameOf(@Transport int transport) {
+    public static @NonNull String transportNameOf(@Transport int transport) {
         if (!isValidTransport(transport)) {
             return "UNKNOWN";
         }
diff --git a/core/java/android/net/NetworkInfo.java b/core/java/android/net/NetworkInfo.java
index cd83531..92f105f 100644
--- a/core/java/android/net/NetworkInfo.java
+++ b/core/java/android/net/NetworkInfo.java
@@ -16,6 +16,7 @@
 
 package android.net;
 
+import android.annotation.NonNull;
 import android.annotation.UnsupportedAppUsage;
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -138,7 +139,9 @@
     private int mSubtype;
     private String mTypeName;
     private String mSubtypeName;
+    @NonNull
     private State mState;
+    @NonNull
     private DetailedState mDetailedState;
     private String mReason;
     private String mExtraInfo;
@@ -451,7 +454,7 @@
      *             the device and let apps react more easily and quickly to changes.
      */
     @Deprecated
-    public DetailedState getDetailedState() {
+    public @NonNull DetailedState getDetailedState() {
         synchronized (this) {
             return mDetailedState;
         }
diff --git a/core/java/android/net/NetworkRequest.java b/core/java/android/net/NetworkRequest.java
index dcb027d..51cbed4 100644
--- a/core/java/android/net/NetworkRequest.java
+++ b/core/java/android/net/NetworkRequest.java
@@ -347,7 +347,7 @@
          * @hide
          */
         @SystemApi
-        public Builder setSignalStrength(int signalStrength) {
+        public @NonNull Builder setSignalStrength(int signalStrength) {
             mNetworkCapabilities.setSignalStrength(signalStrength);
             return this;
         }
diff --git a/core/java/android/net/NetworkTemplate.java b/core/java/android/net/NetworkTemplate.java
index d42fce3..ae421a4 100644
--- a/core/java/android/net/NetworkTemplate.java
+++ b/core/java/android/net/NetworkTemplate.java
@@ -40,6 +40,7 @@
 import android.util.BackupUtils;
 import android.util.Log;
 
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.ArrayUtils;
 
 import java.io.ByteArrayOutputStream;
@@ -89,10 +90,22 @@
 
     private static boolean sForceAllNetworkTypes = false;
 
+    /**
+     * Results in matching against all mobile network types.
+     *
+     * <p>See {@link #matchesMobile} and {@link matchesMobileWildcard}.
+     */
+    @VisibleForTesting
     public static void forceAllNetworkTypes() {
         sForceAllNetworkTypes = true;
     }
 
+    /** Resets the affect of {@link #forceAllNetworkTypes}. */
+    @VisibleForTesting
+    public static void resetForceAllNetworkTypes() {
+        sForceAllNetworkTypes = false;
+    }
+
     /**
      * Template to match {@link ConnectivityManager#TYPE_MOBILE} networks with
      * the given IMSI.
diff --git a/core/java/android/net/ParseException.java b/core/java/android/net/ParseException.java
index 2380e86..9d4727a 100644
--- a/core/java/android/net/ParseException.java
+++ b/core/java/android/net/ParseException.java
@@ -16,15 +16,22 @@
 
 package android.net;
 
+import android.annotation.NonNull;
+
 /**
- * Thrown when parsing a URL fails.
+ * Thrown when parsing failed.
  */
 // See non-public class {@link WebAddress}.
 public class ParseException extends RuntimeException {
     public String response;
 
-    ParseException(String response) {
+    public ParseException(@NonNull String response) {
         super(response);
         this.response = response;
     }
+
+    public ParseException(@NonNull String response, @NonNull Throwable cause) {
+        super(response, cause);
+        this.response = response;
+    }
 }
diff --git a/core/java/android/net/RouteInfo.java b/core/java/android/net/RouteInfo.java
index c1c8f6e..b0239c8 100644
--- a/core/java/android/net/RouteInfo.java
+++ b/core/java/android/net/RouteInfo.java
@@ -16,6 +16,7 @@
 
 package android.net;
 
+import android.annotation.Nullable;
 import android.annotation.SystemApi;
 import android.annotation.TestApi;
 import android.annotation.UnsupportedAppUsage;
@@ -112,7 +113,8 @@
      */
     @SystemApi
     @TestApi
-    public RouteInfo(IpPrefix destination, InetAddress gateway, String iface, int type) {
+    public RouteInfo(@Nullable IpPrefix destination, @Nullable InetAddress gateway,
+            @Nullable String iface, int type) {
         switch (type) {
             case RTN_UNICAST:
             case RTN_UNREACHABLE:
diff --git a/core/java/android/net/StaticIpConfiguration.java b/core/java/android/net/StaticIpConfiguration.java
index 8b264ee..e253105 100644
--- a/core/java/android/net/StaticIpConfiguration.java
+++ b/core/java/android/net/StaticIpConfiguration.java
@@ -16,6 +16,8 @@
 
 package android.net;
 
+import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.annotation.SystemApi;
 import android.annotation.TestApi;
 import android.annotation.UnsupportedAppUsage;
@@ -53,22 +55,26 @@
 public final class StaticIpConfiguration implements Parcelable {
     /** @hide */
     @UnsupportedAppUsage
+    @Nullable
     public LinkAddress ipAddress;
     /** @hide */
     @UnsupportedAppUsage
+    @Nullable
     public InetAddress gateway;
     /** @hide */
     @UnsupportedAppUsage
+    @NonNull
     public final ArrayList<InetAddress> dnsServers;
     /** @hide */
     @UnsupportedAppUsage
+    @Nullable
     public String domains;
 
     public StaticIpConfiguration() {
         dnsServers = new ArrayList<InetAddress>();
     }
 
-    public StaticIpConfiguration(StaticIpConfiguration source) {
+    public StaticIpConfiguration(@Nullable StaticIpConfiguration source) {
         this();
         if (source != null) {
             // All of these except dnsServers are immutable, so no need to make copies.
@@ -86,38 +92,38 @@
         domains = null;
     }
 
-    public LinkAddress getIpAddress() {
+    public @Nullable LinkAddress getIpAddress() {
         return ipAddress;
     }
 
-    public void setIpAddress(LinkAddress ipAddress) {
+    public void setIpAddress(@Nullable LinkAddress ipAddress) {
         this.ipAddress = ipAddress;
     }
 
-    public InetAddress getGateway() {
+    public @Nullable InetAddress getGateway() {
         return gateway;
     }
 
-    public void setGateway(InetAddress gateway) {
+    public void setGateway(@Nullable InetAddress gateway) {
         this.gateway = gateway;
     }
 
-    public List<InetAddress> getDnsServers() {
+    public @NonNull List<InetAddress> getDnsServers() {
         return dnsServers;
     }
 
-    public String getDomains() {
+    public @Nullable String getDomains() {
         return domains;
     }
 
-    public void setDomains(String newDomains) {
+    public void setDomains(@Nullable String newDomains) {
         domains = newDomains;
     }
 
     /**
      * Add a DNS server to this configuration.
      */
-    public void addDnsServer(InetAddress server) {
+    public void addDnsServer(@NonNull InetAddress server) {
         dnsServers.add(server);
     }
 
@@ -128,7 +134,7 @@
      * route to the gateway as well. This configuration is arguably invalid, but it used to work
      * in K and earlier, and other OSes appear to accept it.
      */
-    public List<RouteInfo> getRoutes(String iface) {
+    public @NonNull List<RouteInfo> getRoutes(String iface) {
         List<RouteInfo> routes = new ArrayList<RouteInfo>(3);
         if (ipAddress != null) {
             RouteInfo connectedRoute = new RouteInfo(ipAddress, null, iface);
@@ -150,7 +156,7 @@
      * IPv6 configuration) will not be included.
      * @hide
      */
-    public LinkProperties toLinkProperties(String iface) {
+    public @NonNull LinkProperties toLinkProperties(String iface) {
         LinkProperties lp = new LinkProperties();
         lp.setInterfaceName(iface);
         if (ipAddress != null) {
diff --git a/core/java/android/net/TcpKeepalivePacketDataParcelable.aidl b/core/java/android/net/TcpKeepalivePacketDataParcelable.aidl
index 7329c63..d66b6ae 100644
--- a/core/java/android/net/TcpKeepalivePacketDataParcelable.aidl
+++ b/core/java/android/net/TcpKeepalivePacketDataParcelable.aidl
@@ -23,4 +23,6 @@
     int dstPort;
     int seq;
     int ack;
+    int rcvWnd;
+    int rcvWndScale;
 }
diff --git a/core/java/android/net/UidRange.java b/core/java/android/net/UidRange.java
index d4a4cf4..e56f059 100644
--- a/core/java/android/net/UidRange.java
+++ b/core/java/android/net/UidRange.java
@@ -19,14 +19,17 @@
 import static android.os.UserHandle.PER_USER_RANGE;
 
 import android.os.Parcel;
+import android.os.Parcelable;
 
 /**
  * An inclusive range of UIDs.
  *
  * @hide
  */
-public final class UidRange extends UidRangeParcel {
-    private UidRange() {}
+public final class UidRange implements Parcelable {
+    public final int start;
+    public final int stop;
+
     public UidRange(int startUid, int stopUid) {
         if (startUid < 0) throw new IllegalArgumentException("Invalid start UID.");
         if (stopUid < 0) throw new IllegalArgumentException("Invalid stop UID.");
@@ -86,18 +89,28 @@
         return start + "-" + stop;
     }
 
-    /**
-     * DO NOT override "writeToParcel" and "readFromParcel" in this class.
-     * The parceling code is autogenerated by the superclass.
-     */
+    // Implement the Parcelable interface
+    // TODO: Consider making this class no longer parcelable, since all users are likely in the
+    // system server.
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeInt(start);
+        dest.writeInt(stop);
+    }
 
     public static final @android.annotation.NonNull Creator<UidRange> CREATOR =
         new Creator<UidRange>() {
             @Override
             public UidRange createFromParcel(Parcel in) {
-                UidRange obj = new UidRange();
-                obj.readFromParcel(in);
-                return obj;
+                int start = in.readInt();
+                int stop = in.readInt();
+
+                return new UidRange(start, stop);
             }
             @Override
             public UidRange[] newArray(int size) {
diff --git a/core/java/android/net/VpnService.java b/core/java/android/net/VpnService.java
index 870d8b1..ea245a4 100644
--- a/core/java/android/net/VpnService.java
+++ b/core/java/android/net/VpnService.java
@@ -27,6 +27,8 @@
 import android.app.Activity;
 import android.app.PendingIntent;
 import android.app.Service;
+import android.app.admin.DevicePolicyManager;
+import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.IPackageManager;
@@ -48,6 +50,7 @@
 import java.net.Socket;
 import java.util.ArrayList;
 import java.util.List;
+import java.util.Set;
 
 /**
  * VpnService is a base class for applications to extend and build their
@@ -138,7 +141,7 @@
      * provides users with the ability to set it as always-on, so that VPN connection is
      * persisted after device reboot and app upgrade. Always-on VPN can also be enabled by device
      * owner and profile owner apps through
-     * {@link android.app.admin.DevicePolicyManager#setAlwaysOnVpnPackage}.
+     * {@link DevicePolicyManager#setAlwaysOnVpnPackage}.
      *
      * <p>VPN apps not supporting this feature should opt out by adding this meta-data field to the
      * {@code VpnService} component of {@code AndroidManifest.xml}. In case there is more than one
@@ -370,7 +373,10 @@
     }
 
     /**
-     * Returns whether the service is running in always-on VPN mode.
+     * Returns whether the service is running in always-on VPN mode. In this mode the system ensures
+     * that the service is always running by restarting it when necessary, e.g. after reboot.
+     *
+     * @see DevicePolicyManager#setAlwaysOnVpnPackage(ComponentName, String, boolean, Set)
      */
     public final boolean isAlwaysOn() {
         try {
@@ -381,8 +387,11 @@
     }
 
     /**
-     * Returns whether the service is running in always-on VPN mode blocking connections without
-     * VPN.
+     * Returns whether the service is running in always-on VPN lockdown mode. In this mode the
+     * system ensures that the service is always running and that the apps aren't allowed to bypass
+     * the VPN.
+     *
+     * @see DevicePolicyManager#setAlwaysOnVpnPackage(ComponentName, String, boolean, Set)
      */
     public final boolean isLockdownEnabled() {
         try {
diff --git a/core/java/android/net/apf/ApfCapabilities.java b/core/java/android/net/apf/ApfCapabilities.java
index e09fa8f..17a03c7c 100644
--- a/core/java/android/net/apf/ApfCapabilities.java
+++ b/core/java/android/net/apf/ApfCapabilities.java
@@ -16,20 +16,24 @@
 
 package android.net.apf;
 
+import android.annotation.NonNull;
 import android.annotation.SystemApi;
 import android.annotation.TestApi;
 import android.content.Context;
+import android.os.Parcel;
+import android.os.Parcelable;
 
 import com.android.internal.R;
 
 /**
  * APF program support capabilities.
  *
+ * This class is immutable.
  * @hide
  */
 @SystemApi
 @TestApi
-public class ApfCapabilities {
+public final class ApfCapabilities implements Parcelable {
     /**
      * Version of APF instruction set supported for packet filtering. 0 indicates no support for
      * packet filtering using APF programs.
@@ -53,6 +57,37 @@
         this.apfPacketFormat = apfPacketFormat;
     }
 
+    private ApfCapabilities(Parcel in) {
+        apfVersionSupported = in.readInt();
+        maximumApfProgramSize = in.readInt();
+        apfPacketFormat = in.readInt();
+    }
+
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeInt(apfVersionSupported);
+        dest.writeInt(maximumApfProgramSize);
+        dest.writeInt(apfPacketFormat);
+    }
+
+    public static final Creator<ApfCapabilities> CREATOR = new Creator<ApfCapabilities>() {
+        @Override
+        public ApfCapabilities createFromParcel(Parcel in) {
+            return new ApfCapabilities(in);
+        }
+
+        @Override
+        public ApfCapabilities[] newArray(int size) {
+            return new ApfCapabilities[size];
+        }
+    };
+
     @Override
     public String toString() {
         return String.format("%s{version: %d, maxSize: %d, format: %d}", getClass().getSimpleName(),
@@ -81,14 +116,14 @@
     /**
      * @return Whether the APF Filter in the device should filter out IEEE 802.3 Frames.
      */
-    public static boolean getApfDrop8023Frames(Context context) {
+    public static boolean getApfDrop8023Frames(@NonNull Context context) {
         return context.getResources().getBoolean(R.bool.config_apfDrop802_3Frames);
     }
 
     /**
      * @return An array of blacklisted EtherType, packets with EtherTypes within it will be dropped.
      */
-    public static int[] getApfEthTypeBlackList(Context context) {
+    public static @NonNull int[] getApfEthTypeBlackList(@NonNull Context context) {
         return context.getResources().getIntArray(R.array.config_apfEthTypeBlackList);
     }
 }
diff --git a/core/java/android/net/captiveportal/CaptivePortalProbeResult.java b/core/java/android/net/captiveportal/CaptivePortalProbeResult.java
index 3930344..a1d3de2 100644
--- a/core/java/android/net/captiveportal/CaptivePortalProbeResult.java
+++ b/core/java/android/net/captiveportal/CaptivePortalProbeResult.java
@@ -16,6 +16,7 @@
 
 package android.net.captiveportal;
 
+import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.SystemApi;
 import android.annotation.TestApi;
@@ -39,14 +40,18 @@
      */
     public static final int PARTIAL_CODE = -1;
 
+    @NonNull
     public static final CaptivePortalProbeResult FAILED = new CaptivePortalProbeResult(FAILED_CODE);
+    @NonNull
     public static final CaptivePortalProbeResult SUCCESS =
             new CaptivePortalProbeResult(SUCCESS_CODE);
     public static final CaptivePortalProbeResult PARTIAL =
             new CaptivePortalProbeResult(PARTIAL_CODE);
 
     private final int mHttpResponseCode;  // HTTP response code returned from Internet probe.
+    @Nullable
     public final String redirectUrl;      // Redirect destination returned from Internet probe.
+    @Nullable
     public final String detectUrl;        // URL where a 204 response code indicates
                                           // captive portal has been appeased.
     @Nullable
@@ -56,12 +61,13 @@
         this(httpResponseCode, null, null);
     }
 
-    public CaptivePortalProbeResult(int httpResponseCode, String redirectUrl, String detectUrl) {
+    public CaptivePortalProbeResult(int httpResponseCode, @Nullable String redirectUrl,
+            @Nullable String detectUrl) {
         this(httpResponseCode, redirectUrl, detectUrl, null);
     }
 
-    public CaptivePortalProbeResult(int httpResponseCode, String redirectUrl, String detectUrl,
-            CaptivePortalProbeSpec probeSpec) {
+    public CaptivePortalProbeResult(int httpResponseCode, @Nullable String redirectUrl,
+            @Nullable String detectUrl, @Nullable CaptivePortalProbeSpec probeSpec) {
         mHttpResponseCode = httpResponseCode;
         this.redirectUrl = redirectUrl;
         this.detectUrl = detectUrl;
diff --git a/core/java/android/net/captiveportal/CaptivePortalProbeSpec.java b/core/java/android/net/captiveportal/CaptivePortalProbeSpec.java
index 7ad4ecf..6c6a16c 100644
--- a/core/java/android/net/captiveportal/CaptivePortalProbeSpec.java
+++ b/core/java/android/net/captiveportal/CaptivePortalProbeSpec.java
@@ -19,6 +19,8 @@
 import static android.net.captiveportal.CaptivePortalProbeResult.PORTAL_CODE;
 import static android.net.captiveportal.CaptivePortalProbeResult.SUCCESS_CODE;
 
+import static com.android.internal.util.Preconditions.checkNotNull;
+
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.SystemApi;
@@ -48,9 +50,10 @@
     private final String mEncodedSpec;
     private final URL mUrl;
 
-    CaptivePortalProbeSpec(String encodedSpec, URL url) {
-        mEncodedSpec = encodedSpec;
-        mUrl = url;
+    CaptivePortalProbeSpec(@NonNull String encodedSpec, @NonNull URL url)
+            throws NullPointerException {
+        mEncodedSpec = checkNotNull(encodedSpec);
+        mUrl = checkNotNull(url);
     }
 
     /**
@@ -64,7 +67,7 @@
      */
     @VisibleForTesting
     @NonNull
-    public static CaptivePortalProbeSpec parseSpec(String spec) throws ParseException,
+    public static CaptivePortalProbeSpec parseSpec(@NonNull String spec) throws ParseException,
             MalformedURLException {
         if (TextUtils.isEmpty(spec)) {
             throw new ParseException("Empty probe spec", 0 /* errorOffset */);
@@ -84,7 +87,8 @@
     }
 
     @Nullable
-    private static Pattern parsePatternIfNonEmpty(String pattern, int pos) throws ParseException {
+    private static Pattern parsePatternIfNonEmpty(@Nullable String pattern, int pos)
+            throws ParseException {
         if (TextUtils.isEmpty(pattern)) {
             return null;
         }
@@ -120,8 +124,9 @@
      * <p>Each spec is separated by @@,@@ and follows the format for {@link #parseSpec(String)}.
      * <p>This method does not throw but ignores any entry that could not be parsed.
      */
+    @NonNull
     public static Collection<CaptivePortalProbeSpec> parseCaptivePortalProbeSpecs(
-            String settingsVal) {
+            @NonNull String settingsVal) {
         List<CaptivePortalProbeSpec> specs = new ArrayList<>();
         if (settingsVal != null) {
             for (String spec : TextUtils.split(settingsVal, SPEC_SEPARATOR)) {
@@ -142,12 +147,15 @@
     /**
      * Get the probe result from HTTP status and location header.
      */
+    @NonNull
     public abstract CaptivePortalProbeResult getResult(int status, @Nullable String locationHeader);
 
+    @NonNull
     public String getEncodedSpec() {
         return mEncodedSpec;
     }
 
+    @NonNull
     public URL getUrl() {
         return mUrl;
     }
diff --git a/core/java/android/net/metrics/ApfProgramEvent.java b/core/java/android/net/metrics/ApfProgramEvent.java
index b30d8cb..2bd4378 100644
--- a/core/java/android/net/metrics/ApfProgramEvent.java
+++ b/core/java/android/net/metrics/ApfProgramEvent.java
@@ -17,6 +17,7 @@
 package android.net.metrics;
 
 import android.annotation.IntDef;
+import android.annotation.NonNull;
 import android.annotation.SystemApi;
 import android.annotation.TestApi;
 import android.annotation.UnsupportedAppUsage;
@@ -95,7 +96,7 @@
     /**
      * Utility to create an instance of {@link ApfProgramEvent}.
      */
-    public static class Builder {
+    public static final class Builder {
         private long mLifetime;
         private long mActualLifetime;
         private int mFilteredRas;
@@ -106,6 +107,7 @@
         /**
          * Set the maximum computed lifetime of the program in seconds.
          */
+        @NonNull
         public Builder setLifetime(long lifetime) {
             mLifetime = lifetime;
             return this;
@@ -114,6 +116,7 @@
         /**
          * Set the effective program lifetime in seconds.
          */
+        @NonNull
         public Builder setActualLifetime(long lifetime) {
             mActualLifetime = lifetime;
             return this;
@@ -122,6 +125,7 @@
         /**
          * Set the number of RAs filtered by the APF program.
          */
+        @NonNull
         public Builder setFilteredRas(int filteredRas) {
             mFilteredRas = filteredRas;
             return this;
@@ -130,6 +134,7 @@
         /**
          * Set the total number of current RAs at generation time.
          */
+        @NonNull
         public Builder setCurrentRas(int currentRas) {
             mCurrentRas = currentRas;
             return this;
@@ -138,6 +143,7 @@
         /**
          * Set the length of the APF program in bytes.
          */
+        @NonNull
         public Builder setProgramLength(int programLength) {
             mProgramLength = programLength;
             return this;
@@ -146,6 +152,7 @@
         /**
          * Set the flags describing what an Apf program filters.
          */
+        @NonNull
         public Builder setFlags(boolean hasIPv4, boolean multicastFilterOn) {
             mFlags = flagsFor(hasIPv4, multicastFilterOn);
             return this;
@@ -154,6 +161,7 @@
         /**
          * Build a new {@link ApfProgramEvent}.
          */
+        @NonNull
         public ApfProgramEvent build() {
             return new ApfProgramEvent(mLifetime, mActualLifetime, mFilteredRas, mCurrentRas,
                     mProgramLength, mFlags);
diff --git a/core/java/android/net/metrics/ApfStats.java b/core/java/android/net/metrics/ApfStats.java
index e1c8888..6c3b7af 100644
--- a/core/java/android/net/metrics/ApfStats.java
+++ b/core/java/android/net/metrics/ApfStats.java
@@ -16,6 +16,7 @@
 
 package android.net.metrics;
 
+import android.annotation.NonNull;
 import android.annotation.SystemApi;
 import android.annotation.TestApi;
 import android.annotation.UnsupportedAppUsage;
@@ -125,7 +126,7 @@
      */
     @SystemApi
     @TestApi
-    public static class Builder {
+    public static final class Builder {
         private long mDurationMs;
         private int mReceivedRas;
         private int mMatchingRas;
@@ -140,6 +141,7 @@
         /**
          * Set the time interval in milliseconds these statistics covers.
          */
+        @NonNull
         public Builder setDurationMs(long durationMs) {
             mDurationMs = durationMs;
             return this;
@@ -148,6 +150,7 @@
         /**
          * Set the number of received RAs.
          */
+        @NonNull
         public Builder setReceivedRas(int receivedRas) {
             mReceivedRas = receivedRas;
             return this;
@@ -156,6 +159,7 @@
         /**
          * Set the number of received RAs matching a known RA.
          */
+        @NonNull
         public Builder setMatchingRas(int matchingRas) {
             mMatchingRas = matchingRas;
             return this;
@@ -164,6 +168,7 @@
         /**
          * Set the number of received RAs ignored due to the MAX_RAS limit.
          */
+        @NonNull
         public Builder setDroppedRas(int droppedRas) {
             mDroppedRas = droppedRas;
             return this;
@@ -172,6 +177,7 @@
         /**
          * Set the number of received RAs with a minimum lifetime of 0.
          */
+        @NonNull
         public Builder setZeroLifetimeRas(int zeroLifetimeRas) {
             mZeroLifetimeRas = zeroLifetimeRas;
             return this;
@@ -180,6 +186,7 @@
         /**
          * Set the number of received RAs that could not be parsed.
          */
+        @NonNull
         public Builder setParseErrors(int parseErrors) {
             mParseErrors = parseErrors;
             return this;
@@ -188,6 +195,7 @@
         /**
          * Set the number of APF program updates from receiving RAs.
          */
+        @NonNull
         public Builder setProgramUpdates(int programUpdates) {
             mProgramUpdates = programUpdates;
             return this;
@@ -196,6 +204,7 @@
         /**
          * Set the total number of APF program updates.
          */
+        @NonNull
         public Builder setProgramUpdatesAll(int programUpdatesAll) {
             mProgramUpdatesAll = programUpdatesAll;
             return this;
@@ -204,6 +213,7 @@
         /**
          * Set the number of APF program updates from allowing multicast traffic.
          */
+        @NonNull
         public Builder setProgramUpdatesAllowingMulticast(int programUpdatesAllowingMulticast) {
             mProgramUpdatesAllowingMulticast = programUpdatesAllowingMulticast;
             return this;
@@ -212,6 +222,7 @@
         /**
          * Set the maximum APF program size advertised by hardware.
          */
+        @NonNull
         public Builder setMaxProgramSize(int maxProgramSize) {
             mMaxProgramSize = maxProgramSize;
             return this;
@@ -220,6 +231,7 @@
         /**
          * Create a new {@link ApfStats}.
          */
+        @NonNull
         public ApfStats build() {
             return new ApfStats(mDurationMs, mReceivedRas, mMatchingRas, mDroppedRas,
                     mZeroLifetimeRas, mParseErrors, mProgramUpdates, mProgramUpdatesAll,
diff --git a/core/java/android/net/metrics/DhcpClientEvent.java b/core/java/android/net/metrics/DhcpClientEvent.java
index e4faea9..a3d0a20 100644
--- a/core/java/android/net/metrics/DhcpClientEvent.java
+++ b/core/java/android/net/metrics/DhcpClientEvent.java
@@ -16,6 +16,7 @@
 
 package android.net.metrics;
 
+import android.annotation.NonNull;
 import android.annotation.SystemApi;
 import android.annotation.TestApi;
 import android.annotation.UnsupportedAppUsage;
@@ -51,13 +52,14 @@
     /**
      * Utility to create an instance of {@link ApfProgramEvent}.
      */
-    public static class Builder {
+    public static final class Builder {
         private String mMsg;
         private int mDurationMs;
 
         /**
          * Set the message of the event.
          */
+        @NonNull
         public Builder setMsg(String msg) {
             mMsg = msg;
             return this;
@@ -66,6 +68,7 @@
         /**
          * Set the duration of the event in milliseconds.
          */
+        @NonNull
         public Builder setDurationMs(int durationMs) {
             mDurationMs = durationMs;
             return this;
@@ -74,6 +77,7 @@
         /**
          * Create a new {@link DhcpClientEvent}.
          */
+        @NonNull
         public DhcpClientEvent build() {
             return new DhcpClientEvent(mMsg, mDurationMs);
         }
diff --git a/core/java/android/net/metrics/DhcpErrorEvent.java b/core/java/android/net/metrics/DhcpErrorEvent.java
index 91318a2..652ce5d 100644
--- a/core/java/android/net/metrics/DhcpErrorEvent.java
+++ b/core/java/android/net/metrics/DhcpErrorEvent.java
@@ -37,26 +37,26 @@
     public static final int DHCP_ERROR = 4;
     public static final int MISC_ERROR = 5;
 
-    public static final int L2_TOO_SHORT               = makeErrorCode(L2_ERROR, 1);
-    public static final int L2_WRONG_ETH_TYPE          = makeErrorCode(L2_ERROR, 2);
+    public static final int L2_TOO_SHORT               = (L2_ERROR << 24) | (1 << 16);
+    public static final int L2_WRONG_ETH_TYPE          = (L2_ERROR << 24) | (2 << 16);
 
-    public static final int L3_TOO_SHORT               = makeErrorCode(L3_ERROR, 1);
-    public static final int L3_NOT_IPV4                = makeErrorCode(L3_ERROR, 2);
-    public static final int L3_INVALID_IP              = makeErrorCode(L3_ERROR, 3);
+    public static final int L3_TOO_SHORT               = (L3_ERROR << 24) | (1 << 16);
+    public static final int L3_NOT_IPV4                = (L3_ERROR << 24) | (2 << 16);
+    public static final int L3_INVALID_IP              = (L3_ERROR << 24) | (3 << 16);
 
-    public static final int L4_NOT_UDP                 = makeErrorCode(L4_ERROR, 1);
-    public static final int L4_WRONG_PORT              = makeErrorCode(L4_ERROR, 2);
+    public static final int L4_NOT_UDP                 = (L4_ERROR << 24) | (1 << 16);
+    public static final int L4_WRONG_PORT              = (L4_ERROR << 24) | (2 << 16);
 
-    public static final int BOOTP_TOO_SHORT            = makeErrorCode(DHCP_ERROR, 1);
-    public static final int DHCP_BAD_MAGIC_COOKIE      = makeErrorCode(DHCP_ERROR, 2);
-    public static final int DHCP_INVALID_OPTION_LENGTH = makeErrorCode(DHCP_ERROR, 3);
-    public static final int DHCP_NO_MSG_TYPE           = makeErrorCode(DHCP_ERROR, 4);
-    public static final int DHCP_UNKNOWN_MSG_TYPE      = makeErrorCode(DHCP_ERROR, 5);
-    public static final int DHCP_NO_COOKIE             = makeErrorCode(DHCP_ERROR, 6);
+    public static final int BOOTP_TOO_SHORT            = (DHCP_ERROR << 24) | (1 << 16);
+    public static final int DHCP_BAD_MAGIC_COOKIE      = (DHCP_ERROR << 24) | (2 << 16);
+    public static final int DHCP_INVALID_OPTION_LENGTH = (DHCP_ERROR << 24) | (3 << 16);
+    public static final int DHCP_NO_MSG_TYPE           = (DHCP_ERROR << 24) | (4 << 16);
+    public static final int DHCP_UNKNOWN_MSG_TYPE      = (DHCP_ERROR << 24) | (5 << 16);
+    public static final int DHCP_NO_COOKIE             = (DHCP_ERROR << 24) | (6 << 16);
 
-    public static final int BUFFER_UNDERFLOW           = makeErrorCode(MISC_ERROR, 1);
-    public static final int RECEIVE_ERROR              = makeErrorCode(MISC_ERROR, 2);
-    public static final int PARSING_ERROR              = makeErrorCode(MISC_ERROR, 3);
+    public static final int BUFFER_UNDERFLOW           = (MISC_ERROR << 24) | (1 << 16);
+    public static final int RECEIVE_ERROR              = (MISC_ERROR << 24) | (2 << 16);
+    public static final int PARSING_ERROR              = (MISC_ERROR << 24) | (3 << 16);
 
     // error code byte format (MSB to LSB):
     // byte 0: error type
@@ -102,10 +102,6 @@
         return (0xFFFF0000 & errorCode) | (0xFF & option);
     }
 
-    private static int makeErrorCode(int type, int subtype) {
-        return (type << 24) | ((0xFF & subtype) << 16);
-    }
-
     @Override
     public String toString() {
         return String.format("DhcpErrorEvent(%s)", Decoder.constants.get(errorCode));
diff --git a/core/java/android/net/metrics/IpConnectivityLog.java b/core/java/android/net/metrics/IpConnectivityLog.java
index 5b5a235..680c015 100644
--- a/core/java/android/net/metrics/IpConnectivityLog.java
+++ b/core/java/android/net/metrics/IpConnectivityLog.java
@@ -16,6 +16,7 @@
 
 package android.net.metrics;
 
+import android.annotation.NonNull;
 import android.annotation.SystemApi;
 import android.annotation.TestApi;
 import android.net.ConnectivityMetricsEvent;
@@ -41,7 +42,7 @@
 
     /** @hide */
     public static final String SERVICE_NAME = "connmetrics";
-
+    @NonNull
     private IIpConnectivityMetrics mService;
 
     /**
@@ -57,7 +58,7 @@
 
     /** @hide */
     @VisibleForTesting
-    public IpConnectivityLog(IIpConnectivityMetrics service) {
+    public IpConnectivityLog(@NonNull IIpConnectivityMetrics service) {
         mService = service;
     }
 
@@ -83,7 +84,7 @@
      * @return true if the event was successfully logged.
      * @hide
      */
-    public boolean log(ConnectivityMetricsEvent ev) {
+    public boolean log(@NonNull ConnectivityMetricsEvent ev) {
         if (!checkLoggerService()) {
             if (DBG) {
                 Log.d(TAG, SERVICE_NAME + " service was not ready");
@@ -109,7 +110,7 @@
      * @param data is a Parcelable instance representing the event.
      * @return true if the event was successfully logged.
      */
-    public boolean log(long timestamp, Event data) {
+    public boolean log(long timestamp, @NonNull Event data) {
         ConnectivityMetricsEvent ev = makeEv(data);
         ev.timestamp = timestamp;
         return log(ev);
@@ -121,7 +122,7 @@
      * @param data is a Parcelable instance representing the event.
      * @return true if the event was successfully logged.
      */
-    public boolean log(String ifname, Event data) {
+    public boolean log(@NonNull String ifname, @NonNull Event data) {
         ConnectivityMetricsEvent ev = makeEv(data);
         ev.ifname = ifname;
         return log(ev);
@@ -135,7 +136,7 @@
      * @param data is a Parcelable instance representing the event.
      * @return true if the event was successfully logged.
      */
-    public boolean log(Network network, int[] transports, Event data) {
+    public boolean log(@NonNull Network network, @NonNull int[] transports, @NonNull Event data) {
         return log(network.netId, transports, data);
     }
 
@@ -147,7 +148,7 @@
      * @param data is a Parcelable instance representing the event.
      * @return true if the event was successfully logged.
      */
-    public boolean log(int netid, int[] transports, Event data) {
+    public boolean log(int netid, @NonNull int[] transports, @NonNull Event data) {
         ConnectivityMetricsEvent ev = makeEv(data);
         ev.netId = netid;
         ev.transports = BitUtils.packBits(transports);
@@ -159,7 +160,7 @@
      * @param data is a Parcelable instance representing the event.
      * @return true if the event was successfully logged.
      */
-    public boolean log(Event data) {
+    public boolean log(@NonNull Event data) {
         return log(makeEv(data));
     }
 
diff --git a/core/java/android/net/metrics/RaEvent.java b/core/java/android/net/metrics/RaEvent.java
index 0d43f12..b2f6585 100644
--- a/core/java/android/net/metrics/RaEvent.java
+++ b/core/java/android/net/metrics/RaEvent.java
@@ -16,6 +16,7 @@
 
 package android.net.metrics;
 
+import android.annotation.NonNull;
 import android.annotation.SystemApi;
 import android.annotation.TestApi;
 import android.os.Parcel;
@@ -107,7 +108,7 @@
         }
     };
 
-    public static class Builder {
+    public static final class Builder {
 
         long routerLifetime          = NO_LIFETIME;
         long prefixValidLifetime     = NO_LIFETIME;
@@ -119,37 +120,37 @@
         public Builder() {
         }
 
-        public RaEvent build() {
+        public @NonNull RaEvent build() {
             return new RaEvent(routerLifetime, prefixValidLifetime, prefixPreferredLifetime,
                     routeInfoLifetime, rdnssLifetime, dnsslLifetime);
         }
 
-        public Builder updateRouterLifetime(long lifetime) {
+        public @NonNull Builder updateRouterLifetime(long lifetime) {
             routerLifetime = updateLifetime(routerLifetime, lifetime);
             return this;
         }
 
-        public Builder updatePrefixValidLifetime(long lifetime) {
+        public @NonNull Builder updatePrefixValidLifetime(long lifetime) {
             prefixValidLifetime = updateLifetime(prefixValidLifetime, lifetime);
             return this;
         }
 
-        public Builder updatePrefixPreferredLifetime(long lifetime) {
+        public @NonNull Builder updatePrefixPreferredLifetime(long lifetime) {
             prefixPreferredLifetime = updateLifetime(prefixPreferredLifetime, lifetime);
             return this;
         }
 
-        public Builder updateRouteInfoLifetime(long lifetime) {
+        public @NonNull Builder updateRouteInfoLifetime(long lifetime) {
             routeInfoLifetime = updateLifetime(routeInfoLifetime, lifetime);
             return this;
         }
 
-        public Builder updateRdnssLifetime(long lifetime) {
+        public @NonNull Builder updateRdnssLifetime(long lifetime) {
             rdnssLifetime = updateLifetime(rdnssLifetime, lifetime);
             return this;
         }
 
-        public Builder updateDnsslLifetime(long lifetime) {
+        public @NonNull Builder updateDnsslLifetime(long lifetime) {
             dnsslLifetime = updateLifetime(dnsslLifetime, lifetime);
             return this;
         }
diff --git a/core/java/android/net/metrics/ValidationProbeEvent.java b/core/java/android/net/metrics/ValidationProbeEvent.java
index 052758d..45b665d 100644
--- a/core/java/android/net/metrics/ValidationProbeEvent.java
+++ b/core/java/android/net/metrics/ValidationProbeEvent.java
@@ -17,6 +17,7 @@
 package android.net.metrics;
 
 import android.annotation.IntDef;
+import android.annotation.NonNull;
 import android.annotation.SystemApi;
 import android.annotation.TestApi;
 import android.os.Parcel;
@@ -81,7 +82,7 @@
     /**
      * Utility to create an instance of {@link ValidationProbeEvent}.
      */
-    public static class Builder {
+    public static final class Builder {
         private long mDurationMs;
         private int mProbeType;
         private int mReturnCode;
@@ -89,6 +90,7 @@
         /**
          * Set the duration of the probe in milliseconds.
          */
+        @NonNull
         public Builder setDurationMs(long durationMs) {
             mDurationMs = durationMs;
             return this;
@@ -97,6 +99,7 @@
         /**
          * Set the probe type based on whether it was the first validation.
          */
+        @NonNull
         public Builder setProbeType(int probeType, boolean firstValidation) {
             mProbeType = makeProbeType(probeType, firstValidation);
             return this;
@@ -105,6 +108,7 @@
         /**
          * Set the return code of the probe.
          */
+        @NonNull
         public Builder setReturnCode(int returnCode) {
             mReturnCode = returnCode;
             return this;
@@ -113,6 +117,7 @@
         /**
          * Create a new {@link ValidationProbeEvent}.
          */
+        @NonNull
         public ValidationProbeEvent build() {
             return new ValidationProbeEvent(mDurationMs, mProbeType, mReturnCode);
         }
diff --git a/core/java/android/net/nsd/INsdManager.aidl b/core/java/android/net/nsd/INsdManager.aidl
index 3361a7b..9484c74 100644
--- a/core/java/android/net/nsd/INsdManager.aidl
+++ b/core/java/android/net/nsd/INsdManager.aidl
@@ -25,6 +25,7 @@
  */
 interface INsdManager
 {
+    @UnsupportedAppUsage
     Messenger getMessenger();
     void setEnabled(boolean enable);
 }
diff --git a/core/java/android/net/util/SocketUtils.java b/core/java/android/net/util/SocketUtils.java
index 5827f9e..6f8aece 100644
--- a/core/java/android/net/util/SocketUtils.java
+++ b/core/java/android/net/util/SocketUtils.java
@@ -45,7 +45,7 @@
  */
 @SystemApi
 @TestApi
-public class SocketUtils {
+public final class SocketUtils {
     /**
      * Create a raw datagram socket that is bound to an interface.
      *
@@ -63,6 +63,7 @@
     /**
      * Make a socket address to communicate with netlink.
      */
+    @NonNull
     public static SocketAddress makeNetlinkSocketAddress(int portId, int groupsMask) {
         return new NetlinkSocketAddress(portId, groupsMask);
     }
@@ -70,13 +71,15 @@
     /**
      * Make socket address that packet sockets can bind to.
      */
-    public static SocketAddress makePacketSocketAddress(short protocol, int ifIndex) {
-        return new PacketSocketAddress(protocol, ifIndex);
+    @NonNull
+    public static SocketAddress makePacketSocketAddress(int protocol, int ifIndex) {
+        return new PacketSocketAddress((short) protocol, ifIndex);
     }
 
     /**
      * Make a socket address that packet socket can send packets to.
      */
+    @NonNull
     public static SocketAddress makePacketSocketAddress(int ifIndex, @NonNull byte[] hwAddr) {
         return new PacketSocketAddress(ifIndex, hwAddr);
     }
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index 4fae3a8..b64fe00 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -200,13 +200,21 @@
 
     /**
      * Include only the current run in the stats.
+     *
+     * @deprecated As of {@link android.os.Build.VERSION_CODES#Q}, only {@link #STATS_SINCE_CHARGED}
+     * is supported.
      */
     @UnsupportedAppUsage
+    @Deprecated
     public static final int STATS_CURRENT = 1;
 
     /**
      * Include only the run since the last time the device was unplugged in the stats.
+     *
+     * @deprecated As of {@link android.os.Build.VERSION_CODES#Q}, only {@link #STATS_SINCE_CHARGED}
+     * is supported.
      */
+    @Deprecated
     public static final int STATS_SINCE_UNPLUGGED = 2;
 
     // NOTE: Update this list if you add/change any stats above.
@@ -255,8 +263,10 @@
      *   - Ambient display properly output in data dump.
      * New in version 33:
      *   - Fixed bug in min learned capacity updating process.
+     * New in version 34:
+     *   - Deprecated STATS_SINCE_UNPLUGGED and STATS_CURRENT.
      */
-    static final int CHECKIN_VERSION = 33;
+    static final int CHECKIN_VERSION = 34;
 
     /**
      * Old version, we hit 9 and ran out of room, need to remove.
@@ -3651,6 +3661,14 @@
      */
     public final void dumpCheckinLocked(Context context, PrintWriter pw, int which, int reqUid,
             boolean wifiOnly) {
+
+        if (which != BatteryStats.STATS_SINCE_CHARGED) {
+            dumpLine(pw, 0, STAT_NAMES[which], "err",
+                    "ERROR: BatteryStats.dumpCheckin called for which type " + which
+                    + " but only STATS_SINCE_CHARGED is supported.");
+            return;
+        }
+
         final long rawUptime = SystemClock.uptimeMillis() * 1000;
         final long rawRealtimeMs = SystemClock.elapsedRealtime();
         final long rawRealtime = rawRealtimeMs * 1000;
@@ -3848,28 +3866,13 @@
                 multicastWakeLockTimeTotalMicros / 1000,
                 multicastWakeLockCountTotal);
 
-        if (which == STATS_SINCE_UNPLUGGED) {
-            dumpLine(pw, 0 /* uid */, category, BATTERY_LEVEL_DATA, getDischargeStartLevel(),
-                    getDischargeCurrentLevel());
-        }
-
-        if (which == STATS_SINCE_UNPLUGGED) {
-            dumpLine(pw, 0 /* uid */, category, BATTERY_DISCHARGE_DATA,
-                    getDischargeStartLevel()-getDischargeCurrentLevel(),
-                    getDischargeStartLevel()-getDischargeCurrentLevel(),
-                    getDischargeAmountScreenOn(), getDischargeAmountScreenOff(),
-                    dischargeCount / 1000, dischargeScreenOffCount / 1000,
-                    getDischargeAmountScreenDoze(), dischargeScreenDozeCount / 1000,
-                    dischargeLightDozeCount / 1000, dischargeDeepDozeCount / 1000);
-        } else {
-            dumpLine(pw, 0 /* uid */, category, BATTERY_DISCHARGE_DATA,
-                    getLowDischargeAmountSinceCharge(), getHighDischargeAmountSinceCharge(),
-                    getDischargeAmountScreenOnSinceCharge(),
-                    getDischargeAmountScreenOffSinceCharge(),
-                    dischargeCount / 1000, dischargeScreenOffCount / 1000,
-                    getDischargeAmountScreenDozeSinceCharge(), dischargeScreenDozeCount / 1000,
-                    dischargeLightDozeCount / 1000, dischargeDeepDozeCount / 1000);
-        }
+        dumpLine(pw, 0 /* uid */, category, BATTERY_DISCHARGE_DATA,
+                getLowDischargeAmountSinceCharge(), getHighDischargeAmountSinceCharge(),
+                getDischargeAmountScreenOnSinceCharge(),
+                getDischargeAmountScreenOffSinceCharge(),
+                dischargeCount / 1000, dischargeScreenOffCount / 1000,
+                getDischargeAmountScreenDozeSinceCharge(), dischargeScreenDozeCount / 1000,
+                dischargeLightDozeCount / 1000, dischargeDeepDozeCount / 1000);
 
         if (reqUid < 0) {
             final Map<String, ? extends Timer> kernelWakelocks = getKernelWakelockStats();
@@ -4432,6 +4435,13 @@
     @SuppressWarnings("unused")
     public final void dumpLocked(Context context, PrintWriter pw, String prefix, final int which,
             int reqUid, boolean wifiOnly) {
+
+        if (which != BatteryStats.STATS_SINCE_CHARGED) {
+            pw.println("ERROR: BatteryStats.dump called for which type " + which
+                    + " but only STATS_SINCE_CHARGED is supported");
+            return;
+        }
+
         final long rawUptime = SystemClock.uptimeMillis() * 1000;
         final long rawRealtime = SystemClock.elapsedRealtime() * 1000;
         final long rawRealtimeMs = (rawRealtime + 500) / 1000;
@@ -5044,41 +5054,18 @@
 
         pw.println();
 
-        if (which == STATS_SINCE_UNPLUGGED) {
-            if (getIsOnBattery()) {
-                pw.print(prefix); pw.println("  Device is currently unplugged");
-                pw.print(prefix); pw.print("    Discharge cycle start level: ");
-                        pw.println(getDischargeStartLevel());
-                pw.print(prefix); pw.print("    Discharge cycle current level: ");
-                        pw.println(getDischargeCurrentLevel());
-            } else {
-                pw.print(prefix); pw.println("  Device is currently plugged into power");
-                pw.print(prefix); pw.print("    Last discharge cycle start level: ");
-                        pw.println(getDischargeStartLevel());
-                pw.print(prefix); pw.print("    Last discharge cycle end level: ");
-                        pw.println(getDischargeCurrentLevel());
-            }
-            pw.print(prefix); pw.print("    Amount discharged while screen on: ");
-            pw.println(getDischargeAmountScreenOn());
-            pw.print(prefix); pw.print("    Amount discharged while screen off: ");
-            pw.println(getDischargeAmountScreenOff());
-            pw.print(prefix); pw.print("    Amount discharged while screen doze: ");
-            pw.println(getDischargeAmountScreenDoze());
-            pw.println(" ");
-        } else {
-            pw.print(prefix); pw.println("  Device battery use since last full charge");
-            pw.print(prefix); pw.print("    Amount discharged (lower bound): ");
-            pw.println(getLowDischargeAmountSinceCharge());
-            pw.print(prefix); pw.print("    Amount discharged (upper bound): ");
-            pw.println(getHighDischargeAmountSinceCharge());
-            pw.print(prefix); pw.print("    Amount discharged while screen on: ");
-            pw.println(getDischargeAmountScreenOnSinceCharge());
-            pw.print(prefix); pw.print("    Amount discharged while screen off: ");
-            pw.println(getDischargeAmountScreenOffSinceCharge());
-            pw.print(prefix); pw.print("    Amount discharged while screen doze: ");
-            pw.println(getDischargeAmountScreenDozeSinceCharge());
-            pw.println();
-        }
+        pw.print(prefix); pw.println("  Device battery use since last full charge");
+        pw.print(prefix); pw.print("    Amount discharged (lower bound): ");
+        pw.println(getLowDischargeAmountSinceCharge());
+        pw.print(prefix); pw.print("    Amount discharged (upper bound): ");
+        pw.println(getHighDischargeAmountSinceCharge());
+        pw.print(prefix); pw.print("    Amount discharged while screen on: ");
+        pw.println(getDischargeAmountScreenOnSinceCharge());
+        pw.print(prefix); pw.print("    Amount discharged while screen off: ");
+        pw.println(getDischargeAmountScreenOffSinceCharge());
+        pw.print(prefix); pw.print("    Amount discharged while screen doze: ");
+        pw.println(getDischargeAmountScreenDozeSinceCharge());
+        pw.println();
 
         final BatteryStatsHelper helper = new BatteryStatsHelper(context, false, wifiOnly);
         helper.create(this);
diff --git a/core/java/android/os/Bundle.java b/core/java/android/os/Bundle.java
index 6432c24..b82e517 100644
--- a/core/java/android/os/Bundle.java
+++ b/core/java/android/os/Bundle.java
@@ -935,12 +935,16 @@
     }
 
     /**
-     * Returns the value associated with the given key, or null if
-     * no mapping of the desired type exists for the given key or a null
+     * Returns the value associated with the given key, or {@code null} if
+     * no mapping of the desired type exists for the given key or a {@code null}
      * value is explicitly associated with the key.
      *
-     * @param key a String, or null
-     * @return a Parcelable value, or null
+     * <p><b>Note: </b> if the expected value is not a class provided by the Android platform,
+     * you must call {@link #setClassLoader(ClassLoader)} with the proper {@link ClassLoader} first.
+     * Otherwise, this method might throw an exception or return {@code null}.
+     *
+     * @param key a String, or {@code null}
+     * @return a Parcelable value, or {@code null}
      */
     @Nullable
     public <T extends Parcelable> T getParcelable(@Nullable String key) {
@@ -958,12 +962,16 @@
     }
 
     /**
-     * Returns the value associated with the given key, or null if
+     * Returns the value associated with the given key, or {@code null} if
      * no mapping of the desired type exists for the given key or a null
      * value is explicitly associated with the key.
      *
-     * @param key a String, or null
-     * @return a Parcelable[] value, or null
+     * <p><b>Note: </b> if the expected value is not a class provided by the Android platform,
+     * you must call {@link #setClassLoader(ClassLoader)} with the proper {@link ClassLoader} first.
+     * Otherwise, this method might throw an exception or return {@code null}.
+     *
+     * @param key a String, or {@code null}
+     * @return a Parcelable[] value, or {@code null}
      */
     @Nullable
     public Parcelable[] getParcelableArray(@Nullable String key) {
@@ -981,12 +989,16 @@
     }
 
     /**
-     * Returns the value associated with the given key, or null if
-     * no mapping of the desired type exists for the given key or a null
+     * Returns the value associated with the given key, or {@code null} if
+     * no mapping of the desired type exists for the given key or a {@code null}
      * value is explicitly associated with the key.
      *
-     * @param key a String, or null
-     * @return an ArrayList<T> value, or null
+     * <p><b>Note: </b> if the expected value is not a class provided by the Android platform,
+     * you must call {@link #setClassLoader(ClassLoader)} with the proper {@link ClassLoader} first.
+     * Otherwise, this method might throw an exception or return {@code null}.
+     *
+     * @param key a String, or {@code null}
+     * @return an ArrayList<T> value, or {@code null}
      */
     @Nullable
     public <T extends Parcelable> ArrayList<T> getParcelableArrayList(@Nullable String key) {
diff --git a/core/java/android/os/GraphicsEnvironment.java b/core/java/android/os/GraphicsEnvironment.java
index 39e9138..707a404 100644
--- a/core/java/android/os/GraphicsEnvironment.java
+++ b/core/java/android/os/GraphicsEnvironment.java
@@ -82,12 +82,18 @@
     public void setup(Context context, Bundle coreSettings) {
         final PackageManager pm = context.getPackageManager();
         final String packageName = context.getPackageName();
+        Trace.traceBegin(Trace.TRACE_TAG_GRAPHICS, "setupGpuLayers");
         setupGpuLayers(context, coreSettings, pm, packageName);
+        Trace.traceEnd(Trace.TRACE_TAG_GRAPHICS);
+        Trace.traceBegin(Trace.TRACE_TAG_GRAPHICS, "setupAngle");
         setupAngle(context, coreSettings, pm, packageName);
+        Trace.traceEnd(Trace.TRACE_TAG_GRAPHICS);
+        Trace.traceBegin(Trace.TRACE_TAG_GRAPHICS, "chooseDriver");
         if (!chooseDriver(context, coreSettings, pm, packageName)) {
             setGpuStats(SYSTEM_DRIVER_NAME, SYSTEM_DRIVER_VERSION_NAME, SYSTEM_DRIVER_VERSION_CODE,
                     SystemProperties.getLong(PROPERTY_GFX_DRIVER_BUILD_TIME, 0), packageName);
         }
+        Trace.traceEnd(Trace.TRACE_TAG_GRAPHICS);
     }
 
     /**
diff --git a/core/java/android/os/INetworkManagementService.aidl b/core/java/android/os/INetworkManagementService.aidl
index f62a999..6536fc9 100644
--- a/core/java/android/os/INetworkManagementService.aidl
+++ b/core/java/android/os/INetworkManagementService.aidl
@@ -242,27 +242,6 @@
     void tetherLimitReached(ITetheringStatsProvider provider);
 
     /**
-     ** PPPD
-     **/
-
-    /**
-     * Returns the list of currently known TTY devices on the system
-     */
-    String[] listTtys();
-
-    /**
-     * Attaches a PPP server daemon to the specified TTY with the specified
-     * local/remote addresses.
-     */
-    void attachPppd(String tty, String localAddr, String remoteAddr, String dns1Addr,
-            String dns2Addr);
-
-    /**
-     * Detaches a PPP server daemon from the specified TTY.
-     */
-    void detachPppd(String tty);
-
-    /**
      ** DATA USAGE RELATED
      **/
 
diff --git a/core/java/android/os/IPowerManager.aidl b/core/java/android/os/IPowerManager.aidl
index 4233340..b5c6604 100644
--- a/core/java/android/os/IPowerManager.aidl
+++ b/core/java/android/os/IPowerManager.aidl
@@ -34,6 +34,7 @@
             String historyTag);
     void acquireWakeLockWithUid(IBinder lock, int flags, String tag, String packageName,
             int uidtoblame);
+    @UnsupportedAppUsage
     void releaseWakeLock(IBinder lock, int flags);
     void updateWakeLockUids(IBinder lock, in int[] uids);
     oneway void powerHint(int hintId, int data);
diff --git a/core/java/android/os/ServiceSpecificException.java b/core/java/android/os/ServiceSpecificException.java
index 3b0f26ae..03d5d3e 100644
--- a/core/java/android/os/ServiceSpecificException.java
+++ b/core/java/android/os/ServiceSpecificException.java
@@ -15,6 +15,7 @@
  */
 package android.os;
 
+import android.annotation.Nullable;
 import android.annotation.SystemApi;
 
 /**
@@ -34,7 +35,7 @@
 public class ServiceSpecificException extends RuntimeException {
     public final int errorCode;
 
-    public ServiceSpecificException(int errorCode, String message) {
+    public ServiceSpecificException(int errorCode, @Nullable String message) {
         super(message);
         this.errorCode = errorCode;
     }
diff --git a/core/java/android/os/SystemClock.java b/core/java/android/os/SystemClock.java
index e695a1b..64effb8 100644
--- a/core/java/android/os/SystemClock.java
+++ b/core/java/android/os/SystemClock.java
@@ -20,6 +20,8 @@
 import android.annotation.UnsupportedAppUsage;
 import android.app.IAlarmManager;
 import android.content.Context;
+import android.location.ILocationManager;
+import android.location.LocationTime;
 import android.util.Slog;
 
 import dalvik.annotation.optimization.CriticalNative;
@@ -317,4 +319,33 @@
             }
         };
     }
+
+    /**
+     * Returns a {@link Clock} that starts at January 1, 1970 00:00:00.0 UTC,
+     * synchronized using the device's location provider.
+     *
+     * @throws DateTimeException when the location provider has not had a location fix since boot.
+     */
+    public static @NonNull Clock currentGnssTimeClock() {
+        return new SimpleClock(ZoneOffset.UTC) {
+            private final ILocationManager mMgr = ILocationManager.Stub
+                    .asInterface(ServiceManager.getService(Context.LOCATION_SERVICE));
+            @Override
+            public long millis() {
+                LocationTime time;
+                try {
+                    time = mMgr.getGnssTimeMillis();
+                } catch (RemoteException e) {
+                    e.rethrowFromSystemServer();
+                    return 0;
+                }
+                if (time == null) {
+                    throw new DateTimeException("Gnss based time is not available.");
+                }
+                long currentNanos = elapsedRealtimeNanos();
+                long deltaMs = (currentNanos - time.getElapsedRealtimeNanos()) / 1000000L;
+                return time.getTime() + deltaMs;
+            }
+        };
+    }
 }
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index 790bb27..9c9829f 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -1470,6 +1470,24 @@
     }
 
     /**
+     * Check if a user is a restricted profile. Restricted profiles may have a reduced number of
+     * available apps, app restrictions, and account restrictions.
+     *
+     * @param user the user to check
+     * @return whether the user is a restricted profile.
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(android.Manifest.permission.MANAGE_USERS)
+    public boolean isRestrictedProfile(@NonNull UserHandle user) {
+        try {
+            return mService.getUserInfo(user.getIdentifier()).isRestricted();
+        } catch (RemoteException re) {
+            throw re.rethrowFromSystemServer();
+        }
+    }
+
+    /**
      * Checks if specified user can have restricted profile.
      * @hide
      */
diff --git a/core/java/android/os/health/SystemHealthManager.java b/core/java/android/os/health/SystemHealthManager.java
index 71eda19..a92e28a 100644
--- a/core/java/android/os/health/SystemHealthManager.java
+++ b/core/java/android/os/health/SystemHealthManager.java
@@ -37,11 +37,13 @@
  * by the logging itself.  It can be substantial.
  * <p>
  * <b>Battery Usage</b><br>
- * The statistics related to power (battery) usage are recorded since the device
- * was last unplugged. It is expected that applications schedule more work to do
- * while the device is plugged in (e.g. using {@link android.app.job.JobScheduler
- * JobScheduler}), and while that can affect charging rates, it is still preferable
- * to actually draining the battery.
+ * Since Android version {@link android.os.Build.VERSION_CODES#Q}, the statistics related to power
+ * (battery) usage are recorded since the device was last considered fully charged (for previous
+ * versions, it is instead since the device was last unplugged).
+ * It is expected that applications schedule more work to do while the device is
+ * plugged in (e.g. using {@link android.app.job.JobScheduler JobScheduler}), and
+ * while that can affect charging rates, it is still preferable to actually draining
+ * the battery.
  */
 @SystemService(Context.SYSTEM_HEALTH_SERVICE)
 public class SystemHealthManager {
diff --git a/core/java/android/permission/RuntimePermissionUsageInfo.java b/core/java/android/permission/RuntimePermissionUsageInfo.java
index 9f954f7..863b0ad9 100644
--- a/core/java/android/permission/RuntimePermissionUsageInfo.java
+++ b/core/java/android/permission/RuntimePermissionUsageInfo.java
@@ -35,7 +35,7 @@
  */
 @SystemApi
 public final class RuntimePermissionUsageInfo implements Parcelable {
-    private final @NonNull CharSequence mName;
+    private final @NonNull String mName;
     private final int mNumUsers;
 
     /**
@@ -44,7 +44,7 @@
      * @param name The permission group name.
      * @param numUsers The number of apps that have used this permission.
      */
-    public RuntimePermissionUsageInfo(@NonNull CharSequence name, int numUsers) {
+    public RuntimePermissionUsageInfo(@NonNull String name, int numUsers) {
         checkNotNull(name);
         checkArgumentNonnegative(numUsers);
 
@@ -53,7 +53,7 @@
     }
 
     private RuntimePermissionUsageInfo(Parcel parcel) {
-        this(parcel.readCharSequence(), parcel.readInt());
+        this(parcel.readString(), parcel.readInt());
     }
 
     /**
@@ -68,7 +68,7 @@
      *
      * @return The name.
      */
-    public @NonNull CharSequence getName() {
+    public @NonNull String getName() {
         return mName;
     }
 
@@ -79,7 +79,7 @@
 
     @Override
     public void writeToParcel(Parcel parcel, int flags) {
-        parcel.writeCharSequence(mName);
+        parcel.writeString(mName);
         parcel.writeInt(mNumUsers);
     }
 
diff --git a/core/java/android/preference/PreferenceGroupAdapter.java b/core/java/android/preference/PreferenceGroupAdapter.java
index fb41ea8..dcc5d4c 100644
--- a/core/java/android/preference/PreferenceGroupAdapter.java
+++ b/core/java/android/preference/PreferenceGroupAdapter.java
@@ -16,6 +16,7 @@
 
 package android.preference;
 
+import android.annotation.UnsupportedAppUsage;
 import android.graphics.drawable.Drawable;
 import android.os.Handler;
 import android.preference.Preference.OnPreferenceChangeInternalListener;
@@ -215,6 +216,7 @@
         return mPreferenceList.size();
     }
 
+    @UnsupportedAppUsage
     public Preference getItem(int position) {
         if (position < 0 || position >= getCount()) return null;
         return mPreferenceList.get(position);
diff --git a/core/java/android/provider/DeviceConfig.java b/core/java/android/provider/DeviceConfig.java
index 6d32f8c..4322a59 100644
--- a/core/java/android/provider/DeviceConfig.java
+++ b/core/java/android/provider/DeviceConfig.java
@@ -78,6 +78,15 @@
             "activity_manager_native_boot";
 
     /**
+     * Namespace for all app compat related features.  These features will be applied
+     * immediately upon change.
+     *
+     * @hide
+     */
+    @SystemApi
+    public static final String NAMESPACE_APP_COMPAT = "app_compat";
+
+    /**
      * Namespace for AttentionManagerService related features.
      *
      * @hide
@@ -163,6 +172,22 @@
     public static final String NAMESPACE_NETD_NATIVE = "netd_native";
 
     /**
+     * Namespace for Rollback flags that are applied immediately.
+     *
+     * @hide
+     */
+    @SystemApi @TestApi
+    public static final String NAMESPACE_ROLLBACK = "rollback";
+
+    /**
+     * Namespace for Rollback flags that are applied after a reboot.
+     *
+     * @hide
+     */
+    @SystemApi @TestApi
+    public static final String NAMESPACE_ROLLBACK_BOOT = "rollback_boot";
+
+    /**
      * Namespace for all runtime related features that don't require a reboot to become active.
      * There are no feature flags using NAMESPACE_RUNTIME.
      *
@@ -191,6 +216,23 @@
     public static final String NAMESPACE_RUNTIME_NATIVE_BOOT = "runtime_native_boot";
 
     /**
+     * Namespace for system scheduler related features. These features will be applied
+     * immediately upon change.
+     *
+     * @hide
+     */
+    @SystemApi
+    public static final String NAMESPACE_SCHEDULER = "scheduler";
+
+    /**
+     * Namespace for storage-related features.
+     *
+     * @hide
+     */
+    @SystemApi
+    public static final String NAMESPACE_STORAGE = "storage";
+
+    /**
      * Namespace for System UI related features.
      *
      * @hide
@@ -199,6 +241,14 @@
     public static final String NAMESPACE_SYSTEMUI = "systemui";
 
     /**
+     * Telephony related properties.
+     *
+     * @hide
+     */
+    @SystemApi
+    public static final String NAMESPACE_TELEPHONY = "telephony";
+
+    /**
      * Namespace for TextClassifier related features.
      *
      * @hide
@@ -243,7 +293,6 @@
      *
      * @hide
      */
-    @SystemApi
     public interface Telephony {
         String NAMESPACE = "telephony";
         /**
@@ -260,86 +309,6 @@
         String RAMPING_RINGER_VIBRATION_DURATION = "ramping_ringer_vibration_duration";
     }
 
-    /**
-     * Namespace for Rollback.
-     *
-     * @hide
-     */
-    @SystemApi @TestApi
-    public interface Rollback {
-
-        /**
-         * Namespace for flags that can be changed immediately after becoming available on device.
-         */
-        String NAMESPACE = "rollback";
-
-        /**
-         * Namespace for flags that can be changed only after reboot.
-         */
-        String BOOT_NAMESPACE = "rollback_boot";
-
-        /**
-         * Timeout duration in milliseconds for enabling package rollback. If we fail to enable
-         * rollback within that period, the install will proceed without rollback enabled.
-         *
-         * <p>If flag value is negative, the default value will be assigned.
-         *
-         * Flag type: {@code long}
-         * Namespace: Rollback.NAMESPACE
-         */
-        String ENABLE_ROLLBACK_TIMEOUT = "enable_rollback_timeout";
-
-        /**
-         * Lifetime duration of rollback packages in millis. A rollback will be available for
-         * at most that duration of time after a package is installed with
-         * {@link PackageInstaller.SessionParams#setEnableRollback()}.
-         *
-         * <p>If flag value is negative, the default value will be assigned.
-         *
-         * @see RollbackManager
-         *
-         * Flag type: {@code long}
-         * Namespace: Rollback.BOOT_NAMESPACE
-         */
-        String ROLLBACK_LIFETIME_IN_MILLIS = "rollback_lifetime_in_millis";
-    }
-
-    /**
-     * Namespace for storage-related features.
-     *
-     * @hide
-     */
-    @SystemApi
-    public interface Storage {
-        String NAMESPACE = "storage";
-
-        /**
-         * If {@code 1}, enables the isolated storage feature. If {@code -1},
-         * disables the isolated storage feature. If {@code 0}, uses the default
-         * value from the build system.
-         */
-        String ISOLATED_STORAGE_ENABLED = "isolated_storage_enabled";
-    }
-
-    /**
-     * Namespace for system scheduler related features. These features will be applied
-     * immediately upon change.
-     *
-     * @hide
-     */
-    @SystemApi
-    public interface Scheduler {
-        String NAMESPACE = "scheduler";
-
-        /**
-         * Flag for enabling fast metrics collection in system scheduler.
-         * A flag value of '' or '0' means the fast metrics collection is not
-         * enabled. Otherwise fast metrics collection is enabled and flag value
-         * is the order id.
-         */
-        String ENABLE_FAST_METRICS_COLLECTION = "enable_fast_metrics_collection";
-    }
-
     private static final Object sLock = new Object();
     @GuardedBy("sLock")
     private static ArrayMap<OnPropertyChangedListener, Pair<String, Executor>> sSingleListeners =
diff --git a/core/java/android/provider/FontsContract.java b/core/java/android/provider/FontsContract.java
index e931826..8f772d4 100644
--- a/core/java/android/provider/FontsContract.java
+++ b/core/java/android/provider/FontsContract.java
@@ -34,7 +34,6 @@
 import android.graphics.fonts.FontStyle;
 import android.graphics.fonts.FontVariationAxis;
 import android.net.Uri;
-import android.os.Build.VERSION_CODES;
 import android.os.CancellationSignal;
 import android.os.Handler;
 import android.os.HandlerThread;
@@ -652,17 +651,12 @@
                 if (familyBuilder == null) {
                     familyBuilder = new FontFamily.Builder(font);
                 } else {
-                    try {
-                        familyBuilder.addFont(font);
-                    } catch (IllegalArgumentException e) {
-                        if (context.getApplicationInfo().targetSdkVersion <= VERSION_CODES.P) {
-                            // Surpress the IllegalArgumentException for keeping the backward
-                            // compatibility.
-                            continue;
-                        }
-                        throw e;
-                    }
+                    familyBuilder.addFont(font);
                 }
+            } catch (IllegalArgumentException e) {
+                // To be a compatible behavior with API28 or before, catch IllegalArgumentExcetpion
+                // thrown by native code and returns null.
+                return null;
             } catch (IOException e) {
                 continue;
             }
diff --git a/core/java/android/provider/SearchIndexablesProvider.java b/core/java/android/provider/SearchIndexablesProvider.java
index 1549c45..d505f02 100644
--- a/core/java/android/provider/SearchIndexablesProvider.java
+++ b/core/java/android/provider/SearchIndexablesProvider.java
@@ -25,6 +25,7 @@
 import android.content.pm.ProviderInfo;
 import android.database.Cursor;
 import android.net.Uri;
+import android.util.Log;
 
 /**
  * Base class for a search indexable provider. Such provider offers data to be indexed either
@@ -112,19 +113,26 @@
     @Override
     public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
                         String sortOrder) {
-        switch (mMatcher.match(uri)) {
-            case MATCH_RES_CODE:
-                return queryXmlResources(null);
-            case MATCH_RAW_CODE:
-                return queryRawData(null);
-            case MATCH_NON_INDEXABLE_KEYS_CODE:
-                return queryNonIndexableKeys(null);
-            case MATCH_SITE_MAP_PAIRS_CODE:
-                return querySiteMapPairs();
-            case MATCH_SLICE_URI_PAIRS_CODE:
-                return querySliceUriPairs();
-            default:
-                throw new UnsupportedOperationException("Unknown Uri " + uri);
+        try {
+            switch (mMatcher.match(uri)) {
+                case MATCH_RES_CODE:
+                    return queryXmlResources(null);
+                case MATCH_RAW_CODE:
+                    return queryRawData(null);
+                case MATCH_NON_INDEXABLE_KEYS_CODE:
+                    return queryNonIndexableKeys(null);
+                case MATCH_SITE_MAP_PAIRS_CODE:
+                    return querySiteMapPairs();
+                case MATCH_SLICE_URI_PAIRS_CODE:
+                    return querySliceUriPairs();
+                default:
+                    throw new UnsupportedOperationException("Unknown Uri " + uri);
+            }
+        } catch (UnsupportedOperationException e) {
+            throw e;
+        } catch (Exception e) {
+            Log.e(TAG, "Provider querying exception:", e);
+            return null;
         }
     }
 
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index df5da6c..7d66b90 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -1696,6 +1696,19 @@
     public static final String ACTION_REQUEST_ENABLE_CONTENT_CAPTURE =
             "android.settings.REQUEST_ENABLE_CONTENT_CAPTURE";
 
+    /**
+     * Activity Action: Show screen that let user manage how Android handles URL resolution.
+     * <p>
+     * Input: Nothing.
+     * <p>
+     * Output: Nothing
+     *
+     * @hide
+     */
+    @SystemApi
+    @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+    public static final String ACTION_MANAGE_DOMAIN_URLS = "android.settings.MANAGE_DOMAIN_URLS";
+
     // End of Intent actions for Settings
 
     /**
@@ -5594,11 +5607,23 @@
          *
          * @hide
          */
+        @SystemApi
         public static final String ODI_CAPTIONS_ENABLED = "odi_captions_enabled";
 
         private static final Validator ODI_CAPTIONS_ENABLED_VALIDATOR = BOOLEAN_VALIDATOR;
 
         /**
+         * Setting to indicate that on device captions cannot be shown because the app
+         * which is currently playing media had opted out.
+         *
+         * @hide
+         */
+        @SystemApi
+        public static final String ODI_CAPTIONS_OPTED_OUT = "odi_captions_opted_out";
+
+        private static final Validator ODI_CAPTIONS_OPTED_OUT_VALIDATOR = BOOLEAN_VALIDATOR;
+
+        /**
          * On Android 8.0 (API level 26) and higher versions of the platform,
          * a 64-bit number (expressed as a hexadecimal string), unique to
          * each combination of app-signing key, user, and device.
@@ -8562,38 +8587,6 @@
                 "packages_to_clear_data_before_full_restore";
 
         /**
-         * Indicates the location state should be maintained after sensor privacy is disabled.
-         * @hide
-         */
-        public static final String MAINTAIN_LOCATION_AFTER_SP_DISABLED = "0";
-
-        /**
-         * Indicates location should be reenabled after sensor privacy is disabled.
-         * @hide
-         */
-        public static final String REENABLE_LOCATION_AFTER_SP_DISABLED = "1";
-
-        /**
-         * Indicates the state of airplane mode should be maintained after sensor privacy is
-         * disabled.
-         * @hide
-         */
-        public static final String MAINTAIN_AIRPLANE_MODE_AFTER_SP_DISABLED = "0";
-
-        /**
-         * Indicates airplane mode should be disabled after sensor privacy is disabled.
-         * @hide
-         */
-        public static final String DISABLE_AIRPLANE_MODE_AFTER_SP_DISABLED = "1";
-
-        /**
-         * The state of all sensors managed by SensorPrivacyService when sensor privacy is enabled.
-         * @hide
-         */
-        public static final String SENSOR_PRIVACY_SENSOR_STATE =
-                "sensor_privacy_sensor_state";
-
-        /**
          * Setting to determine whether to use the new notification priority handling features.
          * @hide
          */
@@ -8965,6 +8958,7 @@
             VALIDATORS.put(SILENCE_CALL_GESTURE_COUNT, SILENCE_GESTURE_COUNT_VALIDATOR);
             VALIDATORS.put(SILENCE_NOTIFICATION_GESTURE_COUNT, SILENCE_GESTURE_COUNT_VALIDATOR);
             VALIDATORS.put(ODI_CAPTIONS_ENABLED, ODI_CAPTIONS_ENABLED_VALIDATOR);
+            VALIDATORS.put(ODI_CAPTIONS_OPTED_OUT, ODI_CAPTIONS_OPTED_OUT_VALIDATOR);
         }
 
         /**
@@ -9053,7 +9047,6 @@
          * @return true if the provider is enabled
          *
          * @deprecated use {@link LocationManager#isProviderEnabled(String)}
-         * @removed no longer supported
          */
         @Deprecated
         public static boolean isLocationProviderEnabled(ContentResolver cr, String provider) {
@@ -9063,12 +9056,12 @@
         }
 
         /**
-         * Thread-safe method for enabling or disabling a single location provider.
+         * Thread-safe method for enabling or disabling a single location provider. This will have
+         * no effect on Android Q and above.
          * @param cr the content resolver to use
          * @param provider the location provider to enable or disable
          * @param enabled true if the provider should be enabled
          * @deprecated This API is deprecated
-         * @removed no longer supported
          */
         @Deprecated
         public static void setLocationProviderEnabled(ContentResolver cr,
@@ -12586,8 +12579,9 @@
 
         /**
          * Battery level [1-100] at which low power mode automatically turns on.
-         * Pre-Q If 0, it will not automatically turn on. Q and newer it will only automatically
-         * turn on if the {@link #AUTOMATIC_POWER_SAVER_MODE} setting is also set to
+         * If 0, it will not automatically turn on. For Q and newer, it will only automatically
+         * turn on if the value is greater than 0 and the {@link #AUTOMATIC_POWER_SAVER_MODE}
+         * setting is also set to
          * {@link android.os.PowerManager.AutoPowerSaverMode#POWER_SAVER_MODE_PERCENTAGE}.
          *
          * @see #AUTOMATIC_POWER_SAVER_MODE
diff --git a/core/java/android/security/keymaster/KeymasterBlobArgument.java b/core/java/android/security/keymaster/KeymasterBlobArgument.java
index 541d33e..fc562bd 100644
--- a/core/java/android/security/keymaster/KeymasterBlobArgument.java
+++ b/core/java/android/security/keymaster/KeymasterBlobArgument.java
@@ -16,14 +16,17 @@
 
 package android.security.keymaster;
 
+import android.annotation.UnsupportedAppUsage;
 import android.os.Parcel;
 
 /**
  * @hide
  */
 class KeymasterBlobArgument extends KeymasterArgument {
+    @UnsupportedAppUsage
     public final byte[] blob;
 
+    @UnsupportedAppUsage
     public KeymasterBlobArgument(int tag, byte[] blob) {
         super(tag);
         switch (KeymasterDefs.getTagType(tag)) {
@@ -36,6 +39,7 @@
         this.blob = blob;
     }
 
+    @UnsupportedAppUsage
     public KeymasterBlobArgument(int tag, Parcel in) {
         super(tag);
         blob = in.createByteArray();
diff --git a/core/java/android/security/keymaster/KeymasterBooleanArgument.java b/core/java/android/security/keymaster/KeymasterBooleanArgument.java
index 67b3281..4286aa0 100644
--- a/core/java/android/security/keymaster/KeymasterBooleanArgument.java
+++ b/core/java/android/security/keymaster/KeymasterBooleanArgument.java
@@ -16,6 +16,7 @@
 
 package android.security.keymaster;
 
+import android.annotation.UnsupportedAppUsage;
 import android.os.Parcel;
 
 /**
@@ -36,6 +37,7 @@
         }
     }
 
+    @UnsupportedAppUsage
     public KeymasterBooleanArgument(int tag, Parcel in) {
         super(tag);
     }
diff --git a/core/java/android/security/keymaster/KeymasterDateArgument.java b/core/java/android/security/keymaster/KeymasterDateArgument.java
index aa15e34..3e04c15 100644
--- a/core/java/android/security/keymaster/KeymasterDateArgument.java
+++ b/core/java/android/security/keymaster/KeymasterDateArgument.java
@@ -16,6 +16,7 @@
 
 package android.security.keymaster;
 
+import android.annotation.UnsupportedAppUsage;
 import android.os.Parcel;
 import java.util.Date;
 
@@ -36,6 +37,7 @@
         this.date = date;
     }
 
+    @UnsupportedAppUsage
     public KeymasterDateArgument(int tag, Parcel in) {
         super(tag);
         date = new Date(in.readLong());
diff --git a/core/java/android/security/keymaster/KeymasterIntArgument.java b/core/java/android/security/keymaster/KeymasterIntArgument.java
index 578d249..4aadce4 100644
--- a/core/java/android/security/keymaster/KeymasterIntArgument.java
+++ b/core/java/android/security/keymaster/KeymasterIntArgument.java
@@ -16,14 +16,17 @@
 
 package android.security.keymaster;
 
+import android.annotation.UnsupportedAppUsage;
 import android.os.Parcel;
 
 /**
  * @hide
  */
 class KeymasterIntArgument extends KeymasterArgument {
+    @UnsupportedAppUsage
     public final int value;
 
+    @UnsupportedAppUsage
     public KeymasterIntArgument(int tag, int value) {
         super(tag);
         switch (KeymasterDefs.getTagType(tag)) {
@@ -38,6 +41,7 @@
         this.value = value;
     }
 
+    @UnsupportedAppUsage
     public KeymasterIntArgument(int tag, Parcel in) {
         super(tag);
         value = in.readInt();
diff --git a/core/java/android/security/keymaster/KeymasterLongArgument.java b/core/java/android/security/keymaster/KeymasterLongArgument.java
index d3d40ba..bc2255e 100644
--- a/core/java/android/security/keymaster/KeymasterLongArgument.java
+++ b/core/java/android/security/keymaster/KeymasterLongArgument.java
@@ -16,14 +16,17 @@
 
 package android.security.keymaster;
 
+import android.annotation.UnsupportedAppUsage;
 import android.os.Parcel;
 
 /**
  * @hide
  */
 class KeymasterLongArgument extends KeymasterArgument {
+    @UnsupportedAppUsage
     public final long value;
 
+    @UnsupportedAppUsage
     public KeymasterLongArgument(int tag, long value) {
         super(tag);
         switch (KeymasterDefs.getTagType(tag)) {
@@ -36,6 +39,7 @@
         this.value = value;
     }
 
+    @UnsupportedAppUsage
     public KeymasterLongArgument(int tag, Parcel in) {
         super(tag);
         value = in.readLong();
diff --git a/core/java/android/service/autofill/augmented/AugmentedAutofillService.java b/core/java/android/service/autofill/augmented/AugmentedAutofillService.java
index 19e216a..96b861b 100644
--- a/core/java/android/service/autofill/augmented/AugmentedAutofillService.java
+++ b/core/java/android/service/autofill/augmented/AugmentedAutofillService.java
@@ -30,6 +30,7 @@
 import android.os.CancellationSignal;
 import android.os.Handler;
 import android.os.IBinder;
+import android.os.ICancellationSignal;
 import android.os.Looper;
 import android.os.RemoteException;
 import android.os.SystemClock;
@@ -201,18 +202,26 @@
         if (mAutofillProxies == null) {
             mAutofillProxies = new SparseArray<>();
         }
+
+        final ICancellationSignal transport = CancellationSignal.createTransport();
+        final CancellationSignal cancellationSignal = CancellationSignal.fromTransport(transport);
         AutofillProxy proxy = mAutofillProxies.get(sessionId);
         if (proxy == null) {
             proxy = new AutofillProxy(sessionId, client, taskId, componentName, focusedId,
-                    focusedValue, requestTime, callback);
+                    focusedValue, requestTime, callback, cancellationSignal);
             mAutofillProxies.put(sessionId,  proxy);
         } else {
             // TODO(b/123099468): figure out if it's ok to reuse the proxy; add logging
             if (DEBUG) Log.d(TAG, "Reusing proxy for session " + sessionId);
             proxy.update(focusedId, focusedValue, callback);
         }
-        // TODO(b/123101711): set cancellation signal
-        final CancellationSignal cancellationSignal = null;
+
+        try {
+            callback.onCancellable(transport);
+        } catch (RemoteException e) {
+            e.rethrowFromSystemServer();
+        }
+
         onFillRequest(new FillRequest(proxy), cancellationSignal, new FillController(proxy),
                 new FillCallback(proxy));
     }
@@ -329,18 +338,21 @@
         @GuardedBy("mLock")
         private FillWindow mFillWindow;
 
+        private CancellationSignal mCancellationSignal;
+
         private AutofillProxy(int sessionId, @NonNull IBinder client, int taskId,
                 @NonNull ComponentName componentName, @NonNull AutofillId focusedId,
                 @Nullable AutofillValue focusedValue, long requestTime,
-                @NonNull IFillCallback callback) {
+                @NonNull IFillCallback callback, @NonNull CancellationSignal cancellationSignal) {
             mSessionId = sessionId;
             mClient = IAugmentedAutofillManagerClient.Stub.asInterface(client);
             mCallback = callback;
             this.taskId = taskId;
             this.componentName = componentName;
-            this.mFocusedId = focusedId;
-            this.mFocusedValue = focusedValue;
-            this.mFirstRequestTime = requestTime;
+            mFocusedId = focusedId;
+            mFocusedValue = focusedValue;
+            mFirstRequestTime = requestTime;
+            mCancellationSignal = cancellationSignal;
             // TODO(b/123099468): linkToDeath
         }
 
@@ -394,6 +406,12 @@
 
         public void requestShowFillUi(int width, int height, Rect anchorBounds,
                 IAutofillWindowPresenter presenter) throws RemoteException {
+            if (mCancellationSignal.isCanceled()) {
+                if (VERBOSE) {
+                    Log.v(TAG, "requestShowFillUi() not showing because request is cancelled");
+                }
+                return;
+            }
             mClient.requestShowFillUi(mSessionId, mFocusedId, width, height, anchorBounds,
                     presenter);
         }
@@ -408,8 +426,13 @@
                 mFocusedId = focusedId;
                 mFocusedValue = focusedValue;
                 if (mCallback != null) {
-                    // TODO(b/123101711): we need to check whether the previous request was
-                    //  completed or not, and if not, cancel it first.
+                    try {
+                        if (!mCallback.isCompleted()) {
+                            mCallback.cancel();
+                        }
+                    } catch (RemoteException e) {
+                        Slog.e(TAG, "failed to check current pending request status", e);
+                    }
                     Slog.d(TAG, "mCallback is updated.");
                 }
                 mCallback = callback;
diff --git a/core/java/android/service/autofill/augmented/IFillCallback.aidl b/core/java/android/service/autofill/augmented/IFillCallback.aidl
index 2b072664..88baa87 100644
--- a/core/java/android/service/autofill/augmented/IFillCallback.aidl
+++ b/core/java/android/service/autofill/augmented/IFillCallback.aidl
@@ -24,7 +24,8 @@
  * @hide
  */
 interface IFillCallback {
-    // TODO(b/123101711): add cancellation (after we have CTS tests, so we can test it)
-//    void onCancellable(in ICancellationSignal cancellation);
+    void onCancellable(in ICancellationSignal cancellation);
     void onSuccess();
+    boolean isCompleted();
+    void cancel();
 }
diff --git a/core/java/android/service/contentcapture/ActivityEvent.java b/core/java/android/service/contentcapture/ActivityEvent.java
index 5407c1d..fc781c2 100644
--- a/core/java/android/service/contentcapture/ActivityEvent.java
+++ b/core/java/android/service/contentcapture/ActivityEvent.java
@@ -52,11 +52,17 @@
      */
     public static final int TYPE_ACTIVITY_STOPPED = Event.ACTIVITY_STOPPED;
 
+    /**
+     * The activity was destroyed.
+     */
+    public static final int TYPE_ACTIVITY_DESTROYED = Event.ACTIVITY_DESTROYED;
+
     /** @hide */
     @IntDef(prefix = { "TYPE_" }, value = {
             TYPE_ACTIVITY_RESUMED,
             TYPE_ACTIVITY_PAUSED,
-            TYPE_ACTIVITY_STOPPED
+            TYPE_ACTIVITY_STOPPED,
+            TYPE_ACTIVITY_DESTROYED
     })
     @Retention(RetentionPolicy.SOURCE)
     public @interface ActivityEventType{}
@@ -81,7 +87,8 @@
     /**
      * Gets the event type.
      *
-     * @return either {@link #TYPE_ACTIVITY_RESUMED} or {@value #TYPE_ACTIVITY_PAUSED}.
+     * @return either {@link #TYPE_ACTIVITY_RESUMED}, {@value #TYPE_ACTIVITY_PAUSED},
+     * {@value #TYPE_ACTIVITY_STOPPED}, or {@value #TYPE_ACTIVITY_DESTROYED}.
      */
     @ActivityEventType
     public int getEventType() {
@@ -97,6 +104,8 @@
                 return "ACTIVITY_PAUSED";
             case TYPE_ACTIVITY_STOPPED:
                 return "ACTIVITY_STOPPED";
+            case TYPE_ACTIVITY_DESTROYED:
+                return "ACTIVITY_DESTROYED";
             default:
                 return "UKNOWN_TYPE: " + type;
         }
diff --git a/core/java/android/service/contentcapture/ContentCaptureService.java b/core/java/android/service/contentcapture/ContentCaptureService.java
index 6f4114d..df11397 100644
--- a/core/java/android/service/contentcapture/ContentCaptureService.java
+++ b/core/java/android/service/contentcapture/ContentCaptureService.java
@@ -78,6 +78,21 @@
     public static final String SERVICE_INTERFACE =
             "android.service.contentcapture.ContentCaptureService";
 
+    /**
+     * Name under which a ContentCaptureService component publishes information about itself.
+     *
+     * <p>This meta-data should reference an XML resource containing a
+     * <code>&lt;{@link
+     * android.R.styleable#ContentCaptureService content-capture-service}&gt;</code> tag.
+     *
+     * <p>This is a a sample XML file configuring a ContentCaptureService:
+     * <pre> &lt;content-capture-service
+     *     android:settingsActivity="foo.bar.SettingsActivity"
+     *     . . .
+     * /&gt;</pre>
+     */
+    public static final String SERVICE_META_DATA = "android.content_capture";
+
     private Handler mHandler;
     private IContentCaptureServiceCallback mCallback;
 
diff --git a/core/java/android/service/contentcapture/ContentCaptureServiceInfo.java b/core/java/android/service/contentcapture/ContentCaptureServiceInfo.java
new file mode 100644
index 0000000..6ecd82f
--- /dev/null
+++ b/core/java/android/service/contentcapture/ContentCaptureServiceInfo.java
@@ -0,0 +1,171 @@
+/*
+ * 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 android.service.contentcapture;
+
+import android.Manifest;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.UserIdInt;
+import android.app.AppGlobals;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.pm.ServiceInfo;
+import android.content.res.Resources;
+import android.content.res.TypedArray;
+import android.content.res.XmlResourceParser;
+import android.os.RemoteException;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.util.Slog;
+import android.util.Xml;
+
+import com.android.internal.R;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.IOException;
+import java.io.PrintWriter;
+
+/**
+ * {@link ServiceInfo} and meta-data about an {@link ContentCaptureService}.
+ *
+ * @hide
+ */
+public final class ContentCaptureServiceInfo {
+
+    private static final String TAG = ContentCaptureServiceInfo.class.getSimpleName();
+    private static final String XML_TAG_SERVICE = "content-capture-service";
+
+    private static ServiceInfo getServiceInfoOrThrow(ComponentName comp, boolean isTemp,
+            @UserIdInt int userId) throws PackageManager.NameNotFoundException {
+        int flags = PackageManager.GET_META_DATA;
+        if (!isTemp) {
+            flags |= PackageManager.MATCH_SYSTEM_ONLY;
+        }
+
+        ServiceInfo si = null;
+        try {
+            si = AppGlobals.getPackageManager().getServiceInfo(comp, flags, userId);
+        } catch (RemoteException e) {
+        }
+        if (si == null) {
+            throw new NameNotFoundException("Could not get serviceInfo for "
+                    + (isTemp ? " (temp)" : "(default system)")
+                    + " " + comp.flattenToShortString());
+        }
+        return si;
+    }
+
+    @NonNull
+    private final ServiceInfo mServiceInfo;
+
+    @Nullable
+    private final String mSettingsActivity;
+
+    public ContentCaptureServiceInfo(@NonNull Context context, @NonNull ComponentName comp,
+            boolean isTemporaryService, @UserIdInt int userId)
+            throws PackageManager.NameNotFoundException {
+        this(context, getServiceInfoOrThrow(comp, isTemporaryService, userId));
+    }
+
+    private ContentCaptureServiceInfo(@NonNull Context context, @NonNull ServiceInfo si) {
+        // Check for permissions.
+        if (!Manifest.permission.BIND_CONTENT_CAPTURE_SERVICE.equals(si.permission)) {
+            Slog.w(TAG, "ContentCaptureService from '" + si.packageName
+                    + "' does not require permission "
+                    + Manifest.permission.BIND_CONTENT_CAPTURE_SERVICE);
+            throw new SecurityException("Service does not require permission "
+                    + Manifest.permission.BIND_CONTENT_CAPTURE_SERVICE);
+        }
+
+        mServiceInfo = si;
+
+        // Get the metadata, if declared.
+        final XmlResourceParser parser = si.loadXmlMetaData(context.getPackageManager(),
+                ContentCaptureService.SERVICE_META_DATA);
+        if (parser == null) {
+            mSettingsActivity = null;
+            return;
+        }
+
+        String settingsActivity = null;
+
+        try {
+            final Resources resources = context.getPackageManager().getResourcesForApplication(
+                    si.applicationInfo);
+
+            int type = 0;
+            while (type != XmlPullParser.END_DOCUMENT && type != XmlPullParser.START_TAG) {
+                type = parser.next();
+            }
+
+            if (XML_TAG_SERVICE.equals(parser.getName())) {
+                final AttributeSet allAttributes = Xml.asAttributeSet(parser);
+                TypedArray afsAttributes = null;
+                try {
+                    afsAttributes = resources.obtainAttributes(allAttributes,
+                            com.android.internal.R.styleable.ContentCaptureService);
+                    settingsActivity = afsAttributes.getString(
+                            R.styleable.ContentCaptureService_settingsActivity);
+                } finally {
+                    if (afsAttributes != null) {
+                        afsAttributes.recycle();
+                    }
+                }
+            } else {
+                Log.e(TAG, "Meta-data does not start with content-capture-service tag");
+            }
+        } catch (PackageManager.NameNotFoundException | IOException | XmlPullParserException e) {
+            Log.e(TAG, "Error parsing auto fill service meta-data", e);
+        }
+
+        mSettingsActivity = settingsActivity;
+    }
+
+    public ServiceInfo getServiceInfo() {
+        return mServiceInfo;
+    }
+
+    @Nullable
+    public String getSettingsActivity() {
+        return mSettingsActivity;
+    }
+
+    @Override
+    public String toString() {
+        final StringBuilder builder = new StringBuilder();
+        builder.append(getClass().getSimpleName());
+        builder.append("[").append(mServiceInfo);
+        builder.append(", settings:").append(mSettingsActivity);
+        return builder.toString();
+    }
+
+    /**
+     * Dumps it!
+     */
+    public void dump(@NonNull String prefix, @NonNull PrintWriter pw) {
+        pw.print(prefix);
+        pw.print("Component: ");
+        pw.println(getServiceInfo().getComponentName());
+        pw.print(prefix);
+        pw.print("Settings: ");
+        pw.println(mSettingsActivity);
+    }
+}
diff --git a/core/java/android/service/dreams/IDreamManager.aidl b/core/java/android/service/dreams/IDreamManager.aidl
index b84e6c9..d3f2a70 100644
--- a/core/java/android/service/dreams/IDreamManager.aidl
+++ b/core/java/android/service/dreams/IDreamManager.aidl
@@ -23,12 +23,16 @@
 
 /** @hide */
 interface IDreamManager {
+    @UnsupportedAppUsage
     void dream();
+    @UnsupportedAppUsage
     void awaken();
+    @UnsupportedAppUsage
     void setDreamComponents(in ComponentName[] componentNames);
     ComponentName[] getDreamComponents();
     ComponentName getDefaultDreamComponent();
     void testDream(in ComponentName componentName);
+    @UnsupportedAppUsage
     boolean isDreaming();
     void finishSelf(in IBinder token, boolean immediate);
     void startDozing(in IBinder token, int screenState, int screenBrightness);
diff --git a/core/java/android/service/euicc/GetEuiccProfileInfoListResult.java b/core/java/android/service/euicc/GetEuiccProfileInfoListResult.java
index 7a9d8a0..9add38e 100644
--- a/core/java/android/service/euicc/GetEuiccProfileInfoListResult.java
+++ b/core/java/android/service/euicc/GetEuiccProfileInfoListResult.java
@@ -97,9 +97,10 @@
         if (this.result == EuiccService.RESULT_OK) {
             this.mProfiles = profiles;
         } else {
-            if (profiles != null) {
+            // For error case, profiles is either null or 0 size.
+            if (profiles != null && profiles.length > 0) {
                 throw new IllegalArgumentException(
-                        "Error result with non-null profiles: " + result);
+                        "Error result with non-empty profiles: " + result);
             }
             this.mProfiles = null;
         }
diff --git a/core/java/android/service/notification/Adjustment.java b/core/java/android/service/notification/Adjustment.java
index 1cdb62f..8ba9a83 100644
--- a/core/java/android/service/notification/Adjustment.java
+++ b/core/java/android/service/notification/Adjustment.java
@@ -16,6 +16,7 @@
 package android.service.notification;
 
 import android.annotation.NonNull;
+import android.annotation.StringDef;
 import android.annotation.SystemApi;
 import android.app.Notification;
 import android.os.Bundle;
@@ -23,6 +24,9 @@
 import android.os.Parcelable;
 import android.os.UserHandle;
 
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
 /**
  * Ranking updates from the Assistant.
  *
@@ -43,6 +47,14 @@
     private final Bundle mSignals;
     private final int mUser;
 
+    /** @hide */
+    @StringDef (prefix = { "KEY_" }, value = {
+            KEY_CONTEXTUAL_ACTIONS, KEY_GROUP_KEY, KEY_IMPORTANCE, KEY_PEOPLE, KEY_SNOOZE_CRITERIA,
+            KEY_TEXT_REPLIES, KEY_USER_SENTIMENT
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface Keys {}
+
     /**
      * Data type: ArrayList of {@code String}, where each is a representation of a
      * {@link android.provider.ContactsContract.Contacts#CONTENT_LOOKUP_URI}.
diff --git a/core/java/android/service/notification/NotificationAssistantService.java b/core/java/android/service/notification/NotificationAssistantService.java
index 780b576..a1932b8 100644
--- a/core/java/android/service/notification/NotificationAssistantService.java
+++ b/core/java/android/service/notification/NotificationAssistantService.java
@@ -25,6 +25,7 @@
 import android.annotation.SystemApi;
 import android.app.Notification;
 import android.app.NotificationChannel;
+import android.app.NotificationManager;
 import android.app.admin.DevicePolicyManager;
 import android.content.ComponentName;
 import android.content.Context;
@@ -141,7 +142,6 @@
         return onNotificationEnqueued(sbn);
     }
 
-
     /**
      * Implement this method to learn when notifications are removed, how they were interacted with
      * before removal, and why they were removed.
@@ -216,6 +216,15 @@
     }
 
     /**
+     * Implement this to know when a user has changed which features of
+     * their notifications the assistant can modify.
+     * <p> Query {@link NotificationManager#getAllowedAssistantCapabilities()} to see what
+     * {@link Adjustment adjustments} you are currently allowed to make.</p>
+     */
+    public void onCapabilitiesChanged() {
+    }
+
+    /**
      * Updates a notification.  N.B. this won’t cause
      * an existing notification to alert, but might allow a future update to
      * this notification to alert.
diff --git a/core/java/android/service/notification/StatusBarNotification.java b/core/java/android/service/notification/StatusBarNotification.java
index cc74e1a..8512a0b 100644
--- a/core/java/android/service/notification/StatusBarNotification.java
+++ b/core/java/android/service/notification/StatusBarNotification.java
@@ -292,9 +292,9 @@
         return uid;
     }
 
-    /** The package that posted the notification.
-     *<p>
-     * Might be different from {@link #getPackageName()} if the app owning the notification has
+    /**
+     * The package that posted the notification.
+     * <p> Might be different from {@link #getPackageName()} if the app owning the notification has
      * a {@link NotificationManager#setNotificationDelegate(String) notification delegate}.
      */
     public @NonNull String getOpPkg() {
diff --git a/core/java/android/speech/tts/TextToSpeech.java b/core/java/android/speech/tts/TextToSpeech.java
index 83f14d1..100774c 100644
--- a/core/java/android/speech/tts/TextToSpeech.java
+++ b/core/java/android/speech/tts/TextToSpeech.java
@@ -536,7 +536,7 @@
          * or playing back a file. The value should be one of the STREAM_ constants
          * defined in {@link AudioManager}.
          *
-         * @see TextToSpeech#speak(String, int, HashMap)
+         * @see TextToSpeech#speak(CharSequence, int, Bundle, String)
          * @see TextToSpeech#playEarcon(String, int, HashMap)
          */
         public static final String KEY_PARAM_STREAM = "streamType";
@@ -546,7 +546,7 @@
          * speaking text or playing back a file. The value should be set
          * using {@link TextToSpeech#setAudioAttributes(AudioAttributes)}.
          *
-         * @see TextToSpeech#speak(String, int, HashMap)
+         * @see TextToSpeech#speak(CharSequence, int, Bundle, String)
          * @see TextToSpeech#playEarcon(String, int, HashMap)
          * @hide
          */
@@ -557,7 +557,7 @@
          * {@link TextToSpeech.OnUtteranceCompletedListener} after text has been
          * spoken, a file has been played back or a silence duration has elapsed.
          *
-         * @see TextToSpeech#speak(String, int, HashMap)
+         * @see TextToSpeech#speak(CharSequence, int, Bundle, String)
          * @see TextToSpeech#playEarcon(String, int, HashMap)
          * @see TextToSpeech#synthesizeToFile(String, HashMap, String)
          */
@@ -568,7 +568,7 @@
          * volume used when speaking text. Volume is specified as a float ranging from 0 to 1
          * where 0 is silence, and 1 is the maximum volume (the default behavior).
          *
-         * @see TextToSpeech#speak(String, int, HashMap)
+         * @see TextToSpeech#speak(CharSequence, int, Bundle, String)
          * @see TextToSpeech#playEarcon(String, int, HashMap)
          */
         public static final String KEY_PARAM_VOLUME = "volume";
@@ -578,7 +578,7 @@
          * Pan is specified as a float ranging from -1 to +1 where -1 maps to a hard-left pan,
          * 0 to center (the default behavior), and +1 to hard-right.
          *
-         * @see TextToSpeech#speak(String, int, HashMap)
+         * @see TextToSpeech#speak(CharSequence, int, Bundle, String)
          * @see TextToSpeech#playEarcon(String, int, HashMap)
          */
         public static final String KEY_PARAM_PAN = "pan";
@@ -589,7 +589,7 @@
          * as per {@link TextToSpeech#getFeatures(Locale)}, the engine must
          * use network based synthesis.
          *
-         * @see TextToSpeech#speak(String, int, java.util.HashMap)
+         * @see TextToSpeech#speak(CharSequence, int, Bundle, String)
          * @see TextToSpeech#synthesizeToFile(String, java.util.HashMap, String)
          * @see TextToSpeech#getFeatures(java.util.Locale)
          *
@@ -607,7 +607,7 @@
          * as per {@link TextToSpeech#getFeatures(Locale)}, the engine must synthesize
          * text on-device (without making network requests).
          *
-         * @see TextToSpeech#speak(String, int, java.util.HashMap)
+         * @see TextToSpeech#speak(CharSequence, int, Bundle, String)
          * @see TextToSpeech#synthesizeToFile(String, java.util.HashMap, String)
          * @see TextToSpeech#getFeatures(java.util.Locale)
 
@@ -625,7 +625,7 @@
          * output. It can be used to associate one of the {@link android.media.audiofx.AudioEffect}
          * objects with the synthesis (or earcon) output.
          *
-         * @see TextToSpeech#speak(String, int, HashMap)
+         * @see TextToSpeech#speak(CharSequence, int, Bundle, String)
          * @see TextToSpeech#playEarcon(String, int, HashMap)
          */
         public static final String KEY_PARAM_SESSION_ID = "sessionId";
@@ -881,7 +881,7 @@
     /**
      * Adds a mapping between a string of text and a sound resource in a
      * package. After a call to this method, subsequent calls to
-     * {@link #speak(String, int, HashMap)} will play the specified sound resource
+     * {@link #speak(CharSequence, int, Bundle, String)} will play the specified sound resource
      * if it is available, or synthesize the text it is missing.
      *
      * @param text
@@ -915,7 +915,7 @@
     /**
      * Adds a mapping between a CharSequence (may be spanned with TtsSpans) of text
      * and a sound resource in a package. After a call to this method, subsequent calls to
-     * {@link #speak(String, int, HashMap)} will play the specified sound resource
+     * {@link #speak(CharSequence, int, Bundle, String)} will play the specified sound resource
      * if it is available, or synthesize the text it is missing.
      *
      * @param text
@@ -947,11 +947,10 @@
     }
 
     /**
-     * Adds a mapping between a string of text and a sound file. Using this, it
-     * is possible to add custom pronounciations for a string of text.
-     * After a call to this method, subsequent calls to {@link #speak(String, int, HashMap)}
-     * will play the specified sound resource if it is available, or synthesize the text it is
-     * missing.
+     * Adds a mapping between a string of text and a sound file. Using this, it is possible to
+     * add custom pronounciations for a string of text. After a call to this method, subsequent
+     * calls to {@link #speak(CharSequence, int, Bundle, String)} will play the specified sound
+     * resource if it is available, or synthesize the text it is missing.
      *
      * @param text
      *            The string of text. Example: <code>"south_south_east"</code>
@@ -970,8 +969,8 @@
 
     /**
      * Adds a mapping between a CharSequence (may be spanned with TtsSpans and a sound file.
-     * Using this, it is possible to add custom pronounciations for a string of text.
-     * After a call to this method, subsequent calls to {@link #speak(String, int, HashMap)}
+     * Using this, it is possible to add custom pronounciations for a string of text. After a call
+     * to this method, subsequent calls to {@link #speak(CharSequence, int, Bundle, String)}
      * will play the specified sound resource if it is available, or synthesize the text it is
      * missing.
      *
diff --git a/core/java/android/text/style/LineBackgroundSpan.java b/core/java/android/text/style/LineBackgroundSpan.java
index e43fd83..7cb9147 100644
--- a/core/java/android/text/style/LineBackgroundSpan.java
+++ b/core/java/android/text/style/LineBackgroundSpan.java
@@ -53,6 +53,15 @@
     /**
      * Default implementation of the {@link LineBackgroundSpan}, which changes the background
      * color of the lines to which the span is attached.
+     * <p>
+     * For example, an <code>LineBackgroundSpan</code> can be used like this:
+     * <pre>
+     * String text = "This is a multiline text. LineBackgroundSpan is applied here. This is a multiline text.";
+     * SpannableString string = new SpannableString(text);
+     * string.setSpan(new LineBackgroundSpan.Standard(Color.YELLOW), 26, 61, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
+     * </pre>
+     * <img src="{@docRoot}reference/android/images/text/style/linebackgroundspan.png" />
+     * <figcaption>Text with <code>LineBackgroundSpan</code></figcaption>
      */
     class Standard implements LineBackgroundSpan, ParcelableSpan {
 
diff --git a/core/java/android/text/style/LineHeightSpan.java b/core/java/android/text/style/LineHeightSpan.java
index 7fb0f95..610cf2c 100644
--- a/core/java/android/text/style/LineHeightSpan.java
+++ b/core/java/android/text/style/LineHeightSpan.java
@@ -70,7 +70,15 @@
      * Default implementation of the {@link LineHeightSpan}, which changes the line height of the
      * attached paragraph.
      * <p>
-     * LineHeightSpan will change the line height of the entire paragraph, even though it
+     * For example, a paragraph with its line height equal to 100px can be set like this:
+     * <pre>
+     * SpannableString string = new SpannableString("This is a multiline paragraph. This is a multiline paragraph.");
+     * string.setSpan(new LineHeightSpan.Standard(100), 0, string.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
+     * </pre>
+     * <img src="{@docRoot}reference/android/images/text/style/lineheightspan.png" />
+     * <figcaption>Text with line height set to 100 pixels.</figcaption>
+     * <p>
+     * Notice that LineHeightSpan will change the line height of the entire paragraph, even though it
      * covers only part of the paragraph.
      * </p>
      */
diff --git a/core/java/android/util/FeatureFlagUtils.java b/core/java/android/util/FeatureFlagUtils.java
index c1504ae..de10ffb 100644
--- a/core/java/android/util/FeatureFlagUtils.java
+++ b/core/java/android/util/FeatureFlagUtils.java
@@ -51,7 +51,7 @@
         DEFAULT_FLAGS.put("settings_network_and_internet_v2", "true");
         DEFAULT_FLAGS.put("settings_slice_injection", "true");
         DEFAULT_FLAGS.put("settings_systemui_theme", "true");
-        DEFAULT_FLAGS.put("settings_mainline_module", "false");
+        DEFAULT_FLAGS.put("settings_mainline_module", "true");
         DEFAULT_FLAGS.put("settings_dynamic_android", "false");
         DEFAULT_FLAGS.put(SEAMLESS_TRANSFER, "false");
         DEFAULT_FLAGS.put(HEARING_AID_SETTINGS, "false");
diff --git a/core/java/android/util/XmlPullAttributes.java b/core/java/android/util/XmlPullAttributes.java
index cb35eb5..32fe16f 100644
--- a/core/java/android/util/XmlPullAttributes.java
+++ b/core/java/android/util/XmlPullAttributes.java
@@ -18,6 +18,7 @@
 
 import org.xmlpull.v1.XmlPullParser;
 
+import android.annotation.UnsupportedAppUsage;
 import android.util.AttributeSet;
 
 import com.android.internal.util.XmlUtils;
@@ -26,6 +27,7 @@
  * Provides an implementation of AttributeSet on top of an XmlPullParser.
  */
 class XmlPullAttributes implements AttributeSet {
+    @UnsupportedAppUsage
     public XmlPullAttributes(XmlPullParser parser) {
         mParser = parser;
     }
@@ -147,5 +149,6 @@
         return getAttributeResourceValue(null, "style", 0);
     }
 
+    @UnsupportedAppUsage
     /*package*/ XmlPullParser mParser;
 }
diff --git a/core/java/android/view/IRecentsAnimationController.aidl b/core/java/android/view/IRecentsAnimationController.aidl
index b1f934a..597b34bf 100644
--- a/core/java/android/view/IRecentsAnimationController.aidl
+++ b/core/java/android/view/IRecentsAnimationController.aidl
@@ -73,4 +73,33 @@
      * Hides the current input method if one is showing.
      */
     void hideCurrentInputMethod();
+
+    /**
+     * Set a state for controller whether would like to cancel recents animations with deferred
+     * task screenshot presentation.
+     *
+     * When we cancel the recents animation due to a stack order change, we can't just cancel it
+     * immediately as it would lead to a flicker in Launcher if we just remove the task from the
+     * leash. Instead we screenshot the previous task and replace the child of the leash with the
+     * screenshot, so that Launcher can still control the leash lifecycle & make the next app
+     * transition animate smoothly without flickering.
+     *
+     * @param screenshot When set {@code true}, means recents animation will be canceled when the
+     *                   next app launch. System will take previous task's screenshot when the next
+     *                   app transition starting, and skip previous task's animation.
+     *                   Set {@code false} means will not take screenshot & skip animation
+     *                   for previous task.
+     *
+     * @see #cleanupScreenshot()
+     * @see IRecentsAnimationRunner#onCancelled
+     */
+    void setCancelWithDeferredScreenshot(boolean screenshot);
+
+    /**
+     * Clean up the screenshot of previous task which was created during recents animation that
+     * was cancelled by a stack order change.
+     *
+     * @see {@link IRecentsAnimationRunner#onAnimationCanceled}
+     */
+    void cleanupScreenshot();
 }
diff --git a/core/java/android/view/IRecentsAnimationRunner.aidl b/core/java/android/view/IRecentsAnimationRunner.aidl
index 6e382f4..9c652a8 100644
--- a/core/java/android/view/IRecentsAnimationRunner.aidl
+++ b/core/java/android/view/IRecentsAnimationRunner.aidl
@@ -32,9 +32,17 @@
      * Called when the system needs to cancel the current animation. This can be due to the
      * wallpaper not drawing in time, or the handler not finishing the animation within a predefined
      * amount of time.
+     *
+     * @param deferredWithScreenshot If set to {@code true}, the contents of the task will be
+     *                               replaced with a screenshot, such that the runner's leash is
+     *                               still active. As soon as the runner doesn't need the leash
+     *                               anymore, it can call
+     *                               {@link IRecentsAnimationController#cleanupScreenshot).
+     *
+     * @see {@link RecentsAnimationController#cleanupScreenshot}
      */
     @UnsupportedAppUsage
-    void onAnimationCanceled() = 1;
+    void onAnimationCanceled(boolean deferredWithScreenshot) = 1;
 
     /**
      * Called when the system is ready for the handler to start animating all the visible tasks.
diff --git a/core/java/android/view/ISystemGestureExclusionListener.aidl b/core/java/android/view/ISystemGestureExclusionListener.aidl
new file mode 100644
index 0000000..a032625
--- /dev/null
+++ b/core/java/android/view/ISystemGestureExclusionListener.aidl
@@ -0,0 +1,34 @@
+/**
+ * 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 android.view;
+
+import android.graphics.Region;
+
+/**
+ * Listener for changes to the system gesture exclusion region
+ *
+ * {@hide}
+ */
+oneway interface ISystemGestureExclusionListener {
+    /**
+     * Called when the system gesture exclusion for the given display changed.
+     * @param displayId the display whose system gesture exclusion changed
+     * @param systemGestureExclusion a {@code Region} where the app would like priority over the
+     *                               system gestures, in display coordinates.
+     */
+    void onSystemGestureExclusionChanged(int displayId, in Region systemGestureExclusion);
+}
\ No newline at end of file
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
index e32c4e1..b91b93f 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -40,6 +40,7 @@
 import android.view.IPinnedStackListener;
 import android.view.RemoteAnimationAdapter;
 import android.view.IRotationWatcher;
+import android.view.ISystemGestureExclusionListener;
 import android.view.IWallpaperVisibilityListener;
 import android.view.IWindowSession;
 import android.view.IWindowSessionCallback;
@@ -129,7 +130,7 @@
     @UnsupportedAppUsage
     boolean isKeyguardLocked();
     @UnsupportedAppUsage
-    boolean isKeyguardSecure();
+    boolean isKeyguardSecure(int userId);
     void dismissKeyguard(IKeyguardDismissCallback callback, CharSequence message);
 
     // Requires INTERACT_ACROSS_USERS_FULL permission
@@ -281,6 +282,18 @@
         int displayId);
 
     /**
+     * Registers a system gesture exclusion listener for a given display.
+     */
+    void registerSystemGestureExclusionListener(ISystemGestureExclusionListener listener,
+        int displayId);
+
+    /**
+     * Unregisters a system gesture exclusion listener for a given display.
+     */
+    void unregisterSystemGestureExclusionListener(ISystemGestureExclusionListener listener,
+        int displayId);
+
+    /**
      * Used only for assist -- request a screenshot of the current application.
      */
     boolean requestAssistScreenshot(IAssistDataReceiver receiver);
diff --git a/core/java/android/view/IWindowSession.aidl b/core/java/android/view/IWindowSession.aidl
index 1fcd432..87efb3f 100644
--- a/core/java/android/view/IWindowSession.aidl
+++ b/core/java/android/view/IWindowSession.aidl
@@ -32,6 +32,8 @@
 import android.view.Surface;
 import android.view.SurfaceControl;
 
+import java.util.List;
+
 /**
  * System private per-application interface to the window manager.
  *
@@ -265,4 +267,10 @@
      * that new state.
      */
     void insetsModified(IWindow window, in InsetsState state);
+
+
+    /**
+     * Called when the system gesture exclusion has changed.
+     */
+    void reportSystemGestureExclusionChanged(IWindow window, in List<Rect> exclusionRects);
 }
diff --git a/core/java/android/view/InsetsState.java b/core/java/android/view/InsetsState.java
index 2d7e179..6129b38 100644
--- a/core/java/android/view/InsetsState.java
+++ b/core/java/android/view/InsetsState.java
@@ -145,7 +145,14 @@
 
             // TODO: set system gesture insets based on actual system gesture area.
             typeInsetsMap[Type.indexOf(Type.systemGestures())] = Insets.of(legacyContentInsets);
-            typeMaxInsetsMap[Type.indexOf(Type.systemGestures())] = Insets.of(legacyContentInsets);
+            typeInsetsMap[Type.indexOf(Type.mandatorySystemGestures())] =
+                    Insets.of(legacyContentInsets);
+            typeInsetsMap[Type.indexOf(Type.tappableElement())] = Insets.of(legacyContentInsets);
+
+            typeMaxInsetsMap[Type.indexOf(Type.systemGestures())] = Insets.of(legacyStableInsets);
+            typeMaxInsetsMap[Type.indexOf(Type.mandatorySystemGestures())] =
+                    Insets.of(legacyStableInsets);
+            typeMaxInsetsMap[Type.indexOf(Type.tappableElement())] = Insets.of(legacyStableInsets);
         }
         for (int type = FIRST_TYPE; type <= LAST_TYPE; type++) {
             InsetsSource source = mSources.get(type);
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index b857f1e..75067d3 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -125,8 +125,8 @@
 import android.view.inputmethod.InputConnection;
 import android.view.inputmethod.InputMethodManager;
 import android.view.inspector.InspectableProperty;
-import android.view.inspector.InspectableProperty.EnumMap;
-import android.view.inspector.InspectableProperty.FlagMap;
+import android.view.inspector.InspectableProperty.EnumEntry;
+import android.view.inspector.InspectableProperty.FlagEntry;
 import android.widget.Checkable;
 import android.widget.FrameLayout;
 import android.widget.ScrollBarDrawable;
@@ -6897,13 +6897,13 @@
      * @return a bitmask representing the enabled scroll indicators
      */
     @InspectableProperty(flagMapping = {
-            @FlagMap(target = SCROLL_INDICATORS_NONE, mask = 0xffff_ffff, name = "none"),
-            @FlagMap(target = SCROLL_INDICATOR_TOP, name = "top"),
-            @FlagMap(target = SCROLL_INDICATOR_BOTTOM, name = "bottom"),
-            @FlagMap(target = SCROLL_INDICATOR_LEFT, name = "left"),
-            @FlagMap(target = SCROLL_INDICATOR_RIGHT, name = "right"),
-            @FlagMap(target = SCROLL_INDICATOR_START, name = "start"),
-            @FlagMap(target = SCROLL_INDICATOR_END, name = "end")
+            @FlagEntry(target = SCROLL_INDICATORS_NONE, mask = 0xffff_ffff, name = "none"),
+            @FlagEntry(target = SCROLL_INDICATOR_TOP, name = "top"),
+            @FlagEntry(target = SCROLL_INDICATOR_BOTTOM, name = "bottom"),
+            @FlagEntry(target = SCROLL_INDICATOR_LEFT, name = "left"),
+            @FlagEntry(target = SCROLL_INDICATOR_RIGHT, name = "right"),
+            @FlagEntry(target = SCROLL_INDICATOR_START, name = "start"),
+            @FlagEntry(target = SCROLL_INDICATOR_END, name = "end")
     })
     @ScrollIndicators
     public int getScrollIndicators() {
@@ -9032,12 +9032,12 @@
             @ViewDebug.IntToString(from = IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS,
                 to = "noExcludeDescendants")})
     @InspectableProperty(enumMapping = {
-            @EnumMap(value = IMPORTANT_FOR_AUTOFILL_AUTO, name = "auto"),
-            @EnumMap(value = IMPORTANT_FOR_AUTOFILL_YES, name = "yes"),
-            @EnumMap(value = IMPORTANT_FOR_AUTOFILL_NO, name = "no"),
-            @EnumMap(value = IMPORTANT_FOR_AUTOFILL_YES_EXCLUDE_DESCENDANTS,
+            @EnumEntry(value = IMPORTANT_FOR_AUTOFILL_AUTO, name = "auto"),
+            @EnumEntry(value = IMPORTANT_FOR_AUTOFILL_YES, name = "yes"),
+            @EnumEntry(value = IMPORTANT_FOR_AUTOFILL_NO, name = "no"),
+            @EnumEntry(value = IMPORTANT_FOR_AUTOFILL_YES_EXCLUDE_DESCENDANTS,
                     name = "yesExcludeDescendants"),
-            @EnumMap(value = IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS,
+            @EnumEntry(value = IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS,
                     name = "noExcludeDescendants"),
     })
     public @AutofillImportance int getImportantForAutofill() {
@@ -9225,12 +9225,12 @@
             @ViewDebug.IntToString(from = IMPORTANT_FOR_CONTENT_CAPTURE_NO_EXCLUDE_DESCENDANTS,
                 to = "noExcludeDescendants")})
     @InspectableProperty(enumMapping = {
-            @EnumMap(value = IMPORTANT_FOR_CONTENT_CAPTURE_AUTO, name = "auto"),
-            @EnumMap(value = IMPORTANT_FOR_CONTENT_CAPTURE_YES, name = "yes"),
-            @EnumMap(value = IMPORTANT_FOR_CONTENT_CAPTURE_NO, name = "no"),
-            @EnumMap(value = IMPORTANT_FOR_CONTENT_CAPTURE_YES_EXCLUDE_DESCENDANTS,
+            @EnumEntry(value = IMPORTANT_FOR_CONTENT_CAPTURE_AUTO, name = "auto"),
+            @EnumEntry(value = IMPORTANT_FOR_CONTENT_CAPTURE_YES, name = "yes"),
+            @EnumEntry(value = IMPORTANT_FOR_CONTENT_CAPTURE_NO, name = "no"),
+            @EnumEntry(value = IMPORTANT_FOR_CONTENT_CAPTURE_YES_EXCLUDE_DESCENDANTS,
                     name = "yesExcludeDescendants"),
-            @EnumMap(value = IMPORTANT_FOR_CONTENT_CAPTURE_NO_EXCLUDE_DESCENDANTS,
+            @EnumEntry(value = IMPORTANT_FOR_CONTENT_CAPTURE_NO_EXCLUDE_DESCENDANTS,
                     name = "noExcludeDescendants"),
     })
     public @ContentCaptureImportance int getImportantForContentCapture() {
@@ -10534,9 +10534,9 @@
     @Deprecated
     @DrawingCacheQuality
     @InspectableProperty(enumMapping = {
-            @EnumMap(value = DRAWING_CACHE_QUALITY_LOW, name = "low"),
-            @EnumMap(value = DRAWING_CACHE_QUALITY_HIGH, name = "high"),
-            @EnumMap(value = DRAWING_CACHE_QUALITY_AUTO, name = "auto")
+            @EnumEntry(value = DRAWING_CACHE_QUALITY_LOW, name = "low"),
+            @EnumEntry(value = DRAWING_CACHE_QUALITY_HIGH, name = "high"),
+            @EnumEntry(value = DRAWING_CACHE_QUALITY_AUTO, name = "auto")
     })
     public int getDrawingCacheQuality() {
         return mViewFlags & DRAWING_CACHE_QUALITY_MASK;
@@ -11090,11 +11090,10 @@
      * <p>Computes the coordinates of this view in its surface. The argument
      * must be an array of two integers. After the method returns, the array
      * contains the x and y location in that order.</p>
-     * @hide
+     *
      * @param location an array of two integers in which to hold the coordinates
      */
-    @UnsupportedAppUsage
-    public void getLocationInSurface(@Size(2) int[] location) {
+    public void getLocationInSurface(@NonNull @Size(2) int[] location) {
         getLocationInWindow(location);
         if (mAttachInfo != null && mAttachInfo.mViewRootImpl != null) {
             location[0] += mAttachInfo.mViewRootImpl.mWindowAttributes.surfaceInsets.left;
@@ -11276,9 +11275,9 @@
         @ViewDebug.IntToString(from = GONE,      to = "GONE")
     })
     @InspectableProperty(enumMapping = {
-            @EnumMap(value = VISIBLE, name = "visible"),
-            @EnumMap(value = INVISIBLE, name = "invisible"),
-            @EnumMap(value = GONE, name = "gone")
+            @EnumEntry(value = VISIBLE, name = "visible"),
+            @EnumEntry(value = INVISIBLE, name = "invisible"),
+            @EnumEntry(value = GONE, name = "gone")
     })
     @Visibility
     public int getVisibility() {
@@ -11527,10 +11526,10 @@
         @ViewDebug.IntToString(from = LAYOUT_DIRECTION_LOCALE,  to = "LOCALE")
     })
     @InspectableProperty(hasAttributeId = false, enumMapping = {
-            @EnumMap(value = LAYOUT_DIRECTION_LTR, name = "ltr"),
-            @EnumMap(value = LAYOUT_DIRECTION_RTL, name = "rtl"),
-            @EnumMap(value = LAYOUT_DIRECTION_INHERIT, name = "inherit"),
-            @EnumMap(value = LAYOUT_DIRECTION_LOCALE, name = "locale")
+            @EnumEntry(value = LAYOUT_DIRECTION_LTR, name = "ltr"),
+            @EnumEntry(value = LAYOUT_DIRECTION_RTL, name = "rtl"),
+            @EnumEntry(value = LAYOUT_DIRECTION_INHERIT, name = "inherit"),
+            @EnumEntry(value = LAYOUT_DIRECTION_LOCALE, name = "locale")
     })
     @LayoutDir
     public int getRawLayoutDirection() {
@@ -11586,8 +11585,8 @@
         @ViewDebug.IntToString(from = LAYOUT_DIRECTION_RTL, to = "RESOLVED_DIRECTION_RTL")
     })
     @InspectableProperty(enumMapping = {
-            @EnumMap(value = LAYOUT_DIRECTION_LTR, name = "ltr"),
-            @EnumMap(value = LAYOUT_DIRECTION_RTL, name = "rtl")
+            @EnumEntry(value = LAYOUT_DIRECTION_LTR, name = "ltr"),
+            @EnumEntry(value = LAYOUT_DIRECTION_RTL, name = "rtl")
     })
     @ResolvedLayoutDir
     public int getLayoutDirection() {
@@ -12072,9 +12071,9 @@
             @ViewDebug.IntToString(from = FOCUSABLE_AUTO, to = "FOCUSABLE_AUTO")
             }, category = "focus")
     @InspectableProperty(enumMapping = {
-            @EnumMap(value = NOT_FOCUSABLE, name = "false"),
-            @EnumMap(value = FOCUSABLE, name = "true"),
-            @EnumMap(value = FOCUSABLE_AUTO, name = "auto")
+            @EnumEntry(value = NOT_FOCUSABLE, name = "false"),
+            @EnumEntry(value = FOCUSABLE, name = "true"),
+            @EnumEntry(value = FOCUSABLE_AUTO, name = "auto")
     })
     @Focusable
     public int getFocusable() {
@@ -12957,10 +12956,10 @@
                     to = "noHideDescendants")
         })
     @InspectableProperty(enumMapping = {
-            @EnumMap(value = IMPORTANT_FOR_ACCESSIBILITY_AUTO, name = "auto"),
-            @EnumMap(value = IMPORTANT_FOR_ACCESSIBILITY_YES, name = "yes"),
-            @EnumMap(value = IMPORTANT_FOR_ACCESSIBILITY_NO, name = "no"),
-            @EnumMap(value = IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS,
+            @EnumEntry(value = IMPORTANT_FOR_ACCESSIBILITY_AUTO, name = "auto"),
+            @EnumEntry(value = IMPORTANT_FOR_ACCESSIBILITY_YES, name = "yes"),
+            @EnumEntry(value = IMPORTANT_FOR_ACCESSIBILITY_NO, name = "no"),
+            @EnumEntry(value = IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS,
                     name = "noHideDescendants"),
     })
     public int getImportantForAccessibility() {
@@ -13016,9 +13015,9 @@
      * @see #setAccessibilityLiveRegion(int)
      */
     @InspectableProperty(enumMapping = {
-            @EnumMap(value = ACCESSIBILITY_LIVE_REGION_NONE, name = "none"),
-            @EnumMap(value = ACCESSIBILITY_LIVE_REGION_POLITE, name = "polite"),
-            @EnumMap(value = ACCESSIBILITY_LIVE_REGION_ASSERTIVE, name = "assertive")
+            @EnumEntry(value = ACCESSIBILITY_LIVE_REGION_NONE, name = "none"),
+            @EnumEntry(value = ACCESSIBILITY_LIVE_REGION_POLITE, name = "polite"),
+            @EnumEntry(value = ACCESSIBILITY_LIVE_REGION_ASSERTIVE, name = "assertive")
     })
     public int getAccessibilityLiveRegion() {
         return (mPrivateFlags2 & PFLAG2_ACCESSIBILITY_LIVE_REGION_MASK)
@@ -18625,9 +18624,9 @@
      * @hide
      */
     @InspectableProperty(name = "requiresFadingEdge", flagMapping = {
-            @FlagMap(target = FADING_EDGE_NONE, mask = FADING_EDGE_MASK, name = "none"),
-            @FlagMap(target = FADING_EDGE_VERTICAL, name = "vertical"),
-            @FlagMap(target = FADING_EDGE_HORIZONTAL, name = "horizontal")
+            @FlagEntry(target = FADING_EDGE_NONE, mask = FADING_EDGE_MASK, name = "none"),
+            @FlagEntry(target = FADING_EDGE_VERTICAL, name = "vertical"),
+            @FlagEntry(target = FADING_EDGE_HORIZONTAL, name = "horizontal")
     })
     public int getFadingEdge() {
         return mViewFlags & FADING_EDGE_MASK;
@@ -18922,10 +18921,10 @@
             @ViewDebug.IntToString(from = SCROLLBARS_OUTSIDE_INSET, to = "OUTSIDE_INSET")
     })
     @InspectableProperty(name = "scrollbarStyle", enumMapping = {
-            @EnumMap(value = SCROLLBARS_INSIDE_OVERLAY, name = "insideOverlay"),
-            @EnumMap(value = SCROLLBARS_INSIDE_INSET, name = "insideInset"),
-            @EnumMap(value = SCROLLBARS_OUTSIDE_OVERLAY, name = "outsideOverlay"),
-            @EnumMap(value = SCROLLBARS_OUTSIDE_INSET, name = "outsideInset")
+            @EnumEntry(value = SCROLLBARS_INSIDE_OVERLAY, name = "insideOverlay"),
+            @EnumEntry(value = SCROLLBARS_INSIDE_INSET, name = "insideInset"),
+            @EnumEntry(value = SCROLLBARS_OUTSIDE_OVERLAY, name = "outsideOverlay"),
+            @EnumEntry(value = SCROLLBARS_OUTSIDE_INSET, name = "outsideInset")
     })
     @ScrollBarStyle
     public int getScrollBarStyle() {
@@ -20478,9 +20477,9 @@
      * @see #LAYER_TYPE_HARDWARE
      */
     @InspectableProperty(enumMapping = {
-            @EnumMap(value = LAYER_TYPE_NONE, name = "none"),
-            @EnumMap(value = LAYER_TYPE_SOFTWARE, name = "software"),
-            @EnumMap(value = LAYER_TYPE_HARDWARE, name = "hardware")
+            @EnumEntry(value = LAYER_TYPE_NONE, name = "none"),
+            @EnumEntry(value = LAYER_TYPE_SOFTWARE, name = "software"),
+            @EnumEntry(value = LAYER_TYPE_HARDWARE, name = "hardware")
     })
     @LayerType
     public int getLayerType() {
@@ -26160,9 +26159,9 @@
      * @return This view's over-scroll mode.
      */
     @InspectableProperty(enumMapping = {
-            @EnumMap(value = OVER_SCROLL_ALWAYS, name = "always"),
-            @EnumMap(value = OVER_SCROLL_IF_CONTENT_SCROLLS, name = "ifContentScrolls"),
-            @EnumMap(value = OVER_SCROLL_NEVER, name = "never")
+            @EnumEntry(value = OVER_SCROLL_ALWAYS, name = "always"),
+            @EnumEntry(value = OVER_SCROLL_IF_CONTENT_SCROLLS, name = "ifContentScrolls"),
+            @EnumEntry(value = OVER_SCROLL_NEVER, name = "never")
     })
     public int getOverScrollMode() {
         return mOverScrollMode;
@@ -26553,14 +26552,14 @@
             @ViewDebug.IntToString(from = TEXT_DIRECTION_FIRST_STRONG_RTL, to = "FIRST_STRONG_RTL")
     })
     @InspectableProperty(hasAttributeId = false, enumMapping = {
-            @EnumMap(value = TEXT_DIRECTION_INHERIT, name = "inherit"),
-            @EnumMap(value = TEXT_DIRECTION_LOCALE, name = "locale"),
-            @EnumMap(value = TEXT_DIRECTION_ANY_RTL, name = "anyRtl"),
-            @EnumMap(value = TEXT_DIRECTION_LTR, name = "ltr"),
-            @EnumMap(value = TEXT_DIRECTION_RTL, name = "rtl"),
-            @EnumMap(value = TEXT_DIRECTION_FIRST_STRONG, name = "firstStrong"),
-            @EnumMap(value = TEXT_DIRECTION_FIRST_STRONG_LTR, name = "firstStrongLtr"),
-            @EnumMap(value = TEXT_DIRECTION_FIRST_STRONG_RTL, name = "firstStrongRtl"),
+            @EnumEntry(value = TEXT_DIRECTION_INHERIT, name = "inherit"),
+            @EnumEntry(value = TEXT_DIRECTION_LOCALE, name = "locale"),
+            @EnumEntry(value = TEXT_DIRECTION_ANY_RTL, name = "anyRtl"),
+            @EnumEntry(value = TEXT_DIRECTION_LTR, name = "ltr"),
+            @EnumEntry(value = TEXT_DIRECTION_RTL, name = "rtl"),
+            @EnumEntry(value = TEXT_DIRECTION_FIRST_STRONG, name = "firstStrong"),
+            @EnumEntry(value = TEXT_DIRECTION_FIRST_STRONG_LTR, name = "firstStrongLtr"),
+            @EnumEntry(value = TEXT_DIRECTION_FIRST_STRONG_RTL, name = "firstStrongRtl"),
     })
     @UnsupportedAppUsage
     public int getRawTextDirection() {
@@ -26630,13 +26629,13 @@
             @ViewDebug.IntToString(from = TEXT_DIRECTION_FIRST_STRONG_RTL, to = "FIRST_STRONG_RTL")
     })
     @InspectableProperty(hasAttributeId = false, enumMapping = {
-            @EnumMap(value = TEXT_DIRECTION_LOCALE, name = "locale"),
-            @EnumMap(value = TEXT_DIRECTION_ANY_RTL, name = "anyRtl"),
-            @EnumMap(value = TEXT_DIRECTION_LTR, name = "ltr"),
-            @EnumMap(value = TEXT_DIRECTION_RTL, name = "rtl"),
-            @EnumMap(value = TEXT_DIRECTION_FIRST_STRONG, name = "firstStrong"),
-            @EnumMap(value = TEXT_DIRECTION_FIRST_STRONG_LTR, name = "firstStrongLtr"),
-            @EnumMap(value = TEXT_DIRECTION_FIRST_STRONG_RTL, name = "firstStrongRtl"),
+            @EnumEntry(value = TEXT_DIRECTION_LOCALE, name = "locale"),
+            @EnumEntry(value = TEXT_DIRECTION_ANY_RTL, name = "anyRtl"),
+            @EnumEntry(value = TEXT_DIRECTION_LTR, name = "ltr"),
+            @EnumEntry(value = TEXT_DIRECTION_RTL, name = "rtl"),
+            @EnumEntry(value = TEXT_DIRECTION_FIRST_STRONG, name = "firstStrong"),
+            @EnumEntry(value = TEXT_DIRECTION_FIRST_STRONG_LTR, name = "firstStrongLtr"),
+            @EnumEntry(value = TEXT_DIRECTION_FIRST_STRONG_RTL, name = "firstStrongRtl"),
     })
     public int getTextDirection() {
         return (mPrivateFlags2 & PFLAG2_TEXT_DIRECTION_RESOLVED_MASK) >> PFLAG2_TEXT_DIRECTION_RESOLVED_MASK_SHIFT;
@@ -26810,13 +26809,13 @@
             @ViewDebug.IntToString(from = TEXT_ALIGNMENT_VIEW_END, to = "VIEW_END")
     })
     @InspectableProperty(hasAttributeId = false, enumMapping = {
-            @EnumMap(value = TEXT_ALIGNMENT_INHERIT, name = "inherit"),
-            @EnumMap(value = TEXT_ALIGNMENT_GRAVITY, name = "gravity"),
-            @EnumMap(value = TEXT_ALIGNMENT_TEXT_START, name = "textStart"),
-            @EnumMap(value = TEXT_ALIGNMENT_TEXT_END, name = "textEnd"),
-            @EnumMap(value = TEXT_ALIGNMENT_CENTER, name = "center"),
-            @EnumMap(value = TEXT_ALIGNMENT_VIEW_START, name = "viewStart"),
-            @EnumMap(value = TEXT_ALIGNMENT_VIEW_END, name = "viewEnd")
+            @EnumEntry(value = TEXT_ALIGNMENT_INHERIT, name = "inherit"),
+            @EnumEntry(value = TEXT_ALIGNMENT_GRAVITY, name = "gravity"),
+            @EnumEntry(value = TEXT_ALIGNMENT_TEXT_START, name = "textStart"),
+            @EnumEntry(value = TEXT_ALIGNMENT_TEXT_END, name = "textEnd"),
+            @EnumEntry(value = TEXT_ALIGNMENT_CENTER, name = "center"),
+            @EnumEntry(value = TEXT_ALIGNMENT_VIEW_START, name = "viewStart"),
+            @EnumEntry(value = TEXT_ALIGNMENT_VIEW_END, name = "viewEnd")
     })
     @TextAlignment
     @UnsupportedAppUsage
@@ -26885,12 +26884,12 @@
             @ViewDebug.IntToString(from = TEXT_ALIGNMENT_VIEW_END, to = "VIEW_END")
     })
     @InspectableProperty(enumMapping = {
-            @EnumMap(value = TEXT_ALIGNMENT_GRAVITY, name = "gravity"),
-            @EnumMap(value = TEXT_ALIGNMENT_TEXT_START, name = "textStart"),
-            @EnumMap(value = TEXT_ALIGNMENT_TEXT_END, name = "textEnd"),
-            @EnumMap(value = TEXT_ALIGNMENT_CENTER, name = "center"),
-            @EnumMap(value = TEXT_ALIGNMENT_VIEW_START, name = "viewStart"),
-            @EnumMap(value = TEXT_ALIGNMENT_VIEW_END, name = "viewEnd")
+            @EnumEntry(value = TEXT_ALIGNMENT_GRAVITY, name = "gravity"),
+            @EnumEntry(value = TEXT_ALIGNMENT_TEXT_START, name = "textStart"),
+            @EnumEntry(value = TEXT_ALIGNMENT_TEXT_END, name = "textEnd"),
+            @EnumEntry(value = TEXT_ALIGNMENT_CENTER, name = "center"),
+            @EnumEntry(value = TEXT_ALIGNMENT_VIEW_START, name = "viewStart"),
+            @EnumEntry(value = TEXT_ALIGNMENT_VIEW_END, name = "viewEnd")
     })
     @TextAlignment
     public int getTextAlignment() {
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index 4964ee1..a4d80dc 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -61,7 +61,7 @@
 import android.view.animation.Transformation;
 import android.view.autofill.Helper;
 import android.view.inspector.InspectableProperty;
-import android.view.inspector.InspectableProperty.EnumMap;
+import android.view.inspector.InspectableProperty.EnumEntry;
 
 import com.android.internal.R;
 
@@ -778,9 +778,9 @@
         @ViewDebug.IntToString(from = FOCUS_BLOCK_DESCENDANTS, to = "FOCUS_BLOCK_DESCENDANTS")
     })
     @InspectableProperty(enumMapping = {
-            @EnumMap(value = FOCUS_BEFORE_DESCENDANTS, name = "beforeDescendants"),
-            @EnumMap(value = FOCUS_AFTER_DESCENDANTS, name = "afterDescendants"),
-            @EnumMap(value = FOCUS_BLOCK_DESCENDANTS, name = "blocksDescendants")
+            @EnumEntry(value = FOCUS_BEFORE_DESCENDANTS, name = "beforeDescendants"),
+            @EnumEntry(value = FOCUS_AFTER_DESCENDANTS, name = "afterDescendants"),
+            @EnumEntry(value = FOCUS_BLOCK_DESCENDANTS, name = "blocksDescendants")
     })
     public int getDescendantFocusability() {
         return mGroupFlags & FLAG_MASK_FOCUSABILITY;
@@ -6574,10 +6574,10 @@
         @ViewDebug.IntToString(from = PERSISTENT_ALL_CACHES,      to = "ALL")
     })
     @InspectableProperty(enumMapping = {
-            @EnumMap(value = PERSISTENT_NO_CACHE, name = "none"),
-            @EnumMap(value = PERSISTENT_ANIMATION_CACHE, name = "animation"),
-            @EnumMap(value = PERSISTENT_SCROLLING_CACHE, name = "scrolling"),
-            @EnumMap(value = PERSISTENT_ALL_CACHES, name = "all"),
+            @EnumEntry(value = PERSISTENT_NO_CACHE, name = "none"),
+            @EnumEntry(value = PERSISTENT_ANIMATION_CACHE, name = "animation"),
+            @EnumEntry(value = PERSISTENT_SCROLLING_CACHE, name = "scrolling"),
+            @EnumEntry(value = PERSISTENT_ALL_CACHES, name = "all"),
     })
     public int getPersistentDrawingCache() {
         return mPersistentDrawingCache;
@@ -6657,8 +6657,8 @@
      * @see #setLayoutMode(int)
      */
     @InspectableProperty(enumMapping = {
-            @EnumMap(value = LAYOUT_MODE_CLIP_BOUNDS, name = "clipBounds"),
-            @EnumMap(value = LAYOUT_MODE_OPTICAL_BOUNDS, name = "opticalBounds")
+            @EnumEntry(value = LAYOUT_MODE_CLIP_BOUNDS, name = "clipBounds"),
+            @EnumEntry(value = LAYOUT_MODE_OPTICAL_BOUNDS, name = "opticalBounds")
     })
     public int getLayoutMode() {
         if (mLayoutMode == LAYOUT_MODE_UNDEFINED) {
@@ -7849,8 +7849,8 @@
             @ViewDebug.IntToString(from = WRAP_CONTENT, to = "WRAP_CONTENT")
         })
         @InspectableProperty(name = "layout_width", enumMapping = {
-                @InspectableProperty.EnumMap(name = "match_parent", value = MATCH_PARENT),
-                @InspectableProperty.EnumMap(name = "wrap_content", value = WRAP_CONTENT)
+                @EnumEntry(name = "match_parent", value = MATCH_PARENT),
+                @EnumEntry(name = "wrap_content", value = WRAP_CONTENT)
         })
         public int width;
 
@@ -7864,8 +7864,8 @@
             @ViewDebug.IntToString(from = WRAP_CONTENT, to = "WRAP_CONTENT")
         })
         @InspectableProperty(name = "layout_height", enumMapping = {
-                @InspectableProperty.EnumMap(name = "match_parent", value = MATCH_PARENT),
-                @InspectableProperty.EnumMap(name = "wrap_content", value = WRAP_CONTENT)
+                @EnumEntry(name = "match_parent", value = MATCH_PARENT),
+                @EnumEntry(name = "wrap_content", value = WRAP_CONTENT)
         })
         public int height;
 
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index a28d662..6d04cd31 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -3987,7 +3987,11 @@
     void systemGestureExclusionChanged() {
         final List<Rect> rectsForWindowManager = mGestureExclusionTracker.computeChangedRects();
         if (rectsForWindowManager != null) {
-            // TODO Send to WM
+            try {
+                mWindowSession.reportSystemGestureExclusionChanged(mWindow, rectsForWindowManager);
+            } catch (RemoteException e) {
+                throw e.rethrowFromSystemServer();
+            }
             mAttachInfo.mTreeObserver
                     .dispatchOnSystemGestureExclusionRectsChanged(rectsForWindowManager);
         }
diff --git a/core/java/android/view/WindowInsets.java b/core/java/android/view/WindowInsets.java
index f1a992c..aac0e34 100644
--- a/core/java/android/view/WindowInsets.java
+++ b/core/java/android/view/WindowInsets.java
@@ -20,14 +20,18 @@
 import static android.view.WindowInsets.Type.FIRST;
 import static android.view.WindowInsets.Type.IME;
 import static android.view.WindowInsets.Type.LAST;
+import static android.view.WindowInsets.Type.MANDATORY_SYSTEM_GESTURES;
 import static android.view.WindowInsets.Type.SIDE_BARS;
 import static android.view.WindowInsets.Type.SIZE;
 import static android.view.WindowInsets.Type.SYSTEM_GESTURES;
+import static android.view.WindowInsets.Type.TAPPABLE_ELEMENT;
 import static android.view.WindowInsets.Type.TOP_BAR;
 import static android.view.WindowInsets.Type.all;
 import static android.view.WindowInsets.Type.compatSystemInsets;
 import static android.view.WindowInsets.Type.indexOf;
+import static android.view.WindowInsets.Type.mandatorySystemGestures;
 import static android.view.WindowInsets.Type.systemGestures;
+import static android.view.WindowInsets.Type.tappableElement;
 
 import android.annotation.IntDef;
 import android.annotation.IntRange;
@@ -223,6 +227,8 @@
         assignCompatInsets(typeInsetMap, insets);
         // TODO: set system gesture insets based on actual system gesture area.
         typeInsetMap[indexOf(systemGestures())] = Insets.of(insets);
+        typeInsetMap[indexOf(mandatorySystemGestures())] = Insets.of(insets);
+        typeInsetMap[indexOf(tappableElement())] = Insets.of(insets);
         return typeInsetMap;
     }
 
@@ -639,15 +645,22 @@
      * priority and may consume some or all touch input, e.g. due to the a system bar
      * occupying it, or it being reserved for touch-only gestures.
      *
+     * <p>An app can declare priority over system gestures with
+     * {@link View#setSystemGestureExclusionRects} outside of the
+     * {@link #getMandatorySystemGestureInsets() mandatory system gesture insets}.
+     *
      * <p>Simple taps are guaranteed to reach the window even within the system gesture insets,
-     * as long as they are outside the {@link #getSystemWindowInsets() system window insets}.
+     * as long as they are outside the {@link #getTappableElementInsets() system window insets}.
      *
      * <p>When {@link View#SYSTEM_UI_FLAG_LAYOUT_STABLE} is requested, an inset will be returned
      * even when the system gestures are inactive due to
      * {@link View#SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN} or
      * {@link View#SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION}.
      *
-     * <p>This inset does not affect the result of {@link #isConsumed()} and cannot be consumed.
+     * <p>This inset is consumed together with the {@link #getSystemWindowInsets()
+     * system window insets} by {@link #consumeSystemWindowInsets()}.
+     *
+     * @see #getMandatorySystemGestureInsets
      */
     @NonNull
     public Insets getSystemGestureInsets() {
@@ -655,6 +668,60 @@
     }
 
     /**
+     * Returns the mandatory system gesture insets.
+     *
+     * <p>The mandatory system gesture insets represent the area of a window where mandatory system
+     * gestures have priority and may consume some or all touch input, e.g. due to the a system bar
+     * occupying it, or it being reserved for touch-only gestures.
+     *
+     * <p>In contrast to {@link #getSystemGestureInsets regular system gestures}, <b>mandatory</b>
+     * system gestures cannot be overriden by {@link View#setSystemGestureExclusionRects}.
+     *
+     * <p>Simple taps are guaranteed to reach the window even within the system gesture insets,
+     * as long as they are outside the {@link #getTappableElementInsets() system window insets}.
+     *
+     * <p>When {@link View#SYSTEM_UI_FLAG_LAYOUT_STABLE} is requested, an inset will be returned
+     * even when the system gestures are inactive due to
+     * {@link View#SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN} or
+     * {@link View#SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION}.
+     *
+     * <p>This inset is consumed together with the {@link #getSystemWindowInsets()
+     * system window insets} by {@link #consumeSystemWindowInsets()}.
+     *
+     * @see #getSystemGestureInsets
+     */
+    @NonNull
+    public Insets getMandatorySystemGestureInsets() {
+        return getInsets(mTypeInsetsMap, MANDATORY_SYSTEM_GESTURES);
+    }
+
+    /**
+     * Returns the tappable element insets.
+     *
+     * <p>The tappable element insets represent how much tappable elements <b>must at least</b> be
+     * inset to remain both tappable and visually unobstructed by persistent system windows.
+     *
+     * <p>This may be smaller than {@link #getSystemWindowInsets()} if the system window is
+     * largely transparent and lets through simple taps (but not necessarily more complex gestures).
+     *
+     * <p>Note that generally, tappable elements <strong>should</strong> be aligned with the
+     * {@link #getSystemWindowInsets() system window insets} instead to avoid overlapping with the
+     * system bars.
+     *
+     * <p>When {@link View#SYSTEM_UI_FLAG_LAYOUT_STABLE} is requested, an inset will be returned
+     * even when the area covered by the inset would be tappable due to
+     * {@link View#SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN} or
+     * {@link View#SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION}.
+     *
+     * <p>This inset is consumed together with the {@link #getSystemWindowInsets()
+     * system window insets} by {@link #consumeSystemWindowInsets()}.
+     */
+    @NonNull
+    public Insets getTappableElementInsets() {
+        return getInsets(mTypeInsetsMap, TAPPABLE_ELEMENT);
+    }
+
+    /**
      * Returns a copy of this WindowInsets with the stable insets fully consumed.
      *
      * @return A modified copy of this WindowInsets
@@ -895,6 +962,41 @@
         }
 
         /**
+         * Sets mandatory system gesture insets in pixels.
+         *
+         * <p>The mandatory system gesture insets represent the area of a window where mandatory
+         * system gestures have priority and may consume some or all touch input, e.g. due to the a
+         * system bar occupying it, or it being reserved for touch-only gestures.
+         *
+         * <p>In contrast to {@link #setSystemGestureInsets regular system gestures},
+         * <b>mandatory</b> system gestures cannot be overriden by
+         * {@link View#setSystemGestureExclusionRects}.
+         *
+         * @see #getMandatorySystemGestureInsets()
+         * @return itself
+         */
+        @NonNull
+        public Builder setMandatorySystemGestureInsets(@NonNull Insets insets) {
+            WindowInsets.setInsets(mTypeInsetsMap, MANDATORY_SYSTEM_GESTURES, insets);
+            return this;
+        }
+
+        /**
+         * Sets tappable element insets in pixels.
+         *
+         * <p>The tappable element insets represent how much tappable elements <b>must at least</b>
+         * be inset to remain both tappable and visually unobstructed by persistent system windows.
+         *
+         * @see #getTappableElementInsets()
+         * @return itself
+         */
+        @NonNull
+        public Builder setTappableElementInsets(@NonNull Insets insets) {
+            WindowInsets.setInsets(mTypeInsetsMap, TAPPABLE_ELEMENT, insets);
+            return this;
+        }
+
+        /**
          * Sets the insets of a specific window type in pixels.
          *
          * <p>The insets represents the area of a a window that is partially or fully obscured by
@@ -1041,16 +1143,18 @@
      */
     public static final class Type {
 
-        static final int FIRST = 0x1;
+        static final int FIRST = 1 << 0;
         static final int TOP_BAR = FIRST;
 
-        static final int IME = 0x2;
-        static final int SIDE_BARS = 0x4;
+        static final int IME = 1 << 1;
+        static final int SIDE_BARS = 1 << 2;
 
-        static final int SYSTEM_GESTURES = 0x8;
+        static final int SYSTEM_GESTURES = 1 << 3;
+        static final int MANDATORY_SYSTEM_GESTURES = 1 << 4;
+        static final int TAPPABLE_ELEMENT = 1 << 5;
 
-        static final int LAST = 0x10;
-        static final int SIZE = 5;
+        static final int LAST = 1 << 6;
+        static final int SIZE = 7;
         static final int WINDOW_DECOR = LAST;
 
         static int indexOf(@InsetType int type) {
@@ -1063,8 +1167,12 @@
                     return 2;
                 case SYSTEM_GESTURES:
                     return 3;
-                case WINDOW_DECOR:
+                case MANDATORY_SYSTEM_GESTURES:
                     return 4;
+                case TAPPABLE_ELEMENT:
+                    return 5;
+                case WINDOW_DECOR:
+                    return 6;
                 default:
                     throw new IllegalArgumentException("type needs to be >= FIRST and <= LAST,"
                             + " type=" + type);
@@ -1076,7 +1184,8 @@
 
         /** @hide */
         @Retention(RetentionPolicy.SOURCE)
-        @IntDef(flag = true, value = { TOP_BAR, IME, SIDE_BARS, WINDOW_DECOR, SYSTEM_GESTURES })
+        @IntDef(flag = true, value = { TOP_BAR, IME, SIDE_BARS, WINDOW_DECOR, SYSTEM_GESTURES,
+                MANDATORY_SYSTEM_GESTURES, TAPPABLE_ELEMENT})
         public @interface InsetType {
         }
 
@@ -1131,6 +1240,20 @@
         }
 
         /**
+         * @see #getMandatorySystemGestureInsets
+         */
+        public static @InsetType int mandatorySystemGestures() {
+            return MANDATORY_SYSTEM_GESTURES;
+        }
+
+        /**
+         * @see #getTappableElementInsets
+         */
+        public static @InsetType int tappableElement() {
+            return TAPPABLE_ELEMENT;
+        }
+
+        /**
          * @return All system bars. Includes {@link #topBar()} as well as {@link #sideBars()}, but
          *         not {@link #ime()}.
          */
diff --git a/core/java/android/view/accessibility/IAccessibilityInteractionConnectionCallback.aidl b/core/java/android/view/accessibility/IAccessibilityInteractionConnectionCallback.aidl
index c1a3ab7..f96f0ac 100644
--- a/core/java/android/view/accessibility/IAccessibilityInteractionConnectionCallback.aidl
+++ b/core/java/android/view/accessibility/IAccessibilityInteractionConnectionCallback.aidl
@@ -33,6 +33,7 @@
      * @param infos The result {@link AccessibilityNodeInfo}.
      * @param interactionId The interaction id to match the result with the request.
      */
+    @UnsupportedAppUsage
     void setFindAccessibilityNodeInfoResult(in AccessibilityNodeInfo info, int interactionId);
 
     /**
@@ -41,6 +42,7 @@
      * @param infos The result {@link AccessibilityNodeInfo}s.
      * @param interactionId The interaction id to match the result with the request.
      */
+    @UnsupportedAppUsage
     void setFindAccessibilityNodeInfosResult(in List<AccessibilityNodeInfo> infos,
         int interactionId);
 
@@ -50,5 +52,6 @@
      * @param Whether the action was performed.
      * @param interactionId The interaction id to match the result with the request.
      */
+    @UnsupportedAppUsage
     void setPerformAccessibilityActionResult(boolean succeeded, int interactionId);
 }
diff --git a/core/java/android/view/accessibility/IAccessibilityManager.aidl b/core/java/android/view/accessibility/IAccessibilityManager.aidl
index 486b35d..0d5c7c9 100644
--- a/core/java/android/view/accessibility/IAccessibilityManager.aidl
+++ b/core/java/android/view/accessibility/IAccessibilityManager.aidl
@@ -42,6 +42,7 @@
 
     List<AccessibilityServiceInfo> getInstalledAccessibilityServiceList(int userId);
 
+    @UnsupportedAppUsage
     List<AccessibilityServiceInfo> getEnabledAccessibilityServiceList(int feedbackType, int userId);
 
     int addAccessibilityInteractionConnection(IWindow windowToken,
diff --git a/core/java/android/view/autofill/AutofillManager.java b/core/java/android/view/autofill/AutofillManager.java
index 604cce5..8cb04cb 100644
--- a/core/java/android/view/autofill/AutofillManager.java
+++ b/core/java/android/view/autofill/AutofillManager.java
@@ -228,6 +228,9 @@
     /** @hide */ public static final int FLAG_ADD_CLIENT_ENABLED = 0x1;
     /** @hide */ public static final int FLAG_ADD_CLIENT_DEBUG = 0x2;
     /** @hide */ public static final int FLAG_ADD_CLIENT_VERBOSE = 0x4;
+
+    /** @hide */ public static final int FLAG_SESSION_FOR_AUGMENTED_AUTOFILL_ONLY = 0x1;
+
     /** @hide */
     public static final int DEFAULT_LOGGING_LEVEL = Build.IS_DEBUGGABLE
             ? AutofillManager.FLAG_ADD_CLIENT_DEBUG
@@ -307,8 +310,8 @@
 
     /**
      * Same as {@link #STATE_UNKNOWN}, but used on
-     * {@link AutofillManagerClient#setSessionFinished(int)} when the session was finished because
-     * the URL bar changed on client mode
+     * {@link AutofillManagerClient#setSessionFinished(int, List)} when the session was finished
+     * because the URL bar changed on client mode
      *
      * @hide
      */
@@ -316,8 +319,8 @@
 
     /**
      * Same as {@link #STATE_UNKNOWN}, but used on
-     * {@link AutofillManagerClient#setSessionFinished(int)} when the session was finished because
-     * the service failed to fullfil a request.
+     * {@link AutofillManagerClient#setSessionFinished(int, List)} when the session was finished
+     * because the service failed to fullfil a request.
      *
      * @hide
      */
@@ -436,7 +439,7 @@
      * There is currently no session running.
      * {@hide}
      */
-    public static final int NO_SESSION = Integer.MIN_VALUE;
+    public static final int NO_SESSION = Integer.MAX_VALUE;
 
     private final IAutoFillManager mService;
 
@@ -513,6 +516,10 @@
     @Nullable
     private final AutofillOptions mOptions;
 
+    /** When set, session is only used for augmented autofill requests. */
+    @GuardedBy("mLock")
+    private boolean mForAugmentedAutofillOnly;
+
     /** @hide */
     public interface AutofillClient {
         /**
@@ -940,9 +947,8 @@
         ensureServiceClientAddedIfNeededLocked();
 
         if (!mEnabled) {
-            if (sVerbose) {
-                Log.v(TAG, "ignoring notifyViewEntered(" + id + "): disabled");
-            }
+            if (sVerbose) Log.v(TAG, "ignoring notifyViewEntered(" + id + "): disabled");
+
             if (mCallback != null) {
                 callback = mCallback;
             }
@@ -1025,6 +1031,12 @@
     private void notifyViewVisibilityChangedInternal(@NonNull View view, int virtualId,
             boolean isVisible, boolean virtual) {
         synchronized (mLock) {
+            if (mForAugmentedAutofillOnly) {
+                if (sVerbose) {
+                    Log.v(TAG,  "notifyViewVisibilityChanged(): ignoring on augmented only mode");
+                }
+                return;
+            }
             if (mEnabled && isActiveLocked()) {
                 final AutofillId id = virtual ? getAutofillId(view, virtualId)
                         : view.getAutofillId();
@@ -1168,6 +1180,10 @@
         AutofillValue value = null;
 
         synchronized (mLock) {
+            if (mForAugmentedAutofillOnly) {
+                if (sVerbose) Log.v(TAG,  "notifyValueChanged(): ignoring on augmented only mode");
+                return;
+            }
             // If the session is gone some fields might still be highlighted, hence we have to
             // remove the isAutofilled property even if no sessions are active.
             if (mLastAutofilledData == null) {
@@ -1221,6 +1237,10 @@
             return;
         }
         synchronized (mLock) {
+            if (mForAugmentedAutofillOnly) {
+                if (sVerbose) Log.v(TAG,  "notifyValueChanged(): ignoring on augmented only mode");
+                return;
+            }
             if (!mEnabled || !isActiveLocked()) {
                 if (sVerbose) {
                     Log.v(TAG, "notifyValueChanged(" + view.getAutofillId() + ":" + virtualId
@@ -1676,14 +1696,20 @@
             if (client == null) return; // NOTE: getClient() already logged it..
 
             final SyncResultReceiver receiver = new SyncResultReceiver(SYNC_CALLS_TIMEOUT_MS);
+            final ComponentName componentName = client.autofillClientGetComponentName();
             mService.startSession(client.autofillClientGetActivityToken(),
                     mServiceClient.asBinder(), id, bounds, value, mContext.getUserId(),
-                    mCallback != null, flags, client.autofillClientGetComponentName(),
+                    mCallback != null, flags, componentName,
                     isCompatibilityModeEnabledLocked(), receiver);
             mSessionId = receiver.getIntResult();
             if (mSessionId != NO_SESSION) {
                 mState = STATE_ACTIVE;
             }
+            final int extraFlags = receiver.getOptionalExtraIntResult(0);
+            if ((extraFlags & FLAG_SESSION_FOR_AUGMENTED_AUTOFILL_ONLY) != 0) {
+                if (sDebug) Log.d(TAG, "startSession(" + componentName + "): for augmented only");
+                mForAugmentedAutofillOnly = true;
+            }
             client.autofillClientResetableStateAvailable();
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
@@ -2400,6 +2426,9 @@
             pw.print(pfx); pw.print("entered ids for augmented autofill: ");
             pw.println(mEnteredForAugmentedAutofillIds);
         }
+        if (mForAugmentedAutofillOnly) {
+            pw.print(pfx); pw.println("For Augmented Autofill Only");
+        }
         pw.print(pfx); pw.print("save trigger id: "); pw.println(mSaveTriggerId);
         pw.print(pfx); pw.print("save on finish(): "); pw.println(mSaveOnFinish);
         if (mOptions != null) {
@@ -3146,6 +3175,10 @@
             if (afm == null) return null;
 
             final View view = afm.getClient().autofillClientFindViewByAutofillIdTraversal(id);
+            if (view == null) {
+                Log.w(TAG, "getViewCoordinates(" + id + "): could not find view");
+                return null;
+            }
             final Rect windowVisibleDisplayFrame = new Rect();
             view.getWindowVisibleDisplayFrame(windowVisibleDisplayFrame);
             final int[] location = new int[2];
diff --git a/core/java/android/view/contentcapture/ContentCaptureContext.java b/core/java/android/view/contentcapture/ContentCaptureContext.java
index 019ebff..5a27e94 100644
--- a/core/java/android/view/contentcapture/ContentCaptureContext.java
+++ b/core/java/android/view/contentcapture/ContentCaptureContext.java
@@ -161,7 +161,7 @@
     /**
      * Gets the context id.
      */
-    @NonNull
+    @Nullable
     public LocusId getLocusId() {
         return mId;
     }
diff --git a/core/java/android/view/inspector/InspectableNodeName.java b/core/java/android/view/inspector/InspectableNodeName.java
deleted file mode 100644
index 7b9a507..0000000
--- a/core/java/android/view/inspector/InspectableNodeName.java
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Copyright 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.view.inspector;
-
-import static java.lang.annotation.ElementType.TYPE;
-import static java.lang.annotation.RetentionPolicy.SOURCE;
-
-import android.annotation.TestApi;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.Target;
-
-/**
- * Marks the node name to display to a developer in the inspection tree.
- *
- * This annotation is optional to marking a class as inspectable. If it is omitted, the node name
- * will be inferred using the semantics of {@link Class#getSimpleName()}. The fully qualified class
- * name is always available in the tree, this is for display purposes only. If a class is inflated
- * from XML and the tag it inflates from does not match its simple name, this annotation should be
- * used to inform the inspector to display the XML tag name in the inspection tree view.
- *
- * This annotation does not inherit. If a class extends an annotated parent class, but does not
- * annotate itself, its node name will be inferred from its Java name.
- *
- * @see InspectionCompanion#getNodeName()
- * @hide
- */
-@Target({TYPE})
-@Retention(SOURCE)
-@TestApi
-public @interface InspectableNodeName {
-    /**
-     * The display name for nodes of this type.
-     *
-     * @return The name for nodes of this type
-     */
-    String value();
-}
diff --git a/core/java/android/view/inspector/InspectableProperty.java b/core/java/android/view/inspector/InspectableProperty.java
index 97ede86..03f1ec5 100644
--- a/core/java/android/view/inspector/InspectableProperty.java
+++ b/core/java/android/view/inspector/InspectableProperty.java
@@ -87,21 +87,21 @@
      *
      * Note that {@link #enumMapping()} cannot be used simultaneously with {@link #flagMapping()}.
      *
-     * @return An array of {@link EnumMap}, empty if not applicable
+     * @return An array of {@link EnumEntry}, empty if not applicable
      * @see android.annotation.IntDef
      */
-    EnumMap[] enumMapping() default {};
+    EnumEntry[] enumMapping() default {};
 
     /**
      * For flags packed into primitive {int} properties, model the string names of the flags.
      *
      * Note that {@link #flagMapping()} cannot be used simultaneously with {@link #enumMapping()}.
      *
-     * @return An array of {@link FlagMap}, empty if not applicable
+     * @return An array of {@link FlagEntry}, empty if not applicable
      * @see android.annotation.IntDef
      * @see IntFlagMapping
      */
-    FlagMap[] flagMapping() default {};
+    FlagEntry[] flagMapping() default {};
 
 
     /**
@@ -113,7 +113,7 @@
     @Target({TYPE})
     @Retention(SOURCE)
     @TestApi
-    @interface EnumMap {
+    @interface EnumEntry {
         /**
          * The string name of this enumeration value.
          *
@@ -138,7 +138,7 @@
     @Target({TYPE})
     @Retention(SOURCE)
     @TestApi
-    @interface FlagMap {
+    @interface FlagEntry {
         /**
          * The string name of this flag.
          *
@@ -195,7 +195,7 @@
          *
          * This is inferred if {@link #enumMapping()} is specified.
          *
-         * @see EnumMap
+         * @see EnumEntry
          * @hide
          */
         @TestApi
@@ -206,7 +206,7 @@
          *
          * This is inferred if {@link #flagMapping()} is specified.
          *
-         * @see FlagMap
+         * @see FlagEntry
          * @hide
          */
         @TestApi
@@ -227,7 +227,7 @@
         /**
          * Value packs gravity information.
          *
-         * This type is not inferred, and is non-trivial to represent using {@link FlagMap}.
+         * This type is not inferred, and is non-trivial to represent using {@link FlagEntry}.
          *
          * @see android.view.Gravity
          * @hide
diff --git a/core/java/android/view/inspector/InspectionCompanion.java b/core/java/android/view/inspector/InspectionCompanion.java
index 62d769b..a633a58 100644
--- a/core/java/android/view/inspector/InspectionCompanion.java
+++ b/core/java/android/view/inspector/InspectionCompanion.java
@@ -17,7 +17,6 @@
 package android.view.inspector;
 
 import android.annotation.NonNull;
-import android.annotation.Nullable;
 
 /**
  * An interface for companion objects used to inspect views.
@@ -33,11 +32,6 @@
  * parent class via the parent's inspection companion, and the child companion will only read
  * properties added or changed since the parent was defined.
  *
- * Only one child traversal is considered for each class. If a descendant class defines a
- * different child traversal than its parent, only the bottom traversal is used. If a class does
- * not define its own child traversal, but one of its ancestors does, the bottom-most ancestor's
- * traversal will be used.
- *
  * @param <T> The type of inspectable this is the companion to
  */
 public interface InspectionCompanion<T> {
@@ -68,22 +62,6 @@
     void readProperties(@NonNull T inspectable, @NonNull PropertyReader propertyReader);
 
     /**
-     * Get an optional name to display to developers for inspection nodes of this companion's type.
-     *
-     * The default implementation returns null, which will cause the runtime to use the class's
-     * simple name as defined by {@link Class#getSimpleName()} as the node name.
-     *
-     * If the type of this companion is inflated from XML, this method should be overridden to
-     * return the string used as the tag name for this type in XML.
-     *
-     * @return A string to use as the node name, or null to use the simple class name fallback.
-     */
-    @Nullable
-    default String getNodeName() {
-        return null;
-    }
-
-    /**
      * Thrown by {@link #readProperties(Object, PropertyReader)} if called before
      * {@link #mapProperties(PropertyMapper)}.
      */
diff --git a/core/java/android/view/textclassifier/TextClassifierImpl.java b/core/java/android/view/textclassifier/TextClassifierImpl.java
index 8f5f0a37..cb44f79 100644
--- a/core/java/android/view/textclassifier/TextClassifierImpl.java
+++ b/core/java/android/view/textclassifier/TextClassifierImpl.java
@@ -177,8 +177,7 @@
                 final String localesString = concatenateLocales(request.getDefaultLocales());
                 final String detectLanguageTags = detectLanguageTagsFromText(request.getText());
                 final ZonedDateTime refTime = ZonedDateTime.now();
-                final AnnotatorModel annotatorImpl =
-                        getAnnotatorImpl(request.getDefaultLocales());
+                final AnnotatorModel annotatorImpl = getAnnotatorImpl(request.getDefaultLocales());
                 final int start;
                 final int end;
                 if (mSettings.isModelDarkLaunchEnabled() && !request.isDarkLaunchAllowed()) {
@@ -417,7 +416,8 @@
                             nativeConversation,
                             null,
                             mContext,
-                            getResourceLocalesString());
+                            getResourceLocalesString(),
+                            getAnnotatorImpl(LocaleList.getDefault()));
             return createConversationActionResult(request, nativeSuggestions);
         } catch (Throwable t) {
             // Avoid throwing from this method. Log the error.
@@ -583,8 +583,7 @@
                         new File(bestModel.getPath()), ParcelFileDescriptor.MODE_READ_ONLY);
                 try {
                     if (pfd != null) {
-                        mActionsImpl = new ActionsSuggestionsModel(
-                                pfd.getFd(), getAnnotatorImpl(LocaleList.getDefault()));
+                        mActionsImpl = new ActionsSuggestionsModel(pfd.getFd());
                         mActionModelInUse = bestModel;
                     }
                 } finally {
diff --git a/core/java/android/webkit/WebSettings.java b/core/java/android/webkit/WebSettings.java
index 494eb03..a46580d 100644
--- a/core/java/android/webkit/WebSettings.java
+++ b/core/java/android/webkit/WebSettings.java
@@ -245,10 +245,11 @@
     /**
      * Used with {@link #setForceDark}
      *
-     * Enable force dark, dependent on the state of the WebView parent. If the WebView parent view
-     * is being automatically rendered in dark mode, then WebView content will be rendered so as to
-     * emulate a dark theme. WebViews that are not attached to the view hierarchy will not be
-     * inverted.
+     * Enable force dark dependent on the state of the WebView parent view. If the WebView parent
+     * view is being automatically force darkened
+     * (see: {@link android.view.View#setForceDarkAllowed}), then WebView content will be rendered
+     * so as to emulate a dark theme. WebViews that are not attached to the view hierarchy will not
+     * be inverted.
      */
     public static final int FORCE_DARK_AUTO = 1;
 
@@ -1466,6 +1467,8 @@
 
     /**
      * Set the force dark mode for this WebView.
+     *
+     * @param forceDark the force dark mode to set.
      */
     public void setForceDark(@ForceDark int forceDark) {
         // Stub implementation to satisfy Roboelectrc shadows that don't override this yet.
@@ -1474,6 +1477,8 @@
     /**
      * Get the force dark mode for this WebView.
      *
+     * The default force dark mode is {@link #FORCE_DARK_AUTO}
+     *
      * @return the currently set force dark mode.
      */
     public @ForceDark int getForceDark() {
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 034cabd..26dba45 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -2292,9 +2292,9 @@
      * @return the requested renderer priority policy.
      */
     @InspectableProperty(hasAttributeId = false, enumMapping = {
-            @InspectableProperty.EnumMap(name = "waived", value = RENDERER_PRIORITY_WAIVED),
-            @InspectableProperty.EnumMap(name = "bound", value = RENDERER_PRIORITY_BOUND),
-            @InspectableProperty.EnumMap(name = "important", value = RENDERER_PRIORITY_IMPORTANT)
+            @InspectableProperty.EnumEntry(name = "waived", value = RENDERER_PRIORITY_WAIVED),
+            @InspectableProperty.EnumEntry(name = "bound", value = RENDERER_PRIORITY_BOUND),
+            @InspectableProperty.EnumEntry(name = "important", value = RENDERER_PRIORITY_IMPORTANT)
     })
     @RendererPriority
     public int getRendererRequestedPriority() {
diff --git a/core/java/android/webkit/WebViewFactory.java b/core/java/android/webkit/WebViewFactory.java
index 6d88530..4413585 100644
--- a/core/java/android/webkit/WebViewFactory.java
+++ b/core/java/android/webkit/WebViewFactory.java
@@ -448,8 +448,9 @@
 
             Trace.traceBegin(Trace.TRACE_TAG_WEBVIEW, "WebViewFactory.getChromiumProviderClass()");
             try {
-                initialApplication.getAssets().addAssetPathAsSharedLibrary(
-                        webViewContext.getApplicationInfo().sourceDir);
+                for (String newAssetPath : webViewContext.getApplicationInfo().getAllApkPaths()) {
+                    initialApplication.getAssets().addAssetPathAsSharedLibrary(newAssetPath);
+                }
                 ClassLoader clazzLoader = webViewContext.getClassLoader();
 
                 Trace.traceBegin(Trace.TRACE_TAG_WEBVIEW, "WebViewFactory.loadNativeLibrary()");
diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java
index 24f1fb5..4cb552d 100644
--- a/core/java/android/widget/AbsListView.java
+++ b/core/java/android/widget/AbsListView.java
@@ -83,7 +83,7 @@
 import android.view.inputmethod.InputContentInfo;
 import android.view.inputmethod.InputMethodManager;
 import android.view.inspector.InspectableProperty;
-import android.view.inspector.InspectableProperty.EnumMap;
+import android.view.inspector.InspectableProperty.EnumEntry;
 import android.widget.RemoteViews.OnClickHandler;
 
 import com.android.internal.R;
@@ -1221,10 +1221,10 @@
      * @return The current choice mode
      */
     @InspectableProperty(enumMapping = {
-            @EnumMap(value = CHOICE_MODE_NONE, name = "none"),
-            @EnumMap(value = CHOICE_MODE_SINGLE, name = "singleChoice"),
-            @EnumMap(value = CHOICE_MODE_MULTIPLE, name = "multipleChoice"),
-            @EnumMap(value = CHOICE_MODE_MULTIPLE_MODAL, name = "multipleChoiceModal")
+            @EnumEntry(value = CHOICE_MODE_NONE, name = "none"),
+            @EnumEntry(value = CHOICE_MODE_SINGLE, name = "singleChoice"),
+            @InspectableProperty.EnumEntry(value = CHOICE_MODE_MULTIPLE, name = "multipleChoice"),
+            @EnumEntry(value = CHOICE_MODE_MULTIPLE_MODAL, name = "multipleChoiceModal")
     })
     public int getChoiceMode() {
         return mChoiceMode;
@@ -6293,9 +6293,9 @@
      *         {@link #TRANSCRIPT_MODE_ALWAYS_SCROLL}
      */
     @InspectableProperty(enumMapping = {
-            @EnumMap(value = TRANSCRIPT_MODE_DISABLED, name = "disabled"),
-            @EnumMap(value = TRANSCRIPT_MODE_NORMAL, name = "normal"),
-            @EnumMap(value = TRANSCRIPT_MODE_ALWAYS_SCROLL, name = "alwaysScroll")
+            @EnumEntry(value = TRANSCRIPT_MODE_DISABLED, name = "disabled"),
+            @EnumEntry(value = TRANSCRIPT_MODE_NORMAL, name = "normal"),
+            @EnumEntry(value = TRANSCRIPT_MODE_ALWAYS_SCROLL, name = "alwaysScroll")
     })
     public int getTranscriptMode() {
         return mTranscriptMode;
diff --git a/core/java/android/widget/DatePicker.java b/core/java/android/widget/DatePicker.java
index ecb846b..0c593be 100644
--- a/core/java/android/widget/DatePicker.java
+++ b/core/java/android/widget/DatePicker.java
@@ -216,8 +216,8 @@
      * @hide Visible for testing only.
      */
     @InspectableProperty(name = "datePickerMode", enumMapping = {
-            @InspectableProperty.EnumMap(value = MODE_SPINNER, name = "spinner"),
-            @InspectableProperty.EnumMap(value = MODE_CALENDAR, name = "calendar")
+            @InspectableProperty.EnumEntry(value = MODE_SPINNER, name = "spinner"),
+            @InspectableProperty.EnumEntry(value = MODE_CALENDAR, name = "calendar")
     })
     @DatePickerMode
     @TestApi
diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java
index b6ec5f9..c9ef038 100644
--- a/core/java/android/widget/Editor.java
+++ b/core/java/android/widget/Editor.java
@@ -4984,9 +4984,6 @@
             if (magnifierTopLeft == null) {
                 return;
             }
-            final Rect surfaceInsets =
-                    mTextView.getViewRootImpl().mWindowAttributes.surfaceInsets;
-            magnifierTopLeft.offset(-surfaceInsets.left, -surfaceInsets.top);
             final Rect magnifierRect = new Rect(magnifierTopLeft.x, magnifierTopLeft.y,
                     magnifierTopLeft.x + mMagnifierAnimator.mMagnifier.getWidth(),
                     magnifierTopLeft.y + mMagnifierAnimator.mMagnifier.getHeight());
diff --git a/core/java/android/widget/GridLayout.java b/core/java/android/widget/GridLayout.java
index 1c8bb04..8cda47d 100644
--- a/core/java/android/widget/GridLayout.java
+++ b/core/java/android/widget/GridLayout.java
@@ -331,8 +331,8 @@
      */
     @Orientation
     @InspectableProperty(enumMapping = {
-            @InspectableProperty.EnumMap(value = HORIZONTAL, name = "horizontal"),
-            @InspectableProperty.EnumMap(value = VERTICAL, name = "vertical")
+            @InspectableProperty.EnumEntry(value = HORIZONTAL, name = "horizontal"),
+            @InspectableProperty.EnumEntry(value = VERTICAL, name = "vertical")
     })
     public int getOrientation() {
         return mOrientation;
@@ -510,8 +510,8 @@
      */
     @AlignmentMode
     @InspectableProperty(enumMapping = {
-            @InspectableProperty.EnumMap(value = ALIGN_BOUNDS, name = "alignBounds"),
-            @InspectableProperty.EnumMap(value = ALIGN_MARGINS, name = "alignMargins"),
+            @InspectableProperty.EnumEntry(value = ALIGN_BOUNDS, name = "alignBounds"),
+            @InspectableProperty.EnumEntry(value = ALIGN_MARGINS, name = "alignMargins"),
     })
     public int getAlignmentMode() {
         return mAlignmentMode;
diff --git a/core/java/android/widget/GridView.java b/core/java/android/widget/GridView.java
index f44c331..4e39a55 100644
--- a/core/java/android/widget/GridView.java
+++ b/core/java/android/widget/GridView.java
@@ -2174,11 +2174,11 @@
 
     @StretchMode
     @InspectableProperty(enumMapping = {
-            @InspectableProperty.EnumMap(value = NO_STRETCH, name = "none"),
-            @InspectableProperty.EnumMap(value = STRETCH_SPACING, name = "spacingWidth"),
-            @InspectableProperty.EnumMap(
+            @InspectableProperty.EnumEntry(value = NO_STRETCH, name = "none"),
+            @InspectableProperty.EnumEntry(value = STRETCH_SPACING, name = "spacingWidth"),
+            @InspectableProperty.EnumEntry(
                     value = STRETCH_SPACING_UNIFORM, name = "spacingWidthUniform"),
-            @InspectableProperty.EnumMap(value = STRETCH_COLUMN_WIDTH, name = "columnWidth"),
+            @InspectableProperty.EnumEntry(value = STRETCH_COLUMN_WIDTH, name = "columnWidth"),
     })
     public int getStretchMode() {
         return mStretchMode;
diff --git a/core/java/android/widget/LinearLayout.java b/core/java/android/widget/LinearLayout.java
index bdde435..a83e826 100644
--- a/core/java/android/widget/LinearLayout.java
+++ b/core/java/android/widget/LinearLayout.java
@@ -1850,8 +1850,8 @@
      */
     @OrientationMode
     @InspectableProperty(enumMapping = {
-            @InspectableProperty.EnumMap(value = HORIZONTAL, name = "horizontal"),
-            @InspectableProperty.EnumMap(value = VERTICAL, name = "vertical")
+            @InspectableProperty.EnumEntry(value = HORIZONTAL, name = "horizontal"),
+            @InspectableProperty.EnumEntry(value = VERTICAL, name = "vertical")
     })
     public int getOrientation() {
         return mOrientation;
diff --git a/core/java/android/widget/Magnifier.java b/core/java/android/widget/Magnifier.java
index 50e8836..08799cf 100644
--- a/core/java/android/widget/Magnifier.java
+++ b/core/java/android/widget/Magnifier.java
@@ -471,13 +471,13 @@
     }
 
     /**
-     * Returns the top left coordinates of the magnifier, relative to the surface of the
-     * main application window. They will be determined by the coordinates of the last
-     * {@link #show(float, float)} or {@link #show(float, float, float, float)} call, adjusted
-     * to take into account any potential clamping behavior. The method can be used immediately
-     * after a #show call to find out where the magnifier will be positioned. However, the
-     * position of the magnifier will not be updated in the same frame due to the async
-     * copying of the content copying and of the magnifier rendering.
+     * Returns the top left coordinates of the magnifier, relative to the main application
+     * window. They will be determined by the coordinates of the last {@link #show(float, float)}
+     * or {@link #show(float, float, float, float)} call, adjusted to take into account any
+     * potential clamping behavior. The method can be used immediately after a #show
+     * call to find out where the magnifier will be positioned. However, the position of the
+     * magnifier will not be updated visually in the same frame, due to the async nature of
+     * the content copying and of the magnifier rendering.
      * The method will return {@code null} if #show has not yet been called, or if the last
      * operation performed was a #dismiss.
      *
@@ -488,15 +488,18 @@
         if (mWindow == null) {
             return null;
         }
-        return new Point(getCurrentClampedWindowCoordinates());
+        final Point position = getCurrentClampedWindowCoordinates();
+        position.offset(-mParentSurface.mInsets.left, -mParentSurface.mInsets.top);
+        return new Point(position);
     }
 
     /**
      * Returns the top left coordinates of the magnifier source (i.e. the view region going to
-     * be magnified and copied to the magnifier), relative to the surface the content is copied
-     * from. The content will be copied:
+     * be magnified and copied to the magnifier), relative to the window or surface the content
+     * is copied from. The content will be copied:
      * - if the magnified view is a {@link SurfaceView}, from the surface backing it
-     * - otherwise, from the surface of the main application window
+     * - otherwise, from the surface backing the main application window, and the coordinates
+     *   returned will be relative to the main application window
      * The method will return {@code null} if #show has not yet been called, or if the last
      * operation performed was a #dismiss.
      *
@@ -507,7 +510,9 @@
         if (mWindow == null) {
             return null;
         }
-        return new Point(mPixelCopyRequestRect.left, mPixelCopyRequestRect.top);
+        final Point position = new Point(mPixelCopyRequestRect.left, mPixelCopyRequestRect.top);
+        position.offset(-mContentCopySurface.mInsets.left, -mContentCopySurface.mInsets.top);
+        return new Point(position);
     }
 
     /**
@@ -531,7 +536,7 @@
                         viewRootImpl.getHeight() + surfaceInsets.top + surfaceInsets.bottom;
                 validMainWindowSurface =
                         new SurfaceInfo(viewRootImpl.getSurfaceControl(), mainWindowSurface,
-                                surfaceWidth, surfaceHeight, true);
+                                surfaceWidth, surfaceHeight, surfaceInsets, true);
             }
         }
         // Get the surface backing the magnified view, if it is a SurfaceView.
@@ -544,7 +549,7 @@
             if (sc != null && sc.isValid()) {
                 final Rect surfaceFrame = surfaceHolder.getSurfaceFrame();
                 validSurfaceViewSurface = new SurfaceInfo(sc, surfaceViewSurface,
-                        surfaceFrame.right, surfaceFrame.bottom, false);
+                        surfaceFrame.right, surfaceFrame.bottom, new Rect(), false);
             }
         }
 
@@ -708,9 +713,13 @@
         final Rect windowBounds;
         if (mParentSurface.mIsMainWindowSurface) {
             final Insets systemInsets = mView.getRootWindowInsets().getSystemWindowInsets();
-            windowBounds = new Rect(systemInsets.left, systemInsets.top,
-                    mParentSurface.mWidth - systemInsets.right,
-                    mParentSurface.mHeight - systemInsets.bottom);
+            windowBounds = new Rect(
+                    systemInsets.left + mParentSurface.mInsets.left,
+                    systemInsets.top + mParentSurface.mInsets.top,
+                    mParentSurface.mWidth - systemInsets.right - mParentSurface.mInsets.right,
+                    mParentSurface.mHeight - systemInsets.bottom
+                            - mParentSurface.mInsets.bottom
+            );
         } else {
             windowBounds = new Rect(0, 0, mParentSurface.mWidth, mParentSurface.mHeight);
         }
@@ -725,21 +734,23 @@
      * Contains a surface and metadata corresponding to it.
      */
     private static class SurfaceInfo {
-        public static final SurfaceInfo NULL = new SurfaceInfo(null, null, 0, 0, false);
+        public static final SurfaceInfo NULL = new SurfaceInfo(null, null, 0, 0, null, false);
 
         private Surface mSurface;
         private SurfaceControl mSurfaceControl;
         private int mWidth;
         private int mHeight;
+        private Rect mInsets;
         private boolean mIsMainWindowSurface;
 
         SurfaceInfo(final SurfaceControl surfaceControl, final Surface surface,
-                final int width, final int height,
+                final int width, final int height, final Rect insets,
                 final boolean isMainWindowSurface) {
             mSurfaceControl = surfaceControl;
             mSurface = surface;
             mWidth = width;
             mHeight = height;
+            mInsets = insets;
             mIsMainWindowSurface = isMainWindowSurface;
         }
     }
diff --git a/core/java/android/widget/TEST_MAPPING b/core/java/android/widget/TEST_MAPPING
new file mode 100644
index 0000000..ee378ff
--- /dev/null
+++ b/core/java/android/widget/TEST_MAPPING
@@ -0,0 +1,12 @@
+{
+  "presubmit": [
+    {
+      "name": "CtsWidgetTestCases",
+      "options": [
+        {
+          "instrumentation-arg": "size:=small"
+        }
+      ]
+    }
+  ]
+}
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 04bcb14..a5a1a80c 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -173,8 +173,8 @@
 import android.view.inputmethod.InputConnection;
 import android.view.inputmethod.InputMethodManager;
 import android.view.inspector.InspectableProperty;
-import android.view.inspector.InspectableProperty.EnumMap;
-import android.view.inspector.InspectableProperty.FlagMap;
+import android.view.inspector.InspectableProperty.EnumEntry;
+import android.view.inspector.InspectableProperty.FlagEntry;
 import android.view.textclassifier.TextClassification;
 import android.view.textclassifier.TextClassificationContext;
 import android.view.textclassifier.TextClassificationManager;
@@ -1900,8 +1900,8 @@
      * @see #setAutoSizeTextTypeUniformWithPresetSizes(int[], int)
      */
     @InspectableProperty(enumMapping = {
-            @EnumMap(name = "none", value = AUTO_SIZE_TEXT_TYPE_NONE),
-            @EnumMap(name = "uniform", value = AUTO_SIZE_TEXT_TYPE_UNIFORM)
+            @EnumEntry(name = "none", value = AUTO_SIZE_TEXT_TYPE_NONE),
+            @EnumEntry(name = "uniform", value = AUTO_SIZE_TEXT_TYPE_UNIFORM)
     })
     @AutoSizeTextType
     public int getAutoSizeTextType() {
@@ -3527,10 +3527,10 @@
      * @attr ref android.R.styleable#TextView_autoLink
      */
     @InspectableProperty(name = "autoLink", flagMapping = {
-            @FlagMap(name = "web", target = Linkify.WEB_URLS),
-            @FlagMap(name = "email", target = Linkify.EMAIL_ADDRESSES),
-            @FlagMap(name = "phone", target = Linkify.PHONE_NUMBERS),
-            @FlagMap(name = "map", target = Linkify.MAP_ADDRESSES)
+            @FlagEntry(name = "web", target = Linkify.WEB_URLS),
+            @FlagEntry(name = "email", target = Linkify.EMAIL_ADDRESSES),
+            @FlagEntry(name = "phone", target = Linkify.PHONE_NUMBERS),
+            @FlagEntry(name = "map", target = Linkify.MAP_ADDRESSES)
     })
     public final int getAutoLinkMask() {
         return mAutoLinkMask;
@@ -4515,9 +4515,9 @@
      * @see #setBreakStrategy(int)
      */
     @InspectableProperty(enumMapping = {
-            @EnumMap(name = "simple", value = Layout.BREAK_STRATEGY_SIMPLE),
-            @EnumMap(name = "high_quality", value = Layout.BREAK_STRATEGY_HIGH_QUALITY),
-            @EnumMap(name = "balanced", value = Layout.BREAK_STRATEGY_BALANCED)
+            @EnumEntry(name = "simple", value = Layout.BREAK_STRATEGY_SIMPLE),
+            @EnumEntry(name = "high_quality", value = Layout.BREAK_STRATEGY_HIGH_QUALITY),
+            @EnumEntry(name = "balanced", value = Layout.BREAK_STRATEGY_BALANCED)
     })
     @Layout.BreakStrategy
     public int getBreakStrategy() {
@@ -4566,9 +4566,9 @@
      * @see #setHyphenationFrequency(int)
      */
     @InspectableProperty(enumMapping = {
-            @EnumMap(name = "none", value = Layout.HYPHENATION_FREQUENCY_NONE),
-            @EnumMap(name = "normal", value = Layout.HYPHENATION_FREQUENCY_NORMAL),
-            @EnumMap(name = "full", value = Layout.HYPHENATION_FREQUENCY_FULL)
+            @EnumEntry(name = "none", value = Layout.HYPHENATION_FREQUENCY_NONE),
+            @EnumEntry(name = "normal", value = Layout.HYPHENATION_FREQUENCY_NORMAL),
+            @EnumEntry(name = "full", value = Layout.HYPHENATION_FREQUENCY_FULL)
     })
     @Layout.HyphenationFrequency
     public int getHyphenationFrequency() {
@@ -4628,8 +4628,8 @@
      * @see #setJustificationMode(int)
      */
     @InspectableProperty(enumMapping = {
-            @EnumMap(name = "none", value = Layout.JUSTIFICATION_MODE_NONE),
-            @EnumMap(name = "inter_word", value = Layout.JUSTIFICATION_MODE_INTER_WORD)
+            @EnumEntry(name = "none", value = Layout.JUSTIFICATION_MODE_NONE),
+            @EnumEntry(name = "inter_word", value = Layout.JUSTIFICATION_MODE_INTER_WORD)
     })
     public @Layout.JustificationMode int getJustificationMode() {
         return mJustificationMode;
@@ -6667,142 +6667,142 @@
      * @see android.text.InputType
      */
     @InspectableProperty(flagMapping = {
-            @FlagMap(name = "none", mask = 0xffffffff, target = InputType.TYPE_NULL),
-            @FlagMap(
+            @FlagEntry(name = "none", mask = 0xffffffff, target = InputType.TYPE_NULL),
+            @FlagEntry(
                     name = "text",
                     mask = InputType.TYPE_MASK_CLASS | InputType.TYPE_MASK_VARIATION,
                     target = InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_NORMAL),
-            @FlagMap(
+            @FlagEntry(
                     name = "textUri",
                     mask = InputType.TYPE_MASK_CLASS | InputType.TYPE_MASK_VARIATION,
                     target = InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_URI),
-            @FlagMap(
+            @FlagEntry(
                     name = "textEmailAddress",
                     mask = InputType.TYPE_MASK_CLASS | InputType.TYPE_MASK_VARIATION,
                     target = InputType.TYPE_CLASS_TEXT
                             | InputType.TYPE_TEXT_VARIATION_EMAIL_ADDRESS),
-            @FlagMap(
+            @FlagEntry(
                     name = "textEmailSubject",
                     mask = InputType.TYPE_MASK_CLASS | InputType.TYPE_MASK_VARIATION,
                     target = InputType.TYPE_CLASS_TEXT
                             | InputType.TYPE_TEXT_VARIATION_EMAIL_SUBJECT),
-            @FlagMap(
+            @FlagEntry(
                     name = "textShortMessage",
                     mask = InputType.TYPE_MASK_CLASS | InputType.TYPE_MASK_VARIATION,
                     target = InputType.TYPE_CLASS_TEXT
                             | InputType.TYPE_TEXT_VARIATION_SHORT_MESSAGE),
-            @FlagMap(
+            @FlagEntry(
                     name = "textLongMessage",
                     mask = InputType.TYPE_MASK_CLASS | InputType.TYPE_MASK_VARIATION,
                     target = InputType.TYPE_CLASS_TEXT
                             | InputType.TYPE_TEXT_VARIATION_LONG_MESSAGE),
-            @FlagMap(
+            @FlagEntry(
                     name = "textPersonName",
                     mask = InputType.TYPE_MASK_CLASS | InputType.TYPE_MASK_VARIATION,
                     target = InputType.TYPE_CLASS_TEXT
                             | InputType.TYPE_TEXT_VARIATION_PERSON_NAME),
-            @FlagMap(
+            @FlagEntry(
                     name = "textPostalAddress",
                     mask = InputType.TYPE_MASK_CLASS | InputType.TYPE_MASK_VARIATION,
                     target = InputType.TYPE_CLASS_TEXT
                             | InputType.TYPE_TEXT_VARIATION_POSTAL_ADDRESS),
-            @FlagMap(
+            @FlagEntry(
                     name = "textPassword",
                     mask = InputType.TYPE_MASK_CLASS | InputType.TYPE_MASK_VARIATION,
                     target = InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_PASSWORD),
-            @FlagMap(
+            @FlagEntry(
                     name = "textVisiblePassword",
                     mask = InputType.TYPE_MASK_CLASS | InputType.TYPE_MASK_VARIATION,
                     target = InputType.TYPE_CLASS_TEXT
                             | InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD),
-            @FlagMap(
+            @FlagEntry(
                     name = "textWebEditText",
                     mask = InputType.TYPE_MASK_CLASS | InputType.TYPE_MASK_VARIATION,
                     target = InputType.TYPE_CLASS_TEXT
                             | InputType.TYPE_TEXT_VARIATION_WEB_EDIT_TEXT),
-            @FlagMap(
+            @FlagEntry(
                     name = "textFilter",
                     mask = InputType.TYPE_MASK_CLASS | InputType.TYPE_MASK_VARIATION,
                     target = InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_FILTER),
-            @FlagMap(
+            @FlagEntry(
                     name = "textPhonetic",
                     mask = InputType.TYPE_MASK_CLASS | InputType.TYPE_MASK_VARIATION,
                     target = InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_PHONETIC),
-            @FlagMap(
+            @FlagEntry(
                     name = "textWebEmailAddress",
                     mask = InputType.TYPE_MASK_CLASS | InputType.TYPE_MASK_VARIATION,
                     target = InputType.TYPE_CLASS_TEXT
                             | InputType.TYPE_TEXT_VARIATION_WEB_EMAIL_ADDRESS),
-            @FlagMap(
+            @FlagEntry(
                     name = "textWebPassword",
                     mask = InputType.TYPE_MASK_CLASS | InputType.TYPE_MASK_VARIATION,
                     target = InputType.TYPE_CLASS_TEXT
                             | InputType.TYPE_TEXT_VARIATION_WEB_PASSWORD),
-            @FlagMap(
+            @FlagEntry(
                     name = "number",
                     mask = InputType.TYPE_MASK_CLASS | InputType.TYPE_MASK_VARIATION,
                     target = InputType.TYPE_CLASS_NUMBER | InputType.TYPE_NUMBER_VARIATION_NORMAL),
-            @FlagMap(
+            @FlagEntry(
                     name = "numberPassword",
                     mask = InputType.TYPE_MASK_CLASS | InputType.TYPE_MASK_VARIATION,
                     target = InputType.TYPE_CLASS_NUMBER
                             | InputType.TYPE_NUMBER_VARIATION_PASSWORD),
-            @FlagMap(
+            @FlagEntry(
                     name = "phone",
                     mask = InputType.TYPE_MASK_CLASS | InputType.TYPE_MASK_VARIATION,
                     target = InputType.TYPE_CLASS_PHONE),
-            @FlagMap(
+            @FlagEntry(
                     name = "datetime",
                     mask = InputType.TYPE_MASK_CLASS | InputType.TYPE_MASK_VARIATION,
                     target = InputType.TYPE_CLASS_DATETIME
                             | InputType.TYPE_DATETIME_VARIATION_NORMAL),
-            @FlagMap(
+            @FlagEntry(
                     name = "date",
                     mask = InputType.TYPE_MASK_CLASS | InputType.TYPE_MASK_VARIATION,
                     target = InputType.TYPE_CLASS_DATETIME
                             | InputType.TYPE_DATETIME_VARIATION_DATE),
-            @FlagMap(
+            @FlagEntry(
                     name = "time",
                     mask = InputType.TYPE_MASK_CLASS | InputType.TYPE_MASK_VARIATION,
                     target = InputType.TYPE_CLASS_DATETIME
                             | InputType.TYPE_DATETIME_VARIATION_TIME),
-            @FlagMap(
+            @FlagEntry(
                     name = "textCapCharacters",
                     mask = InputType.TYPE_MASK_CLASS | InputType.TYPE_MASK_FLAGS,
                     target = InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_FLAG_CAP_CHARACTERS),
-            @FlagMap(
+            @FlagEntry(
                     name = "textCapWords",
                     mask = InputType.TYPE_MASK_CLASS | InputType.TYPE_MASK_FLAGS,
                     target = InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_FLAG_CAP_WORDS),
-            @FlagMap(
+            @FlagEntry(
                     name = "textCapSentences",
                     mask = InputType.TYPE_MASK_CLASS | InputType.TYPE_MASK_FLAGS,
                     target = InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_FLAG_CAP_SENTENCES),
-            @FlagMap(
+            @FlagEntry(
                     name = "textAutoCorrect",
                     mask = InputType.TYPE_MASK_CLASS | InputType.TYPE_MASK_FLAGS,
                     target = InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_FLAG_AUTO_CORRECT),
-            @FlagMap(
+            @FlagEntry(
                     name = "textAutoComplete",
                     mask = InputType.TYPE_MASK_CLASS | InputType.TYPE_MASK_FLAGS,
                     target = InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_FLAG_AUTO_COMPLETE),
-            @FlagMap(
+            @FlagEntry(
                     name = "textMultiLine",
                     mask = InputType.TYPE_MASK_CLASS | InputType.TYPE_MASK_FLAGS,
                     target = InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_FLAG_MULTI_LINE),
-            @FlagMap(
+            @FlagEntry(
                     name = "textImeMultiLine",
                     mask = InputType.TYPE_MASK_CLASS | InputType.TYPE_MASK_FLAGS,
                     target = InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_FLAG_IME_MULTI_LINE),
-            @FlagMap(
+            @FlagEntry(
                     name = "textNoSuggestions",
                     mask = InputType.TYPE_MASK_CLASS | InputType.TYPE_MASK_FLAGS,
                     target = InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS),
-            @FlagMap(
+            @FlagEntry(
                     name = "numberSigned",
                     mask = InputType.TYPE_MASK_CLASS | InputType.TYPE_MASK_FLAGS,
                     target = InputType.TYPE_CLASS_NUMBER | InputType.TYPE_NUMBER_FLAG_SIGNED),
-            @FlagMap(
+            @FlagEntry(
                     name = "numberDecimal",
                     mask = InputType.TYPE_MASK_CLASS | InputType.TYPE_MASK_FLAGS,
                     target = InputType.TYPE_CLASS_NUMBER | InputType.TYPE_NUMBER_FLAG_DECIMAL),
@@ -6832,49 +6832,51 @@
      * @see EditorInfo
      */
     @InspectableProperty(flagMapping = {
-            @FlagMap(name = "normal", mask = 0xffffffff, target = EditorInfo.IME_NULL),
-            @FlagMap(
+            @FlagEntry(name = "normal", mask = 0xffffffff, target = EditorInfo.IME_NULL),
+            @FlagEntry(
                     name = "actionUnspecified",
                     mask = EditorInfo.IME_MASK_ACTION,
                     target = EditorInfo.IME_ACTION_UNSPECIFIED),
-            @FlagMap(
+            @FlagEntry(
                     name = "actionNone",
                     mask = EditorInfo.IME_MASK_ACTION,
                     target = EditorInfo.IME_ACTION_NONE),
-            @FlagMap(
+            @FlagEntry(
                     name = "actionGo",
                     mask = EditorInfo.IME_MASK_ACTION,
                     target = EditorInfo.IME_ACTION_GO),
-            @FlagMap(
+            @FlagEntry(
                     name = "actionSearch",
                     mask = EditorInfo.IME_MASK_ACTION,
                     target = EditorInfo.IME_ACTION_SEARCH),
-            @FlagMap(
+            @FlagEntry(
                     name = "actionSend",
                     mask = EditorInfo.IME_MASK_ACTION,
                     target = EditorInfo.IME_ACTION_SEND),
-            @FlagMap(
+            @FlagEntry(
                     name = "actionNext",
                     mask = EditorInfo.IME_MASK_ACTION,
                     target = EditorInfo.IME_ACTION_NEXT),
-            @FlagMap(
+            @FlagEntry(
                     name = "actionDone",
                     mask = EditorInfo.IME_MASK_ACTION,
                     target = EditorInfo.IME_ACTION_DONE),
-            @FlagMap(
+            @FlagEntry(
                     name = "actionPrevious",
                     mask = EditorInfo.IME_MASK_ACTION,
                     target = EditorInfo.IME_ACTION_PREVIOUS),
-            @FlagMap(name = "flagForceAscii", target = EditorInfo.IME_FLAG_FORCE_ASCII),
-            @FlagMap(name = "flagNavigateNext", target = EditorInfo.IME_FLAG_NAVIGATE_NEXT),
-            @FlagMap(name = "flagNavigatePrevious", target = EditorInfo.IME_FLAG_NAVIGATE_PREVIOUS),
-            @FlagMap(
+            @FlagEntry(name = "flagForceAscii", target = EditorInfo.IME_FLAG_FORCE_ASCII),
+            @FlagEntry(name = "flagNavigateNext", target = EditorInfo.IME_FLAG_NAVIGATE_NEXT),
+            @FlagEntry(
+                    name = "flagNavigatePrevious",
+                    target = EditorInfo.IME_FLAG_NAVIGATE_PREVIOUS),
+            @FlagEntry(
                     name = "flagNoAccessoryAction",
                     target = EditorInfo.IME_FLAG_NO_ACCESSORY_ACTION),
-            @FlagMap(name = "flagNoEnterAction", target = EditorInfo.IME_FLAG_NO_ENTER_ACTION),
-            @FlagMap(name = "flagNoExtractUi", target = EditorInfo.IME_FLAG_NO_EXTRACT_UI),
-            @FlagMap(name = "flagNoFullscreen", target = EditorInfo.IME_FLAG_NO_FULLSCREEN),
-            @FlagMap(
+            @FlagEntry(name = "flagNoEnterAction", target = EditorInfo.IME_FLAG_NO_ENTER_ACTION),
+            @FlagEntry(name = "flagNoExtractUi", target = EditorInfo.IME_FLAG_NO_EXTRACT_UI),
+            @FlagEntry(name = "flagNoFullscreen", target = EditorInfo.IME_FLAG_NO_FULLSCREEN),
+            @FlagEntry(
                     name = "flagNoPersonalizedLearning",
                     target = EditorInfo.IME_FLAG_NO_PERSONALIZED_LEARNING),
     })
diff --git a/core/java/android/widget/TimePicker.java b/core/java/android/widget/TimePicker.java
index c7a2980..8a5d531 100644
--- a/core/java/android/widget/TimePicker.java
+++ b/core/java/android/widget/TimePicker.java
@@ -169,8 +169,8 @@
     @TimePickerMode
     @TestApi
     @InspectableProperty(name = "timePickerMode", enumMapping = {
-            @InspectableProperty.EnumMap(name = "clock", value = MODE_CLOCK),
-            @InspectableProperty.EnumMap(name = "spinner", value = MODE_SPINNER)
+            @InspectableProperty.EnumEntry(name = "clock", value = MODE_CLOCK),
+            @InspectableProperty.EnumEntry(name = "spinner", value = MODE_SPINNER)
     })
     public int getMode() {
         return mMode;
diff --git a/core/java/com/android/internal/app/AbstractResolverComparator.java b/core/java/com/android/internal/app/AbstractResolverComparator.java
new file mode 100644
index 0000000..3576b6b
--- /dev/null
+++ b/core/java/com/android/internal/app/AbstractResolverComparator.java
@@ -0,0 +1,63 @@
+package com.android.internal.app;
+
+import android.content.ComponentName;
+import com.android.internal.app.ResolverActivity.ResolvedComponentInfo;
+import java.util.Comparator;
+import java.util.List;
+
+/**
+ * Used to sort resolved activities in {@link ResolverListController}.
+ */
+abstract class AbstractResolverComparator implements Comparator<ResolvedComponentInfo> {
+
+    protected AfterCompute mAfterCompute;
+
+    /**
+     * Callback to be called when {@link #compute(List)} finishes. This signals to stop waiting.
+     */
+    public interface AfterCompute {
+
+        public void afterCompute();
+    }
+
+    public void setCallBack(AfterCompute afterCompute) {
+        mAfterCompute = afterCompute;
+    }
+
+    /**
+     * Computes features for each target. This will be called before calls to {@link
+     * #getScore(ComponentName)} or {@link #compare(Object, Object)}, in order to prepare the
+     * comparator for those calls. Note that {@link #getScore(ComponentName)} uses {@link
+     * ComponentName}, so the implementation will have to be prepared to identify a {@link
+     * ResolvedComponentInfo} by {@link ComponentName}.
+     */
+    public abstract void compute(List<ResolvedComponentInfo> targets);
+
+    /**
+     * Returns the score that was calculated for the corresponding {@link ResolvedComponentInfo}
+     * when {@link #compute(List)} was called before this.
+     */
+    public abstract float getScore(ComponentName name);
+
+    /**
+     * Reports to UsageStats what was chosen.
+     */
+    // TODO(b/129014961) Move implemetation here and make final.
+    public abstract void updateChooserCounts(String packageName, int userId, String action);
+
+    /**
+     * Updates the model used to rank the componentNames.
+     *
+     * <p>Default implementation does nothing, as we could have simple model that does not train
+     * online.
+     *
+     * @param componentName the component that the user clicked
+     */
+    public void updateModel(ComponentName componentName) {
+    }
+
+    /**
+     * Called when the {@link ResolverActivity} is destroyed.
+     */
+    public abstract void destroy();
+}
diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java
index f250666..faf0c7d 100644
--- a/core/java/com/android/internal/app/ChooserActivity.java
+++ b/core/java/com/android/internal/app/ChooserActivity.java
@@ -680,7 +680,7 @@
                             & DocumentsContract.Document.FLAG_SUPPORTS_THUMBNAIL) != 0;
                 }
             }
-        } catch (SecurityException e) {
+        } catch (SecurityException | NullPointerException e) {
             Log.w(TAG, "Error loading file preview", e);
         }
 
@@ -918,6 +918,8 @@
         if (isSendAction(in)) {
             in.addFlags(Intent.FLAG_ACTIVITY_NEW_DOCUMENT |
                     Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
+
+            in.fixUris(getUserId());
         }
     }
 
diff --git a/core/java/com/android/internal/app/IAppOpsService.aidl b/core/java/com/android/internal/app/IAppOpsService.aidl
index c4af4c7..1c90182 100644
--- a/core/java/com/android/internal/app/IAppOpsService.aidl
+++ b/core/java/com/android/internal/app/IAppOpsService.aidl
@@ -79,4 +79,6 @@
     void stopWatchingNoted(IAppOpsNotedCallback callback);
 
     int checkOperationRaw(int code, int uid, String packageName);
+
+    void reloadNonHistoricalState();
 }
diff --git a/core/java/com/android/internal/app/ResolverListController.java b/core/java/com/android/internal/app/ResolverListController.java
index f48102a..156baf0 100644
--- a/core/java/com/android/internal/app/ResolverListController.java
+++ b/core/java/com/android/internal/app/ResolverListController.java
@@ -55,7 +55,7 @@
     private static final String TAG = "ResolverListController";
     private static final boolean DEBUG = false;
 
-    private ResolverComparator mResolverComparator;
+    private AbstractResolverComparator mResolverComparator;
     private boolean isComputed = false;
 
     public ResolverListController(
@@ -70,7 +70,8 @@
         mTargetIntent = targetIntent;
         mReferrerPackage = referrerPackage;
         mResolverComparator =
-                new ResolverComparator(mContext, mTargetIntent, mReferrerPackage, null);
+                new ResolverRankerServiceResolverComparator(
+                    mContext, mTargetIntent, mReferrerPackage, null);
     }
 
     @VisibleForTesting
@@ -221,7 +222,7 @@
         return listToReturn;
     }
 
-    private class ComputeCallback implements ResolverComparator.AfterCompute {
+    private class ComputeCallback implements AbstractResolverComparator.AfterCompute {
 
         private CountDownLatch mFinishComputeSignal;
 
diff --git a/core/java/com/android/internal/app/ResolverComparator.java b/core/java/com/android/internal/app/ResolverRankerServiceResolverComparator.java
similarity index 96%
rename from core/java/com/android/internal/app/ResolverComparator.java
rename to core/java/com/android/internal/app/ResolverRankerServiceResolverComparator.java
index b9f67e6..a88a80f 100644
--- a/core/java/com/android/internal/app/ResolverComparator.java
+++ b/core/java/com/android/internal/app/ResolverRankerServiceResolverComparator.java
@@ -46,7 +46,6 @@
 
 import java.text.Collator;
 import java.util.ArrayList;
-import java.util.Comparator;
 import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
@@ -54,10 +53,10 @@
 import java.util.concurrent.TimeUnit;
 
 /**
- * Ranks and compares packages based on usage stats.
+ * Ranks and compares packages based on usage stats and uses the {@link ResolverRankerService}.
  */
-class ResolverComparator implements Comparator<ResolvedComponentInfo> {
-    private static final String TAG = "ResolverComparator";
+class ResolverRankerServiceResolverComparator extends AbstractResolverComparator {
+    private static final String TAG = "RRSResolverComparator";
 
     private static final boolean DEBUG = false;
 
@@ -100,7 +99,6 @@
     private ComponentName mRankerServiceName;
     private IResolverRankerService mRanker;
     private ResolverRankerServiceConnection mConnection;
-    private AfterCompute mAfterCompute;
     private Context mContext;
     private CountDownLatch mConnectSignal;
 
@@ -155,12 +153,8 @@
         }
     };
 
-    public interface AfterCompute {
-        public void afterCompute ();
-    }
-
-    public ResolverComparator(Context context, Intent intent, String referrerPackage,
-                              AfterCompute afterCompute) {
+    public ResolverRankerServiceResolverComparator(Context context, Intent intent,
+                String referrerPackage, AfterCompute afterCompute) {
         mCollator = Collator.getInstance(context.getResources().getConfiguration().locale);
         String scheme = intent.getScheme();
         mHttp = "http".equals(scheme) || "https".equals(scheme);
@@ -185,7 +179,7 @@
     }
 
     // get annotations of content from intent.
-    public void getContentAnnotations(Intent intent) {
+    private void getContentAnnotations(Intent intent) {
         ArrayList<String> annotations = intent.getStringArrayListExtra(
                 Intent.EXTRA_CONTENT_ANNOTATIONS);
         if (annotations != null) {
@@ -200,11 +194,8 @@
         }
     }
 
-    public void setCallBack(AfterCompute afterCompute) {
-        mAfterCompute = afterCompute;
-    }
-
     // compute features for each target according to usage stats of targets.
+    @Override
     public void compute(List<ResolvedComponentInfo> targets) {
         reset();
 
@@ -349,6 +340,7 @@
         return mCollator.compare(sa.toString().trim(), sb.toString().trim());
     }
 
+    @Override
     public float getScore(ComponentName name) {
         final ResolverTarget target = mTargetsDict.get(name);
         if (target != null) {
@@ -357,6 +349,7 @@
         return 0;
     }
 
+    @Override
     public void updateChooserCounts(String packageName, int userId, String action) {
         if (mUsm != null) {
             mUsm.reportChooserSelection(packageName, userId, mContentType, mAnnotations, action);
@@ -364,6 +357,7 @@
     }
 
     // update ranking model when the connection to it is valid.
+    @Override
     public void updateModel(ComponentName componentName) {
         synchronized (mLock) {
             if (mRanker != null) {
@@ -397,6 +391,7 @@
     }
 
     // unbind the service and clear unhandled messges.
+    @Override
     public void destroy() {
         mHandler.removeMessages(RESOLVER_RANKER_SERVICE_RESULT);
         mHandler.removeMessages(RESOLVER_RANKER_RESULT_TIMEOUT);
@@ -478,8 +473,8 @@
                 if (!ResolverRankerService.BIND_PERMISSION.equals(perm)) {
                     Log.w(TAG, "ResolverRankerService " + componentName + " does not require"
                             + " permission " + ResolverRankerService.BIND_PERMISSION
-                            + " - this service will not be queried for ResolverComparator."
-                            + " add android:permission=\""
+                            + " - this service will not be queried for "
+                            + "ResolverRankerServiceResolverComparator. add android:permission=\""
                             + ResolverRankerService.BIND_PERMISSION + "\""
                             + " to the <service> tag for " + componentName
                             + " in the manifest.");
@@ -490,7 +485,8 @@
                         resolveInfo.serviceInfo.packageName)) {
                     Log.w(TAG, "ResolverRankerService " + componentName + " does not hold"
                             + " permission " + ResolverRankerService.HOLD_PERMISSION
-                            + " - this service will not be queried for ResolverComparator.");
+                            + " - this service will not be queried for "
+                            + "ResolverRankerServiceResolverComparator.");
                     continue;
                 }
             } catch (NameNotFoundException e) {
diff --git a/core/java/com/android/internal/backup/IBackupTransport.aidl b/core/java/com/android/internal/backup/IBackupTransport.aidl
index f8117a7..c9baf00 100644
--- a/core/java/com/android/internal/backup/IBackupTransport.aidl
+++ b/core/java/com/android/internal/backup/IBackupTransport.aidl
@@ -79,14 +79,14 @@
     Intent dataManagementIntent();
 
     /**
-     * On demand, supply a short string that can be shown to the user as the label
-     * on an overflow menu item used to invoked the data management UI.
+     * On demand, supply a short {@link CharSequence} that can be shown to the user as the label on
+     * an overflow menu item used to invoke the data management UI.
      *
-     * @return A string to be used as the label for the transport's data management
+     * @return A {@link CharSequence} to be used as the label for the transport's data management
      *         affordance.  If the transport supplies a data management intent, this
      *         method must not return {@code null}.
      */
-    String dataManagementLabel();
+    CharSequence dataManagementIntentLabel();
 
     /**
      * Ask the transport where, on local device storage, to keep backup state blobs.
diff --git a/core/java/com/android/internal/infra/AbstractRemoteService.java b/core/java/com/android/internal/infra/AbstractRemoteService.java
index eb881de..5c144d3 100644
--- a/core/java/com/android/internal/infra/AbstractRemoteService.java
+++ b/core/java/com/android/internal/infra/AbstractRemoteService.java
@@ -577,6 +577,12 @@
         protected boolean isFinal() {
             return false;
         }
+
+        protected boolean isRequestCompleted() {
+            synchronized (mLock) {
+                return mCompleted;
+            }
+        }
     }
 
     /**
diff --git a/core/java/com/android/internal/os/BatteryStatsHelper.java b/core/java/com/android/internal/os/BatteryStatsHelper.java
index ead98e7..e85508e 100644
--- a/core/java/com/android/internal/os/BatteryStatsHelper.java
+++ b/core/java/com/android/internal/os/BatteryStatsHelper.java
@@ -368,6 +368,11 @@
 
     public void refreshStats(int statsType, SparseArray<UserHandle> asUsers, long rawRealtimeUs,
             long rawUptimeUs) {
+        if (statsType != BatteryStats.STATS_SINCE_CHARGED) {
+            Log.w(TAG, "refreshStats called for statsType " + statsType + " but only "
+                    + "STATS_SINCE_CHARGED is supported. Using STATS_SINCE_CHARGED instead.");
+        }
+
         // Initialize mStats if necessary.
         getStats();
 
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index 8679dcb..1fc7635 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -145,7 +145,7 @@
     private static final int MAGIC = 0xBA757475; // 'BATSTATS'
 
     // Current on-disk Parcel version
-    static final int VERSION = 185 + (USE_OLD_HISTORY ? 1000 : 0);
+    static final int VERSION = 186 + (USE_OLD_HISTORY ? 1000 : 0);
 
     // The maximum number of names wakelocks we will keep track of
     // per uid; once the limit is reached, we batch the remaining wakelocks
@@ -991,8 +991,6 @@
     private int mPhoneSimStateRaw = -1;
 
     private int mNumConnectivityChange;
-    private int mLoadedNumConnectivityChange;
-    private int mUnpluggedNumConnectivityChange;
 
     private int mEstimatedBatteryCapacity = -1;
 
@@ -1225,27 +1223,11 @@
         }
 
         public long computeUptime(long curTime, int which) {
-            switch (which) {
-                case STATS_SINCE_CHARGED:
-                    return mUptime + getUptime(curTime);
-                case STATS_CURRENT:
-                    return getUptime(curTime);
-                case STATS_SINCE_UNPLUGGED:
-                    return getUptime(curTime) - mUnpluggedUptime;
-            }
-            return 0;
+            return mUptime + getUptime(curTime);
         }
 
         public long computeRealtime(long curTime, int which) {
-            switch (which) {
-                case STATS_SINCE_CHARGED:
-                    return mRealtime + getRealtime(curTime);
-                case STATS_CURRENT:
-                    return getRealtime(curTime);
-                case STATS_SINCE_UNPLUGGED:
-                    return getRealtime(curTime) - mUnpluggedRealtime;
-            }
-            return 0;
+            return mRealtime + getRealtime(curTime);
         }
 
         public long getUptime(long curTime) {
@@ -1352,16 +1334,10 @@
         @UnsupportedAppUsage
         final AtomicInteger mCount = new AtomicInteger();
         final TimeBase mTimeBase;
-        int mLoadedCount;
-        int mUnpluggedCount;
-        int mPluggedCount;
 
         public Counter(TimeBase timeBase, Parcel in) {
             mTimeBase = timeBase;
-            mPluggedCount = in.readInt();
-            mCount.set(mPluggedCount);
-            mLoadedCount = in.readInt();
-            mUnpluggedCount = in.readInt();
+            mCount.set(in.readInt());
             timeBase.add(this);
         }
 
@@ -1372,18 +1348,14 @@
 
         public void writeToParcel(Parcel out) {
             out.writeInt(mCount.get());
-            out.writeInt(mLoadedCount);
-            out.writeInt(mUnpluggedCount);
         }
 
         @Override
         public void onTimeStarted(long elapsedRealtime, long baseUptime, long baseRealtime) {
-            mUnpluggedCount = mPluggedCount;
         }
 
         @Override
         public void onTimeStopped(long elapsedRealtime, long baseUptime, long baseRealtime) {
-            mPluggedCount = mCount.get();
         }
 
         /**
@@ -1417,21 +1389,11 @@
 
         @Override
         public int getCountLocked(int which) {
-            int val = mCount.get();
-            if (which == STATS_SINCE_UNPLUGGED) {
-                val -= mUnpluggedCount;
-            } else if (which != STATS_SINCE_CHARGED) {
-                val -= mLoadedCount;
-            }
-
-            return val;
+            return mCount.get();
         }
 
         public void logState(Printer pw, String prefix) {
-            pw.println(prefix + "mCount=" + mCount.get()
-                    + " mLoadedCount=" + mLoadedCount
-                    + " mUnpluggedCount=" + mUnpluggedCount
-                    + " mPluggedCount=" + mPluggedCount);
+            pw.println(prefix + "mCount=" + mCount.get());
         }
 
         @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
@@ -1453,7 +1415,6 @@
         @Override
         public boolean reset(boolean detachIfReset) {
             mCount.set(0);
-            mLoadedCount = mPluggedCount = mUnpluggedCount = 0;
             if (detachIfReset) {
                 detach();
             }
@@ -1467,15 +1428,12 @@
 
         @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
         public void writeSummaryFromParcelLocked(Parcel out) {
-            int count = mCount.get();
-            out.writeInt(count);
+            out.writeInt(mCount.get());
         }
 
         @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
         public void readSummaryFromParcelLocked(Parcel in) {
-            mLoadedCount = in.readInt();
-            mCount.set(mLoadedCount);
-            mUnpluggedCount = mPluggedCount = mLoadedCount;
+            mCount.set(in.readInt());
         }
     }
 
@@ -1483,14 +1441,10 @@
     public static class LongSamplingCounterArray extends LongCounterArray implements TimeBaseObs {
         final TimeBase mTimeBase;
         public long[] mCounts;
-        public long[] mLoadedCounts;
-        public long[] mUnpluggedCounts;
 
         private LongSamplingCounterArray(TimeBase timeBase, Parcel in) {
             mTimeBase = timeBase;
             mCounts = in.createLongArray();
-            mLoadedCounts = in.createLongArray();
-            mUnpluggedCounts = in.createLongArray();
             timeBase.add(this);
         }
 
@@ -1501,13 +1455,10 @@
 
         private void writeToParcel(Parcel out) {
             out.writeLongArray(mCounts);
-            out.writeLongArray(mLoadedCounts);
-            out.writeLongArray(mUnpluggedCounts);
         }
 
         @Override
         public void onTimeStarted(long elapsedRealTime, long baseUptime, long baseRealtime) {
-            mUnpluggedCounts = copyArray(mCounts, mUnpluggedCounts);
         }
 
         @Override
@@ -1516,20 +1467,12 @@
 
         @Override
         public long[] getCountsLocked(int which) {
-            long[] val = copyArray(mCounts, null);
-            if (which == STATS_SINCE_UNPLUGGED) {
-                subtract(val, mUnpluggedCounts);
-            } else if (which != STATS_SINCE_CHARGED) {
-                subtract(val, mLoadedCounts);
-            }
-            return val;
+            return mCounts == null ? null : Arrays.copyOf(mCounts, mCounts.length);
         }
 
         @Override
         public void logState(Printer pw, String prefix) {
-            pw.println(prefix + "mCounts=" + Arrays.toString(mCounts)
-                    + " mLoadedCounts=" + Arrays.toString(mLoadedCounts)
-                    + " mUnpluggedCounts=" + Arrays.toString(mUnpluggedCounts));
+            pw.println(prefix + "mCounts=" + Arrays.toString(mCounts));
         }
 
         public void addCountLocked(long[] counts) {
@@ -1559,9 +1502,9 @@
          */
         @Override
         public boolean reset(boolean detachIfReset) {
-            fillArray(mCounts, 0);
-            fillArray(mLoadedCounts, 0);
-            fillArray(mUnpluggedCounts, 0);
+            if (mCounts != null) {
+                Arrays.fill(mCounts, 0);
+            }
             if (detachIfReset) {
                 detach();
             }
@@ -1579,8 +1522,6 @@
 
         private void readSummaryFromParcelLocked(Parcel in) {
             mCounts = in.createLongArray();
-            mLoadedCounts = copyArray(mCounts, mLoadedCounts);
-            mUnpluggedCounts = copyArray(mCounts, mUnpluggedCounts);
         }
 
         public static void writeToParcel(Parcel out, LongSamplingCounterArray counterArray) {
@@ -1621,49 +1562,16 @@
                 return null;
             }
         }
-
-        private static void fillArray(long[] a, long val) {
-            if (a != null) {
-                Arrays.fill(a, val);
-            }
-        }
-
-        private static void subtract(@NonNull long[] val, long[] toSubtract) {
-            if (toSubtract == null) {
-                return;
-            }
-            for (int i = 0; i < val.length; i++) {
-                val[i] -= toSubtract[i];
-            }
-        }
-
-        private static long[] copyArray(long[] src, long[] dest) {
-            if (src == null) {
-                return null;
-            } else {
-                if (dest == null) {
-                    dest = new long[src.length];
-                }
-                System.arraycopy(src, 0, dest, 0, src.length);
-                return dest;
-            }
-        }
     }
 
     @VisibleForTesting
     public static class LongSamplingCounter extends LongCounter implements TimeBaseObs {
         final TimeBase mTimeBase;
-        public long mCount;
-        public long mCurrentCount;
-        public long mLoadedCount;
-        public long mUnpluggedCount;
+        private long mCount;
 
         public LongSamplingCounter(TimeBase timeBase, Parcel in) {
             mTimeBase = timeBase;
             mCount = in.readLong();
-            mCurrentCount = in.readLong();
-            mLoadedCount = in.readLong();
-            mUnpluggedCount = in.readLong();
             timeBase.add(this);
         }
 
@@ -1674,14 +1582,10 @@
 
         public void writeToParcel(Parcel out) {
             out.writeLong(mCount);
-            out.writeLong(mCurrentCount);
-            out.writeLong(mLoadedCount);
-            out.writeLong(mUnpluggedCount);
         }
 
         @Override
         public void onTimeStarted(long elapsedRealtime, long baseUptime, long baseRealtime) {
-            mUnpluggedCount = mCount;
         }
 
         @Override
@@ -1689,43 +1593,22 @@
         }
 
         public long getCountLocked(int which) {
-            long val = mCount;
-            if (which == STATS_SINCE_UNPLUGGED) {
-                val -= mUnpluggedCount;
-            } else if (which != STATS_SINCE_CHARGED) {
-                val -= mLoadedCount;
-            }
-            return val;
+            return mCount;
         }
 
         @Override
         public void logState(Printer pw, String prefix) {
-            pw.println(prefix + "mCount=" + mCount
-                    + " mCurrentCount=" + mCurrentCount
-                    + " mLoadedCount=" + mLoadedCount
-                    + " mUnpluggedCount=" + mUnpluggedCount);
+            pw.println(prefix + "mCount=" + mCount);
         }
 
         public void addCountLocked(long count) {
-            update(mCurrentCount + count, mTimeBase.isRunning());
+            addCountLocked(count, mTimeBase.isRunning());
         }
 
         public void addCountLocked(long count, boolean isRunning) {
-            update(mCurrentCount + count, isRunning);
-        }
-
-        public void update(long count) {
-            update(count, mTimeBase.isRunning());
-        }
-
-        public void update(long count, boolean isRunning) {
-            if (count < mCurrentCount) {
-                mCurrentCount = 0;
-            }
             if (isRunning) {
-                mCount += count - mCurrentCount;
+                mCount += count;
             }
-            mCurrentCount = count;
         }
 
         /**
@@ -1734,7 +1617,6 @@
         @Override
         public boolean reset(boolean detachIfReset) {
             mCount = 0;
-            mLoadedCount = mUnpluggedCount = 0;
             if (detachIfReset) {
                 detach();
             }
@@ -1751,7 +1633,7 @@
         }
 
         public void readSummaryFromParcelLocked(Parcel in) {
-            mCount = mUnpluggedCount= mLoadedCount = in.readLong();
+            mCount = in.readLong();
         }
     }
 
@@ -1764,9 +1646,6 @@
         protected final TimeBase mTimeBase;
 
         protected int mCount;
-        protected int mLoadedCount;
-        protected int mLastCount;
-        protected int mUnpluggedCount;
 
         // Times are in microseconds for better accuracy when dividing by the
         // lock count, and are in "battery realtime" units.
@@ -1779,25 +1658,6 @@
         protected long mTotalTime;
 
         /**
-         * The total time we loaded for the previous runs.  Subtract this from
-         * mTotalTime to find the time for the current run of the system.
-         */
-        protected long mLoadedTime;
-
-        /**
-         * The run time of the last run of the system, as loaded from the
-         * saved data.
-         */
-        protected long mLastTime;
-
-        /**
-         * The value of mTotalTime when unplug() was last called.  Subtract
-         * this from mTotalTime to find the time since the last unplug from
-         * power.
-         */
-        protected long mUnpluggedTime;
-
-        /**
          * The total time this timer has been running until the latest mark has been set.
          * Subtract this from mTotalTime to get the time spent running since the mark was set.
          */
@@ -1815,13 +1675,7 @@
             mTimeBase = timeBase;
 
             mCount = in.readInt();
-            mLoadedCount = in.readInt();
-            mLastCount = 0;
-            mUnpluggedCount = in.readInt();
             mTotalTime = in.readLong();
-            mLoadedTime = in.readLong();
-            mLastTime = 0;
-            mUnpluggedTime = in.readLong();
             mTimeBeforeMark = in.readLong();
             timeBase.add(this);
             if (DEBUG) Log.i(TAG, "**** READ TIMER #" + mType + ": mTotalTime=" + mTotalTime);
@@ -1834,6 +1688,16 @@
             timeBase.add(this);
         }
 
+        public void writeToParcel(Parcel out, long elapsedRealtimeUs) {
+            if (DEBUG) {
+                Log.i(TAG, "**** WRITING TIMER #" + mType + ": mTotalTime="
+                        + computeRunTimeLocked(mTimeBase.getRealtime(elapsedRealtimeUs)));
+            }
+            out.writeInt(computeCurrentCountLocked());
+            out.writeLong(computeRunTimeLocked(mTimeBase.getRealtime(elapsedRealtimeUs)));
+            out.writeLong(mTimeBeforeMark);
+        }
+
         protected abstract long computeRunTimeLocked(long curBatteryRealtime);
 
         protected abstract int computeCurrentCountLocked();
@@ -1844,8 +1708,8 @@
          */
         @Override
         public boolean reset(boolean detachIfReset) {
-            mTotalTime = mLoadedTime = mLastTime = mTimeBeforeMark = 0;
-            mCount = mLoadedCount = mLastCount = 0;
+            mTotalTime = mTimeBeforeMark = 0;
+            mCount = 0;
             if (detachIfReset) {
                 detach();
             }
@@ -1857,32 +1721,8 @@
             mTimeBase.remove(this);
         }
 
-        public void writeToParcel(Parcel out, long elapsedRealtimeUs) {
-            if (DEBUG) Log.i(TAG, "**** WRITING TIMER #" + mType + ": mTotalTime="
-                    + computeRunTimeLocked(mTimeBase.getRealtime(elapsedRealtimeUs)));
-            out.writeInt(computeCurrentCountLocked());
-            out.writeInt(mLoadedCount);
-            out.writeInt(mUnpluggedCount);
-            out.writeLong(computeRunTimeLocked(mTimeBase.getRealtime(elapsedRealtimeUs)));
-            out.writeLong(mLoadedTime);
-            out.writeLong(mUnpluggedTime);
-            out.writeLong(mTimeBeforeMark);
-        }
-
         @Override
         public void onTimeStarted(long elapsedRealtime, long timeBaseUptime, long baseRealtime) {
-            if (DEBUG && mType < 0) {
-                Log.v(TAG, "unplug #" + mType + ": realtime=" + baseRealtime
-                        + " old mUnpluggedTime=" + mUnpluggedTime
-                        + " old mUnpluggedCount=" + mUnpluggedCount);
-            }
-            mUnpluggedTime = computeRunTimeLocked(baseRealtime);
-            mUnpluggedCount = computeCurrentCountLocked();
-            if (DEBUG && mType < 0) {
-                Log.v(TAG, "unplug #" + mType
-                        + ": new mUnpluggedTime=" + mUnpluggedTime
-                        + " new mUnpluggedCount=" + mUnpluggedCount);
-            }
         }
 
         @Override
@@ -1894,8 +1734,7 @@
             mTotalTime = computeRunTimeLocked(baseRealtime);
             mCount = computeCurrentCountLocked();
             if (DEBUG && mType < 0) {
-                Log.v(TAG, "plug #" + mType
-                        + ": new mTotalTime=" + mTotalTime);
+                Log.v(TAG, "plug #" + mType + ": new mTotalTime=" + mTotalTime);
             }
         }
 
@@ -1912,34 +1751,19 @@
                 return;
             }
             out.writeInt(1); // indicates non-null
-
             timer.writeToParcel(out, elapsedRealtimeUs);
         }
 
         @Override
         @UnsupportedAppUsage
         public long getTotalTimeLocked(long elapsedRealtimeUs, int which) {
-            long val = computeRunTimeLocked(mTimeBase.getRealtime(elapsedRealtimeUs));
-            if (which == STATS_SINCE_UNPLUGGED) {
-                val -= mUnpluggedTime;
-            } else if (which != STATS_SINCE_CHARGED) {
-                val -= mLoadedTime;
-            }
-
-            return val;
+            return computeRunTimeLocked(mTimeBase.getRealtime(elapsedRealtimeUs));
         }
 
         @Override
         @UnsupportedAppUsage
         public int getCountLocked(int which) {
-            int val = computeCurrentCountLocked();
-            if (which == STATS_SINCE_UNPLUGGED) {
-                val -= mUnpluggedCount;
-            } else if (which != STATS_SINCE_CHARGED) {
-                val -= mLoadedCount;
-            }
-
-            return val;
+            return computeCurrentCountLocked();
         }
 
         @Override
@@ -1950,13 +1774,8 @@
 
         @Override
         public void logState(Printer pw, String prefix) {
-            pw.println(prefix + "mCount=" + mCount
-                    + " mLoadedCount=" + mLoadedCount + " mLastCount=" + mLastCount
-                    + " mUnpluggedCount=" + mUnpluggedCount);
-            pw.println(prefix + "mTotalTime=" + mTotalTime
-                    + " mLoadedTime=" + mLoadedTime);
-            pw.println(prefix + "mLastTime=" + mLastTime
-                    + " mUnpluggedTime=" + mUnpluggedTime);
+            pw.println(prefix + "mCount=" + mCount);
+            pw.println(prefix + "mTotalTime=" + mTotalTime);
         }
 
 
@@ -1968,13 +1787,8 @@
 
         public void readSummaryFromParcelLocked(Parcel in) {
             // Multiply by 1000 for backwards compatibility
-            mTotalTime = mLoadedTime = in.readLong();
-            mLastTime = 0;
-            mUnpluggedTime = mTotalTime;
-            mCount = mLoadedCount = in.readInt();
-            mLastCount = 0;
-            mUnpluggedCount = mCount;
-
+            mTotalTime = in.readLong();
+            mCount = in.readInt();
             // When reading the summary, we set the mark to be the latest information.
             mTimeBeforeMark = mTotalTime;
         }
@@ -2233,7 +2047,7 @@
 
         private long computeOverage(long curTime) {
             if (mLastAddedTime > 0) {
-                return mLastTime + mLastAddedDuration - curTime;
+                return mLastAddedDuration - curTime;
             }
             return 0;
         }
@@ -2452,7 +2266,7 @@
             mTotalDurationMs = 0;
             mCurrentDurationMs = 0;
             if (mNesting > 0) {
-                mStartTimeMs = mTimeBase.getRealtime(mClocks.elapsedRealtime()*1000) / 1000;
+                mStartTimeMs = mTimeBase.getRealtime(mClocks.elapsedRealtime() * 1000) / 1000;
             } else {
                 mStartTimeMs = -1;
             }
@@ -2491,7 +2305,7 @@
         public long getCurrentDurationMsLocked(long elapsedRealtimeMs) {
             long durationMs = mCurrentDurationMs;
             if (mNesting > 0 && mTimeBase.isRunning()) {
-                durationMs += (mTimeBase.getRealtime(elapsedRealtimeMs*1000)/1000)
+                durationMs += (mTimeBase.getRealtime(elapsedRealtimeMs * 1000) / 1000)
                         - mStartTimeMs;
             }
             return durationMs;
@@ -6401,13 +6215,7 @@
     }
 
     @Override public int getNumConnectivityChange(int which) {
-        int val = mNumConnectivityChange;
-        if (which == STATS_CURRENT) {
-            val -= mLoadedNumConnectivityChange;
-        } else if (which == STATS_SINCE_UNPLUGGED) {
-            val -= mUnpluggedNumConnectivityChange;
-        }
-        return val;
+        return mNumConnectivityChange;
     }
 
     @Override public long getGpsSignalQualityTime(int strengthBin,
@@ -9122,66 +8930,6 @@
              */
             int mNumAnrs;
 
-            /**
-             * The amount of user time loaded from a previous save.
-             */
-            long mLoadedUserTime;
-
-            /**
-             * The amount of system time loaded from a previous save.
-             */
-            long mLoadedSystemTime;
-
-            /**
-             * The amount of foreground time loaded from a previous save.
-             */
-            long mLoadedForegroundTime;
-
-            /**
-             * The number of times the process has started from a previous save.
-             */
-            int mLoadedStarts;
-
-            /**
-             * Number of times the process has crashed from a previous save.
-             */
-            int mLoadedNumCrashes;
-
-            /**
-             * Number of times the process has had an ANR from a previous save.
-             */
-            int mLoadedNumAnrs;
-
-            /**
-             * The amount of user time when last unplugged.
-             */
-            long mUnpluggedUserTime;
-
-            /**
-             * The amount of system time when last unplugged.
-             */
-            long mUnpluggedSystemTime;
-
-            /**
-             * The amount of foreground time since unplugged.
-             */
-            long mUnpluggedForegroundTime;
-
-            /**
-             * The number of times the process has started before unplugged.
-             */
-            int mUnpluggedStarts;
-
-            /**
-             * Number of times the process has crashed before unplugged.
-             */
-            int mUnpluggedNumCrashes;
-
-            /**
-             * Number of times the process has had an ANR before unplugged.
-             */
-            int mUnpluggedNumAnrs;
-
             ArrayList<ExcessivePower> mExcessivePower;
 
             public Proc(BatteryStatsImpl bsi, String name) {
@@ -9191,12 +8939,6 @@
             }
 
             public void onTimeStarted(long elapsedRealtime, long baseUptime, long baseRealtime) {
-                mUnpluggedUserTime = mUserTime;
-                mUnpluggedSystemTime = mSystemTime;
-                mUnpluggedForegroundTime = mForegroundTime;
-                mUnpluggedStarts = mStarts;
-                mUnpluggedNumCrashes = mNumCrashes;
-                mUnpluggedNumAnrs = mNumAnrs;
             }
 
             public void onTimeStopped(long elapsedRealtime, long baseUptime, long baseRealtime) {
@@ -9283,18 +9025,6 @@
                 out.writeInt(mStarts);
                 out.writeInt(mNumCrashes);
                 out.writeInt(mNumAnrs);
-                out.writeLong(mLoadedUserTime);
-                out.writeLong(mLoadedSystemTime);
-                out.writeLong(mLoadedForegroundTime);
-                out.writeInt(mLoadedStarts);
-                out.writeInt(mLoadedNumCrashes);
-                out.writeInt(mLoadedNumAnrs);
-                out.writeLong(mUnpluggedUserTime);
-                out.writeLong(mUnpluggedSystemTime);
-                out.writeLong(mUnpluggedForegroundTime);
-                out.writeInt(mUnpluggedStarts);
-                out.writeInt(mUnpluggedNumCrashes);
-                out.writeInt(mUnpluggedNumAnrs);
                 writeExcessivePowerToParcelLocked(out);
             }
 
@@ -9305,18 +9035,6 @@
                 mStarts = in.readInt();
                 mNumCrashes = in.readInt();
                 mNumAnrs = in.readInt();
-                mLoadedUserTime = in.readLong();
-                mLoadedSystemTime = in.readLong();
-                mLoadedForegroundTime = in.readLong();
-                mLoadedStarts = in.readInt();
-                mLoadedNumCrashes = in.readInt();
-                mLoadedNumAnrs = in.readInt();
-                mUnpluggedUserTime = in.readLong();
-                mUnpluggedSystemTime = in.readLong();
-                mUnpluggedForegroundTime = in.readLong();
-                mUnpluggedStarts = in.readInt();
-                mUnpluggedNumCrashes = in.readInt();
-                mUnpluggedNumAnrs = in.readInt();
                 readExcessivePowerFromParcelLocked(in);
             }
 
@@ -9358,71 +9076,35 @@
             @Override
             @UnsupportedAppUsage
             public long getUserTime(int which) {
-                long val = mUserTime;
-                if (which == STATS_CURRENT) {
-                    val -= mLoadedUserTime;
-                } else if (which == STATS_SINCE_UNPLUGGED) {
-                    val -= mUnpluggedUserTime;
-                }
-                return val;
+                return mUserTime;
             }
 
             @Override
             @UnsupportedAppUsage
             public long getSystemTime(int which) {
-                long val = mSystemTime;
-                if (which == STATS_CURRENT) {
-                    val -= mLoadedSystemTime;
-                } else if (which == STATS_SINCE_UNPLUGGED) {
-                    val -= mUnpluggedSystemTime;
-                }
-                return val;
+                return mSystemTime;
             }
 
             @Override
             @UnsupportedAppUsage
             public long getForegroundTime(int which) {
-                long val = mForegroundTime;
-                if (which == STATS_CURRENT) {
-                    val -= mLoadedForegroundTime;
-                } else if (which == STATS_SINCE_UNPLUGGED) {
-                    val -= mUnpluggedForegroundTime;
-                }
-                return val;
+                return mForegroundTime;
             }
 
             @Override
             @UnsupportedAppUsage
             public int getStarts(int which) {
-                int val = mStarts;
-                if (which == STATS_CURRENT) {
-                    val -= mLoadedStarts;
-                } else if (which == STATS_SINCE_UNPLUGGED) {
-                    val -= mUnpluggedStarts;
-                }
-                return val;
+                return mStarts;
             }
 
             @Override
             public int getNumCrashes(int which) {
-                int val = mNumCrashes;
-                if (which == STATS_CURRENT) {
-                    val -= mLoadedNumCrashes;
-                } else if (which == STATS_SINCE_UNPLUGGED) {
-                    val -= mUnpluggedNumCrashes;
-                }
-                return val;
+                return mNumCrashes;
             }
 
             @Override
             public int getNumAnrs(int which) {
-                int val = mNumAnrs;
-                if (which == STATS_CURRENT) {
-                    val -= mLoadedNumAnrs;
-                } else if (which == STATS_SINCE_UNPLUGGED) {
-                    val -= mUnpluggedNumAnrs;
-                }
-                return val;
+                return mNumAnrs;
             }
         }
 
@@ -9588,54 +9270,6 @@
                 protected int mLaunches;
 
                 /**
-                 * The amount of time spent started loaded from a previous save
-                 * (ms in battery uptime).
-                 */
-                protected long mLoadedStartTime;
-
-                /**
-                 * The number of starts loaded from a previous save.
-                 */
-                protected int mLoadedStarts;
-
-                /**
-                 * The number of launches loaded from a previous save.
-                 */
-                protected int mLoadedLaunches;
-
-                /**
-                 * The amount of time spent started as of the last run (ms
-                 * in battery uptime).
-                 */
-                protected long mLastStartTime;
-
-                /**
-                 * The number of starts as of the last run.
-                 */
-                protected int mLastStarts;
-
-                /**
-                 * The number of launches as of the last run.
-                 */
-                protected int mLastLaunches;
-
-                /**
-                 * The amount of time spent started when last unplugged (ms
-                 * in battery uptime).
-                 */
-                protected long mUnpluggedStartTime;
-
-                /**
-                 * The number of starts when last unplugged.
-                 */
-                protected int mUnpluggedStarts;
-
-                /**
-                 * The number of launches when last unplugged.
-                 */
-                protected int mUnpluggedLaunches;
-
-                /**
                  * Construct a Serv. Also adds it to the on-battery time base as a listener.
                  */
                 public Serv(BatteryStatsImpl bsi) {
@@ -9645,9 +9279,6 @@
 
                 public void onTimeStarted(long elapsedRealtime, long baseUptime,
                         long baseRealtime) {
-                    mUnpluggedStartTime = getStartTimeToNowLocked(baseUptime);
-                    mUnpluggedStarts = mStarts;
-                    mUnpluggedLaunches = mLaunches;
                 }
 
                 public void onTimeStopped(long elapsedRealtime, long baseUptime,
@@ -9679,15 +9310,6 @@
                     mLaunchedSince = in.readLong();
                     mLaunched = in.readInt() != 0;
                     mLaunches = in.readInt();
-                    mLoadedStartTime = in.readLong();
-                    mLoadedStarts = in.readInt();
-                    mLoadedLaunches = in.readInt();
-                    mLastStartTime = 0;
-                    mLastStarts = 0;
-                    mLastLaunches = 0;
-                    mUnpluggedStartTime = in.readLong();
-                    mUnpluggedStarts = in.readInt();
-                    mUnpluggedLaunches = in.readInt();
                 }
 
                 public void writeToParcelLocked(Parcel out) {
@@ -9699,12 +9321,6 @@
                     out.writeLong(mLaunchedSince);
                     out.writeInt(mLaunched ? 1 : 0);
                     out.writeInt(mLaunches);
-                    out.writeLong(mLoadedStartTime);
-                    out.writeInt(mLoadedStarts);
-                    out.writeInt(mLoadedLaunches);
-                    out.writeLong(mUnpluggedStartTime);
-                    out.writeInt(mUnpluggedStarts);
-                    out.writeInt(mUnpluggedLaunches);
                 }
 
                 public long getLaunchTimeToNowLocked(long batteryUptime) {
@@ -9768,36 +9384,17 @@
 
                 @Override
                 public int getLaunches(int which) {
-                    int val = mLaunches;
-                    if (which == STATS_CURRENT) {
-                        val -= mLoadedLaunches;
-                    } else if (which == STATS_SINCE_UNPLUGGED) {
-                        val -= mUnpluggedLaunches;
-                    }
-                    return val;
+                    return mLaunches;
                 }
 
                 @Override
                 public long getStartTime(long now, int which) {
-                    long val = getStartTimeToNowLocked(now);
-                    if (which == STATS_CURRENT) {
-                        val -= mLoadedStartTime;
-                    } else if (which == STATS_SINCE_UNPLUGGED) {
-                        val -= mUnpluggedStartTime;
-                    }
-                    return val;
+                    return getStartTimeToNowLocked(now);
                 }
 
                 @Override
                 public int getStarts(int which) {
-                    int val = mStarts;
-                    if (which == STATS_CURRENT) {
-                        val -= mLoadedStarts;
-                    } else if (which == STATS_SINCE_UNPLUGGED) {
-                        val -= mUnpluggedStarts;
-                    }
-
-                    return val;
+                    return mStarts;
                 }
             }
 
@@ -10932,7 +10529,7 @@
         }
         mBluetoothActivity.reset(false);
         mModemActivity.reset(false);
-        mNumConnectivityChange = mLoadedNumConnectivityChange = mUnpluggedNumConnectivityChange = 0;
+        mNumConnectivityChange = 0;
 
         for (int i=0; i<mUidStats.size(); i++) {
             if (mUidStats.valueAt(i).reset(uptimeMillis * 1000, elapsedRealtimeMillis * 1000)) {
@@ -12668,7 +12265,7 @@
                 startRecordingHistory(elapsedRealtime, uptime, true);
             }
         } else if (level < 96 &&
-            status != BatteryManager.BATTERY_STATUS_UNKNOWN) {
+                status != BatteryManager.BATTERY_STATUS_UNKNOWN) {
             if (!mRecordingHistory) {
                 mRecordingHistory = true;
                 startRecordingHistory(elapsedRealtime, uptime, true);
@@ -12817,8 +12414,8 @@
             }
         }
         if (!onBattery &&
-            (status == BatteryManager.BATTERY_STATUS_FULL ||
-             status == BatteryManager.BATTERY_STATUS_UNKNOWN)) {
+                (status == BatteryManager.BATTERY_STATUS_FULL ||
+                        status == BatteryManager.BATTERY_STATUS_UNKNOWN)) {
             // We don't record history while we are plugged in and fully charged
             // (or when battery is not present).  The next time we are
             // unplugged, history will be cleared.
@@ -12855,7 +12452,9 @@
 
     @UnsupportedAppUsage
     public long getAwakeTimeBattery() {
-        return computeBatteryUptime(getBatteryUptimeLocked(), STATS_CURRENT);
+        // This previously evaluated to mOnBatteryTimeBase.getUptime(getBatteryUptimeLocked());
+        // for over a decade, but surely that was a mistake.
+        return getBatteryUptimeLocked();
     }
 
     @UnsupportedAppUsage
@@ -12865,22 +12464,12 @@
 
     @Override
     public long computeUptime(long curTime, int which) {
-        switch (which) {
-            case STATS_SINCE_CHARGED: return mUptime + (curTime-mUptimeStart);
-            case STATS_CURRENT: return (curTime-mUptimeStart);
-            case STATS_SINCE_UNPLUGGED: return (curTime-mOnBatteryTimeBase.getUptimeStart());
-        }
-        return 0;
+        return mUptime + (curTime - mUptimeStart);
     }
 
     @Override
     public long computeRealtime(long curTime, int which) {
-        switch (which) {
-            case STATS_SINCE_CHARGED: return mRealtime + (curTime-mRealtimeStart);
-            case STATS_CURRENT: return (curTime-mRealtimeStart);
-            case STATS_SINCE_UNPLUGGED: return (curTime-mOnBatteryTimeBase.getRealtimeStart());
-        }
-        return 0;
+        return mRealtime + (curTime - mRealtimeStart);
     }
 
     @Override
@@ -14074,7 +13663,7 @@
         mHasBluetoothReporting = in.readInt() != 0;
         mHasModemReporting = in.readInt() != 0;
 
-        mNumConnectivityChange = mLoadedNumConnectivityChange = in.readInt();
+        mNumConnectivityChange = in.readInt();
         mFlashlightOnNesting = 0;
         mFlashlightOnTimer.readSummaryFromParcelLocked(in);
         mCameraOnNesting = 0;
@@ -14383,12 +13972,12 @@
             for (int ip = 0; ip < NP; ip++) {
                 String procName = in.readString();
                 Uid.Proc p = u.getProcessStatsLocked(procName);
-                p.mUserTime = p.mLoadedUserTime = in.readLong();
-                p.mSystemTime = p.mLoadedSystemTime = in.readLong();
-                p.mForegroundTime = p.mLoadedForegroundTime = in.readLong();
-                p.mStarts = p.mLoadedStarts = in.readInt();
-                p.mNumCrashes = p.mLoadedNumCrashes = in.readInt();
-                p.mNumAnrs = p.mLoadedNumAnrs = in.readInt();
+                p.mUserTime = in.readLong();
+                p.mSystemTime = in.readLong();
+                p.mForegroundTime = in.readLong();
+                p.mStarts = in.readInt();
+                p.mNumCrashes = in.readInt();
+                p.mNumAnrs = in.readInt();
                 p.readExcessivePowerFromParcelLocked(in);
             }
 
@@ -14405,7 +13994,7 @@
                     throw new ParcelFormatException("File corrupt: too many wakeup alarms " + NWA);
                 }
                 p.mWakeupAlarms.clear();
-                for (int iwa=0; iwa<NWA; iwa++) {
+                for (int iwa = 0; iwa < NWA; iwa++) {
                     String tag = in.readString();
                     Counter c = new Counter(mOnBatteryScreenOffTimeBase);
                     c.readSummaryFromParcelLocked(in);
@@ -14418,9 +14007,9 @@
                 for (int is = 0; is < NS; is++) {
                     String servName = in.readString();
                     Uid.Pkg.Serv s = u.getServiceStatsLocked(pkgName, servName);
-                    s.mStartTime = s.mLoadedStartTime = in.readLong();
-                    s.mStarts = s.mLoadedStarts = in.readInt();
-                    s.mLaunches = s.mLoadedLaunches = in.readInt();
+                    s.mStartTime = in.readLong();
+                    s.mStarts = in.readInt();
+                    s.mLaunches = in.readInt();
                 }
             }
         }
@@ -15054,9 +14643,8 @@
         mHasModemReporting = in.readInt() != 0;
 
         mNumConnectivityChange = in.readInt();
-        mLoadedNumConnectivityChange = in.readInt();
-        mUnpluggedNumConnectivityChange = in.readInt();
         mAudioOnNesting = 0;
+        // TODO: It's likely a mistake that mAudioOnTimer/mVideoOnTimer don't write/read to parcel!
         mAudioOnTimer = new StopwatchTimer(mClocks, null, -7, null, mOnBatteryTimeBase);
         mVideoOnNesting = 0;
         mVideoOnTimer = new StopwatchTimer(mClocks, null, -8, null, mOnBatteryTimeBase);
@@ -15256,8 +14844,6 @@
         out.writeInt(mHasModemReporting ? 1 : 0);
 
         out.writeInt(mNumConnectivityChange);
-        out.writeInt(mLoadedNumConnectivityChange);
-        out.writeInt(mUnpluggedNumConnectivityChange);
         mFlashlightOnTimer.writeToParcel(out, uSecRealtime);
         mCameraOnTimer.writeToParcel(out, uSecRealtime);
         mBluetoothScanTimer.writeToParcel(out, uSecRealtime);
diff --git a/core/java/com/android/internal/os/PowerCalculator.java b/core/java/com/android/internal/os/PowerCalculator.java
index cd69d68..e31c9de 100644
--- a/core/java/com/android/internal/os/PowerCalculator.java
+++ b/core/java/com/android/internal/os/PowerCalculator.java
@@ -27,9 +27,10 @@
      * @param u The recorded stats for the app.
      * @param rawRealtimeUs The raw system realtime in microseconds.
      * @param rawUptimeUs The raw system uptime in microseconds.
-     * @param statsType The type of stats. Can be {@link BatteryStats#STATS_CURRENT},
-     *                  {@link BatteryStats#STATS_SINCE_CHARGED}, or
-     *                  {@link BatteryStats#STATS_SINCE_UNPLUGGED}.
+     * @param statsType The type of stats. As of {@link android.os.Build.VERSION_CODES#Q}, this can
+     *                  only be {@link BatteryStats#STATS_SINCE_CHARGED}, since
+     *                  {@link BatteryStats#STATS_CURRENT} and
+     *                  {@link BatteryStats#STATS_SINCE_UNPLUGGED} are deprecated.
      */
     public abstract void calculateApp(BatterySipper app, BatteryStats.Uid u, long rawRealtimeUs,
                                       long rawUptimeUs, int statsType);
@@ -40,9 +41,10 @@
      * @param stats The BatteryStats object from which to retrieve data.
      * @param rawRealtimeUs The raw system realtime in microseconds.
      * @param rawUptimeUs The raw system uptime in microseconds.
-     * @param statsType The type of stats. Can be {@link BatteryStats#STATS_CURRENT},
-     *                  {@link BatteryStats#STATS_SINCE_CHARGED}, or
-     *                  {@link BatteryStats#STATS_SINCE_UNPLUGGED}.
+     * @param statsType The type of stats. As of {@link android.os.Build.VERSION_CODES#Q}, this can
+     *                  only be {@link BatteryStats#STATS_SINCE_CHARGED}, since
+     *                  {@link BatteryStats#STATS_CURRENT} and
+     *                  {@link BatteryStats#STATS_SINCE_UNPLUGGED} are deprecated.
      */
     public void calculateRemaining(BatterySipper app, BatteryStats stats, long rawRealtimeUs,
                                    long rawUptimeUs, int statsType) {
diff --git a/core/java/com/android/internal/os/ZygoteInit.java b/core/java/com/android/internal/os/ZygoteInit.java
index 5f23719..07b82d0 100644
--- a/core/java/com/android/internal/os/ZygoteInit.java
+++ b/core/java/com/android/internal/os/ZygoteInit.java
@@ -122,6 +122,12 @@
 
     private static boolean sPreloadComplete;
 
+    /**
+     * Cached classloader to use for the system server. Will only be populated in the system
+     * server process.
+     */
+    private static ClassLoader sCachedSystemServerClassLoader = null;
+
     static void preload(TimingsTraceLog bootTimingsTraceLog) {
         Log.d(TAG, "begin preload");
         bootTimingsTraceLog.traceBegin("BeginPreload");
@@ -443,7 +449,13 @@
 
         final String systemServerClasspath = Os.getenv("SYSTEMSERVERCLASSPATH");
         if (systemServerClasspath != null) {
-            performSystemServerDexOpt(systemServerClasspath);
+            if (performSystemServerDexOpt(systemServerClasspath)) {
+                // Throw away the cached classloader. If we compiled here, the classloader would
+                // not have had AoT-ed artifacts.
+                // Note: This only works in a very special environment where selinux enforcement is
+                // disabled, e.g., Mac builds.
+                sCachedSystemServerClassLoader = null;
+            }
             // Capturing profiles is only supported for debug or eng builds since selinux normally
             // prevents it.
             boolean profileSystemServer = SystemProperties.getBoolean(
@@ -476,10 +488,9 @@
 
             throw new IllegalStateException("Unexpected return from WrapperInit.execApplication");
         } else {
-            ClassLoader cl = null;
-            if (systemServerClasspath != null) {
-                cl = createPathClassLoader(systemServerClasspath, parsedArgs.mTargetSdkVersion);
-
+            createSystemServerClassLoader();
+            ClassLoader cl = sCachedSystemServerClassLoader;
+            if (cl != null) {
                 Thread.currentThread().setContextClassLoader(cl);
             }
 
@@ -494,6 +505,24 @@
     }
 
     /**
+     * Create the classloader for the system server and store it in
+     * {@link sCachedSystemServerClassLoader}. This function may be called through JNI in
+     * system server startup, when the runtime is in a critically low state. Do not do
+     * extended computation etc here.
+     */
+    private static void createSystemServerClassLoader() {
+        if (sCachedSystemServerClassLoader != null) {
+            return;
+        }
+        final String systemServerClasspath = Os.getenv("SYSTEMSERVERCLASSPATH");
+        // TODO: Should we run optimization here?
+        if (systemServerClasspath != null) {
+            sCachedSystemServerClassLoader = createPathClassLoader(systemServerClasspath,
+                    VMRuntime.SDK_VERSION_CUR_DEVELOPMENT);
+        }
+    }
+
+    /**
      * Note that preparing the profiles for system server does not require special selinux
      * permissions. From the installer perspective the system server is a regular package which can
      * capture profile information.
@@ -557,15 +586,16 @@
 
     /**
      * Performs dex-opt on the elements of {@code classPath}, if needed. We choose the instruction
-     * set of the current runtime.
+     * set of the current runtime. If something was compiled, return true.
      */
-    private static void performSystemServerDexOpt(String classPath) {
+    private static boolean performSystemServerDexOpt(String classPath) {
         final String[] classPathElements = classPath.split(":");
         final IInstalld installd = IInstalld.Stub
                 .asInterface(ServiceManager.getService("installd"));
         final String instructionSet = VMRuntime.getRuntime().vmInstructionSet();
 
         String classPathForElement = "";
+        boolean compiledSomething = false;
         for (String classPathElement : classPathElements) {
             // System server is fully AOTed and never profiled
             // for profile guided compilation.
@@ -607,6 +637,7 @@
                             uuid, classLoaderContext, seInfo, false /* downgrade */,
                             targetSdkVersion, /*profileName*/ null, /*dexMetadataPath*/ null,
                             "server-dexopt");
+                    compiledSomething = true;
                 } catch (RemoteException | ServiceSpecificException e) {
                     // Ignore (but log), we need this on the classpath for fallback mode.
                     Log.w(TAG, "Failed compiling classpath element for system server: "
@@ -617,6 +648,8 @@
             classPathForElement = encodeSystemServerClassPath(
                     classPathForElement, classPathElement);
         }
+
+        return compiledSomething;
     }
 
     /**
diff --git a/core/java/com/android/internal/util/SyncResultReceiver.java b/core/java/com/android/internal/util/SyncResultReceiver.java
index 9a346ac..60af511 100644
--- a/core/java/com/android/internal/util/SyncResultReceiver.java
+++ b/core/java/com/android/internal/util/SyncResultReceiver.java
@@ -96,6 +96,19 @@
         return mBundle == null ? null : mBundle.getParcelable(EXTRA);
     }
 
+    /**
+     * Gets the optional result from an operation that returns an extra {@code int} (besides the
+     * result code).
+     *
+     * @return value set in the bundle, or {@code defaultValue} when not set.
+     */
+    public int getOptionalExtraIntResult(int defaultValue) throws TimeoutException {
+        waitResult();
+        if (mBundle == null || !mBundle.containsKey(EXTRA)) return defaultValue;
+
+        return mBundle.getInt(EXTRA);
+    }
+
     @Override
     public void send(int resultCode, Bundle resultData) {
         mResult = resultCode;
@@ -136,6 +149,18 @@
         return bundle;
     }
 
+    /**
+     * Creates a bundle for an {@code int} value so it can be retrieved by
+     * {@link #getParcelableResult()} - typically used to return an extra {@code int} (as the 1st
+     * is returned as the result code).
+     */
+    @NonNull
+    public static Bundle bundleFor(int value) {
+        final Bundle bundle = new Bundle();
+        bundle.putInt(EXTRA, value);
+        return bundle;
+    }
+
     /** @hide */
     public static final class TimeoutException extends RemoteException {
         private TimeoutException(String msg) {
diff --git a/core/java/com/android/internal/widget/ILockSettings.aidl b/core/java/com/android/internal/widget/ILockSettings.aidl
index 3be7c3e..41e2fc8 100644
--- a/core/java/com/android/internal/widget/ILockSettings.aidl
+++ b/core/java/com/android/internal/widget/ILockSettings.aidl
@@ -62,6 +62,7 @@
     void systemReady();
     void userPresent(int userId);
     int getStrongAuthForUser(int userId);
+    boolean hasPendingEscrowToken(int userId);
 
     // Keystore RecoveryController methods.
     // {@code ServiceSpecificException} may be thrown to signal an error, which caller can
diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java
index c095376..1965609 100644
--- a/core/java/com/android/internal/widget/LockPatternUtils.java
+++ b/core/java/com/android/internal/widget/LockPatternUtils.java
@@ -1638,7 +1638,7 @@
     }
 
     /**
-     * @see StrongAuthTracker#isFingerprintAllowedForUser
+     * @see StrongAuthTracker#isBiometricAllowedForUser(int)
      */
     public boolean isBiometricAllowedForUser(int userId) {
         return (getStrongAuthForUser(userId) & ~StrongAuthTracker.ALLOWING_BIOMETRIC) == 0;
@@ -1980,6 +1980,18 @@
     }
 
     /**
+     * Returns whether the given user has pending escrow tokens
+     */
+    public boolean hasPendingEscrowToken(int userId) {
+        try {
+            return getLockSettings().hasPendingEscrowToken(userId);
+        } catch (RemoteException e) {
+            e.rethrowFromSystemServer();
+        }
+        return false;
+    }
+
+    /**
      * Return true if the device supports the lock screen feature, false otherwise.
      */
     public boolean hasSecureLockScreen() {
diff --git a/core/java/com/android/internal/widget/PointerLocationView.java b/core/java/com/android/internal/widget/PointerLocationView.java
index 4773e16..3205b5a 100644
--- a/core/java/com/android/internal/widget/PointerLocationView.java
+++ b/core/java/com/android/internal/widget/PointerLocationView.java
@@ -20,12 +20,16 @@
 import android.graphics.Canvas;
 import android.graphics.Paint;
 import android.graphics.Paint.FontMetricsInt;
+import android.graphics.Path;
 import android.graphics.RectF;
+import android.graphics.Region;
 import android.hardware.input.InputManager;
 import android.hardware.input.InputManager.InputDeviceListener;
+import android.os.RemoteException;
 import android.os.SystemProperties;
 import android.util.Log;
 import android.util.Slog;
+import android.view.ISystemGestureExclusionListener;
 import android.view.InputDevice;
 import android.view.KeyEvent;
 import android.view.MotionEvent;
@@ -34,6 +38,7 @@
 import android.view.View;
 import android.view.ViewConfiguration;
 import android.view.WindowInsets;
+import android.view.WindowManagerGlobal;
 import android.view.WindowManagerPolicyConstants.PointerEventListener;
 
 import java.util.ArrayList;
@@ -124,12 +129,16 @@
     private int mActivePointerId;
     private final ArrayList<PointerState> mPointers = new ArrayList<PointerState>();
     private final PointerCoords mTempCoords = new PointerCoords();
-    
+
+    private final Region mSystemGestureExclusion = new Region();
+    private final Path mSystemGestureExclusionPath = new Path();
+    private final Paint mSystemGestureExclusionPaint;
+
     private final VelocityTracker mVelocity;
     private final VelocityTracker mAltVelocity;
 
     private final FasterStringBuilder mText = new FasterStringBuilder();
-    
+
     private boolean mPrintCoords = true;
     
     public PointerLocationView(Context c) {
@@ -168,7 +177,11 @@
         mPathPaint.setARGB(255, 0, 96, 255);
         mPaint.setStyle(Paint.Style.STROKE);
         mPaint.setStrokeWidth(1);
-        
+
+        mSystemGestureExclusionPaint = new Paint();
+        mSystemGestureExclusionPaint.setARGB(25, 255, 0, 0);
+        mSystemGestureExclusionPaint.setStyle(Paint.Style.FILL_AND_STROKE);
+
         PointerState ps = new PointerState();
         mPointers.add(ps);
         mActivePointerId = 0;
@@ -236,6 +249,12 @@
 
         final int NP = mPointers.size();
 
+        if (!mSystemGestureExclusion.isEmpty()) {
+            mSystemGestureExclusionPath.reset();
+            mSystemGestureExclusion.getBoundaryPath(mSystemGestureExclusionPath);
+            canvas.drawPath(mSystemGestureExclusionPath, mSystemGestureExclusionPaint);
+        }
+
         // Labels
         if (mActivePointerId >= 0) {
             final PointerState ps = mPointers.get(mActivePointerId);
@@ -719,6 +738,12 @@
         super.onAttachedToWindow();
 
         mIm.registerInputDeviceListener(this, getHandler());
+        try {
+            WindowManagerGlobal.getWindowManagerService().registerSystemGestureExclusionListener(
+                    mSystemGestureExclusionListener, mContext.getDisplayId());
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
         logInputDevices();
     }
 
@@ -727,6 +752,12 @@
         super.onDetachedFromWindow();
 
         mIm.unregisterInputDeviceListener(this);
+        try {
+            WindowManagerGlobal.getWindowManagerService().unregisterSystemGestureExclusionListener(
+                    mSystemGestureExclusionListener, mContext.getDisplayId());
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
     }
 
     @Override
@@ -876,4 +907,17 @@
             return oldLength;
         }
     }
+
+    private ISystemGestureExclusionListener mSystemGestureExclusionListener =
+            new ISystemGestureExclusionListener.Stub() {
+        @Override
+        public void onSystemGestureExclusionChanged(int displayId, Region systemGestureExclusion) {
+            Region exclusion = Region.obtain(systemGestureExclusion);
+            getHandler().post(() -> {
+                mSystemGestureExclusion.set(exclusion);
+                exclusion.recycle();
+                invalidate();
+            });
+        }
+    };
 }
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index da27852..20bed1b 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -1126,6 +1126,12 @@
         return;
     }
 
+    const char* tzdataRootDir = getenv("ANDROID_TZDATA_ROOT");
+    if (tzdataRootDir == NULL) {
+        LOG_FATAL("No tz data directory specified with ANDROID_TZDATA_ROOT environment variable.");
+        return;
+    }
+
     //const char* kernelHack = getenv("LD_ASSUME_KERNEL");
     //ALOGD("Found LD_ASSUME_KERNEL='%s'\n", kernelHack);
 
diff --git a/core/jni/android/graphics/HarfBuzzNGFaceSkia.h b/core/jni/android/graphics/HarfBuzzNGFaceSkia.h
deleted file mode 100644
index 3308d5d..0000000
--- a/core/jni/android/graphics/HarfBuzzNGFaceSkia.h
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Copyright 2011, The Android Open Source Project
- * Copyright 2011, Google Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *  * Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- *  * Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef _ANDROID_GRAPHICS_HARF_BUZZ_NG_FACE_SKIA_H_
-#define _ANDROID_GRAPHICS_HARF_BUZZ_NG_FACE_SKIA_H_
-
-#include <SkScalar.h>
-#include <SkPaint.h>
-
-#include <hb.h>
-
-namespace android {
-
-static inline float
-HBFixedToFloat (hb_position_t v)
-{
-    return scalbnf (v, -8);
-}
-
-static inline hb_position_t
-HBFloatToFixed (float v)
-{
-    return scalbnf (v, +8);
-}
-
-static inline hb_position_t SkScalarToHBFixed(SkScalar value) {
-    return HBFloatToFixed(SkScalarToFloat(value));
-}
-
-hb_blob_t* harfbuzzSkiaReferenceTable(hb_face_t* face, hb_tag_t tag, void* userData);
-
-hb_font_t* createFont(hb_face_t* face, SkPaint* paint, float sizeX, float sizeY);
-
-}  // namespace android
-
-#endif  // _ANDROID_GRAPHICS_HARF_BUZZ_NG_FACE_SKIA_H_
diff --git a/core/jni/android_view_InputDevice.cpp b/core/jni/android_view_InputDevice.cpp
index a698d66..9f4e3e5 100644
--- a/core/jni/android_view_InputDevice.cpp
+++ b/core/jni/android_view_InputDevice.cpp
@@ -68,9 +68,8 @@
                 deviceInfo.getKeyboardType(), kcmObj.get(), deviceInfo.hasVibrator(),
                 hasMic, deviceInfo.hasButtonUnderPad()));
 
-    const Vector<InputDeviceInfo::MotionRange>& ranges = deviceInfo.getMotionRanges();
-    for (size_t i = 0; i < ranges.size(); i++) {
-        const InputDeviceInfo::MotionRange& range = ranges.itemAt(i);
+    const std::vector<InputDeviceInfo::MotionRange>& ranges = deviceInfo.getMotionRanges();
+    for (const InputDeviceInfo::MotionRange& range: ranges) {
         env->CallVoidMethod(inputDeviceObj.get(), gInputDeviceClassInfo.addMotionRange, range.axis,
                 range.source, range.min, range.max, range.flat, range.fuzz, range.resolution);
         if (env->ExceptionCheck()) {
diff --git a/core/jni/android_view_RenderNode.cpp b/core/jni/android_view_RenderNode.cpp
index 9f9fbf9..c4c16ee 100644
--- a/core/jni/android_view_RenderNode.cpp
+++ b/core/jni/android_view_RenderNode.cpp
@@ -31,6 +31,7 @@
 #include <renderthread/CanvasContext.h>
 #include <TreeInfo.h>
 #include <hwui/Paint.h>
+#include <utils/TraceUtils.h>
 
 #include "core_jni_helpers.h"
 
diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp
index 009a6ca..cde1884 100644
--- a/core/jni/com_android_internal_os_Zygote.cpp
+++ b/core/jni/com_android_internal_os_Zygote.cpp
@@ -24,6 +24,7 @@
 #endif
 
 #define LOG_TAG "Zygote"
+#define ATRACE_TAG ATRACE_TAG_DALVIK
 
 #include <async_safe/log.h>
 
@@ -73,6 +74,7 @@
 #include <cutils/multiuser.h>
 #include <private/android_filesystem_config.h>
 #include <utils/String8.h>
+#include <utils/Trace.h>
 #include <selinux/android.h>
 #include <seccomp_policy.h>
 #include <stats_event_list.h>
@@ -111,11 +113,16 @@
 
 static const char kIsolatedStorage[] = "persist.sys.isolated_storage";
 static const char kIsolatedStorageSnapshot[] = "sys.isolated_storage_snapshot";
-static const char kZygoteClassName[] = "com/android/internal/os/Zygote";
+
+static constexpr const char* kZygoteClassName = "com/android/internal/os/Zygote";
 static jclass gZygoteClass;
 static jmethodID gCallPostForkSystemServerHooks;
 static jmethodID gCallPostForkChildHooks;
 
+static constexpr const char* kZygoteInitClassName = "com/android/internal/os/ZygoteInit";
+static jclass gZygoteInitClass;
+static jmethodID gCreateSystemServerClassLoader;
+
 static bool g_is_security_enforced = true;
 
 /**
@@ -585,6 +592,8 @@
 }
 
 static int UnmountTree(const char* path) {
+  ATRACE_CALL();
+
   size_t path_len = strlen(path);
 
   FILE* fp = setmntent("/proc/mounts", "r");
@@ -627,6 +636,8 @@
 }
 
 static void CreatePkgSandboxTarget(userid_t user_id, fail_fn_t fail_fn) {
+  ATRACE_CALL();
+
   // Create /mnt/user/0/package
   std::string pkg_sandbox_dir = StringPrintf("/mnt/user/%d", user_id);
   CreateDir(pkg_sandbox_dir, 0751, AID_ROOT, AID_ROOT, fail_fn);
@@ -650,6 +661,8 @@
                                 uid_t uid,
                                 const char* dir_name,
                                 fail_fn_t fail_fn) {
+  ATRACE_CALL();
+
   std::string mnt_source_dir = StringPrintf("%s/Android/%s/%s",
       mnt_source_root.c_str(), dir_name, package_name.c_str());
 
@@ -662,6 +675,8 @@
 static void CreateSubDirs(int parent_fd, const std::string& parent_path,
                           const std::vector<std::string>& sub_dirs,
                           fail_fn_t fail_fn) {
+  ATRACE_CALL();
+
   for (auto& dir_name : sub_dirs) {
     struct stat sb;
     if (TEMP_FAILURE_RETRY(fstatat(parent_fd, dir_name.c_str(), &sb, 0)) == 0) {
@@ -686,6 +701,8 @@
                                   const std::vector<std::string>& package_names,
                                   bool create_sandbox_dir,
                                   fail_fn_t fail_fn) {
+  ATRACE_CALL();
+
   std::string android_dir = StringPrintf("%s/Android", path.c_str());
   android::base::unique_fd android_fd(open(android_dir.c_str(),
                                            O_RDONLY | O_DIRECTORY | O_CLOEXEC));
@@ -729,6 +746,7 @@
 }
 
 static void CreatePkgSandboxSource(const std::string& sandbox_source, fail_fn_t fail_fn) {
+  ATRACE_CALL();
 
   struct stat sb;
   if (TEMP_FAILURE_RETRY(stat(sandbox_source.c_str(), &sb)) == 0) {
@@ -751,6 +769,8 @@
 static void PreparePkgSpecificDirs(const std::vector<std::string>& package_names,
                                    bool mount_all_obbs, const std::string& sandbox_id,
                                    userid_t user_id, uid_t uid, fail_fn_t fail_fn) {
+  ATRACE_CALL();
+
   std::unique_ptr<DIR, decltype(&closedir)> dirp(opendir("/storage"), closedir);
   if (!dirp) {
     fail_fn(CREATE_ERROR("Failed to opendir /storage: %s", strerror(errno)));
@@ -807,6 +827,8 @@
                                      userid_t user_id,
                                      const std::string& sandbox_id,
                                      fail_fn_t fail_fn) {
+  ATRACE_CALL();
+
   std::string obb_mount_dir = StringPrintf("/mnt/user/%d/obb_mount", user_id);
   std::string obb_mount_file = StringPrintf("%s/%s", obb_mount_dir.c_str(), sandbox_id.c_str());
   if (mount_mode == MOUNT_EXTERNAL_INSTALLER) {
@@ -844,6 +866,7 @@
         const std::string& sandbox_id,
         fail_fn_t fail_fn) {
   // See storage config details at http://source.android.com/tech/storage/
+  ATRACE_CALL();
 
   String8 storage_source;
   if (mount_mode == MOUNT_EXTERNAL_DEFAULT) {
@@ -1420,6 +1443,15 @@
       fail_fn("Error calling post fork system server hooks.");
     }
 
+    // Prefetch the classloader for the system server. This is done early to
+    // allow a tie-down of the proper system server selinux domain.
+    env->CallStaticVoidMethod(gZygoteInitClass, gCreateSystemServerClassLoader);
+    if (env->ExceptionCheck()) {
+      // Be robust here. The Java code will attempt to create the classloader
+      // at a later point (but may not have rights to use AoT artifacts).
+      env->ExceptionClear();
+    }
+
     // TODO(oth): Remove hardcoded label here (b/117874058).
     static const char* kSystemServerLabel = "u:r:system_server:s0";
     if (selinux_android_setcon(kSystemServerLabel) != 0) {
@@ -1986,6 +2018,13 @@
   gCallPostForkChildHooks = GetStaticMethodIDOrDie(env, gZygoteClass, "callPostForkChildHooks",
                                                    "(IZZLjava/lang/String;)V");
 
-  return RegisterMethodsOrDie(env, "com/android/internal/os/Zygote", gMethods, NELEM(gMethods));
+  gZygoteInitClass = MakeGlobalRefOrDie(env, FindClassOrDie(env, kZygoteInitClassName));
+  gCreateSystemServerClassLoader = GetStaticMethodIDOrDie(env, gZygoteInitClass,
+                                                          "createSystemServerClassLoader",
+                                                          "()V");
+
+  RegisterMethodsOrDie(env, "com/android/internal/os/Zygote", gMethods, NELEM(gMethods));
+
+  return JNI_OK;
 }
 }  // namespace android
diff --git a/core/proto/android/app/settings_enums.proto b/core/proto/android/app/settings_enums.proto
index 7ad9223..25caafb 100644
--- a/core/proto/android/app/settings_enums.proto
+++ b/core/proto/android/app/settings_enums.proto
@@ -590,6 +590,13 @@
     // OS: P
     DIALOG_SWITCH_HFP_DEVICES = 1416;
 
+    // OPEN: QS Sensor Privacy Mode tile shown
+    // ACTION: QS Sensor Privacy Mode tile tapped
+    // SUBTYPE: 0 is off, 1 is on
+    // CATEGORY: QUICK_SETTINGS
+    // OS: Q
+    QS_SENSOR_PRIVACY = 1598;
+
     // ACTION: Tap & Pay -> Default Application Setting -> Use Forground
     ACTION_NFC_PAYMENT_FOREGROUND_SETTING = 1622;
 
@@ -2305,4 +2312,8 @@
 
     // Open: Settings > Special App Access > Do not disturb control for app
     ZEN_ACCESS_DETAIL = 1692;
+
+    // OPEN: Settings > Face > Remove face
+    // OS: Q
+    DIALOG_FACE_REMOVE = 1693;
 }
diff --git a/core/proto/android/server/powermanagerservice.proto b/core/proto/android/server/powermanagerservice.proto
index 8fce94e..9bf1825 100644
--- a/core/proto/android/server/powermanagerservice.proto
+++ b/core/proto/android/server/powermanagerservice.proto
@@ -318,6 +318,16 @@
     // Whether battery saver is enabled.
     optional bool enabled = 1;
 
+    enum StateEnum {
+        STATE_UNKNOWN = 0;
+        STATE_OFF = 1;
+        STATE_MANUAL_ON = 2;
+        STATE_AUTOMATIC_ON = 3;
+        STATE_OFF_AUTOMATIC_SNOOZED = 4;
+        STATE_PENDING_STICKY_ON = 5;
+    }
+    optional StateEnum state = 18;
+
     // Whether full battery saver is enabled.
     optional bool is_full_enabled = 14;
 
@@ -337,8 +347,7 @@
     // Whether battery status has been set at least once.
     optional bool battery_status_set = 4;
 
-    // Whether automatic battery saver has been canceled by the user.
-    optional bool battery_saver_snoozing = 5;
+    reserved 5; // battery_saver_snoozing
 
     // Whether the device is connected to any power source.
     optional bool is_powered = 6;
@@ -373,5 +382,5 @@
     // using elapsed realtime as the timebase.
     optional int64 last_adaptive_battery_saver_changed_externally_elapsed = 17;
 
-    // Next tag: 18
+    // Next tag: 19
 }
diff --git a/core/proto/android/service/notification.proto b/core/proto/android/service/notification.proto
index c08d7ca..4ef26dd 100644
--- a/core/proto/android/service/notification.proto
+++ b/core/proto/android/service/notification.proto
@@ -66,6 +66,10 @@
     optional bool can_show_light = 8;
     optional string group_key = 9 [ (.android.privacy).dest = DEST_EXPLICIT ];
     optional sint32 importance = 10;
+    // The package the notification was posted for.
+    optional string package = 11;
+    // The package that posted the notification. It might not be the same as package.
+    optional string delegate_package = 12;
 }
 
 message ListenersDisablingEffectsProto {
diff --git a/media/java/android/media/session/SessionLink.aidl b/core/proto/android/stats/storage/storage_enums.proto
similarity index 74%
copy from media/java/android/media/session/SessionLink.aidl
copy to core/proto/android/stats/storage/storage_enums.proto
index c3be23e..6892e28 100644
--- a/media/java/android/media/session/SessionLink.aidl
+++ b/core/proto/android/stats/storage/storage_enums.proto
@@ -1,5 +1,5 @@
 /*
- * Copyright 2019 The Android Open Source Project
+ * 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.
@@ -14,6 +14,13 @@
  * limitations under the License.
  */
 
-package android.media.session;
+syntax = "proto2";
 
-parcelable SessionLink;
+package android.stats.storage;
+
+enum ExternalStorageType {
+  UNKNOWN = 0;
+  SD_CARD = 1;
+  USB = 2;
+  OTHER = 3;
+}
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index c7417bf..5427147 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -819,8 +819,7 @@
         android:permissionGroup="android.permission-group.UNDEFINED"
         android:label="@string/permlab_sdcardRead"
         android:description="@string/permdesc_sdcardRead"
-        android:protectionLevel="dangerous"
-        android:permissionFlags="removed" />
+        android:protectionLevel="dangerous" />
 
     <!-- Allows an application to write to external storage.
          <p class="note"><strong>Note:</strong> If <em>both</em> your <a
@@ -841,8 +840,7 @@
         android:permissionGroup="android.permission-group.UNDEFINED"
         android:label="@string/permlab_sdcardWrite"
         android:description="@string/permdesc_sdcardWrite"
-        android:protectionLevel="dangerous"
-        android:permissionFlags="removed" />
+        android:protectionLevel="dangerous" />
 
     <!-- Runtime permission controlling access to the user's shared aural media
          collection. -->
@@ -3929,6 +3927,10 @@
     <permission android:name="android.permission.MANAGE_ROLLBACKS"
         android:protectionLevel="signature|verifier" />
 
+    <!-- @SystemApi @TestApi @hide Allows testing apk level rollbacks. -->
+    <permission android:name="android.permission.TEST_MANAGE_ROLLBACKS"
+        android:protectionLevel="signature" />
+
     <!-- @SystemApi @hide Allows an application to mark other applications as harmful -->
     <permission android:name="android.permission.SET_HARMFUL_APP_WARNINGS"
         android:protectionLevel="signature|verifier" />
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 743496f..9d48fe3 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -8108,7 +8108,7 @@
 
     <!-- Use <code>autofill-service</code> as the root tag of the XML resource that describes a
          {@link android.service.autofill.AutofillService}, which is referenced from its
-         {@link android.service.autofill#SERVICE_META_DATA} meta-data entry.
+         {@link android.service.autofill.AutofillService#SERVICE_META_DATA} meta-data entry.
     -->
     <declare-styleable name="AutofillService">
         <!-- Fully qualified class name of an activity that allows the user to modify
@@ -8134,6 +8134,23 @@
     </declare-styleable>
 
     <!-- =============================== -->
+    <!-- Content Capture attributes -->
+    <!-- =============================== -->
+    <eat-comment />
+
+    <!-- Use <code>content-capture-service</code> as the root tag of the XML resource that describes
+         a {@link android.service.contentcapture.ContentCaptureService}, which is referenced from
+         its {@link android.service.contentcapture.ContentCaptureService#SERVICE_META_DATA}
+         meta-data entry.
+         @hide @SystemApi
+    -->
+    <declare-styleable name="ContentCaptureService">
+        <!-- Fully qualified class name of an activity that allows the user to modify
+             the settings for this service. -->
+        <attr name="settingsActivity" />
+    </declare-styleable>
+
+    <!-- =============================== -->
     <!-- Contacts meta-data attributes -->
     <!-- =============================== -->
     <eat-comment />
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index dbea13e..fe2c665 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -118,8 +118,11 @@
     <attr name="manageSpaceActivity" format="string" />
 
     <!-- Option to let applications specify that user data can/cannot be
-         cleared by the user in Settings. This flag is turned on by default.
-         <em>This attribute is usable only by applications
+         cleared. This flag is turned on by default.
+         <p>Starting from API level 29 this flag only controls if the user can
+         clear app data from Settings. To control clearing the data after a
+         failed restore use allowClearUserDataOnFailedRestore flag.
+         <p><em>This attribute is usable only by applications
          included in the system image. Third-party apps cannot use it.</em> -->
     <attr name="allowClearUserData" format="boolean" />
 
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 71e071c..de02286 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -58,6 +58,7 @@
         <item><xliff:g id="id">@string/status_bar_mobile</xliff:g></item>
         <item><xliff:g id="id">@string/status_bar_airplane</xliff:g></item>
         <item><xliff:g id="id">@string/status_bar_battery</xliff:g></item>
+        <item><xliff:g id="id">@string/status_bar_sensors_off</xliff:g></item>
     </string-array>
 
     <string translatable="false" name="status_bar_rotate">rotate</string>
@@ -92,6 +93,7 @@
     <string translatable="false" name="status_bar_microphone">microphone</string>
     <string translatable="false" name="status_bar_camera">camera</string>
     <string translatable="false" name="status_bar_airplane">airplane</string>
+    <string translatable="false" name="status_bar_sensors_off">sensors_off</string>
 
     <!-- Flag indicating whether the surface flinger has limited
          alpha compositing functionality in hardware.  If set, the window
diff --git a/core/res/res/values/dimens_car.xml b/core/res/res/values/dimens_car.xml
index d2cf40a..7b3ac2e 100644
--- a/core/res/res/values/dimens_car.xml
+++ b/core/res/res/values/dimens_car.xml
@@ -21,6 +21,7 @@
     <dimen name="car_fullscreen_user_pod_height">356dp</dimen>
     <dimen name="car_fullscreen_user_pod_image_avatar_width">96dp</dimen>
     <dimen name="car_fullscreen_user_pod_image_avatar_height">96dp</dimen>
+    <dimen name="car_large_avatar_size">96dp</dimen>
 
 
     <!-- Application Bar -->
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 2b13c4e..24fd3a8 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -1538,43 +1538,45 @@
     <string name="permdesc_useFaceAuthentication">Allows the app to use face authentication hardware for authentication</string>
 
     <!-- Message shown during face acquisition when the face cannot be recognized [CHAR LIMIT=50] -->
-    <string name="face_acquired_insufficient">Couldn\u2019t process face. Please try again.</string>
+    <string name="face_acquired_insufficient">Couldn\u2019t capture accurate face data. Try again.</string>
     <!-- Message shown during face acquisition when the image is too bright [CHAR LIMIT=50] -->
-    <string name="face_acquired_too_bright">Face is too bright. Please try in lower light.</string>
+    <string name="face_acquired_too_bright">Too bright. Try gentler lighting.</string>
     <!-- Message shown during face acquisition when the image is too dark [CHAR LIMIT=50] -->
-    <string name="face_acquired_too_dark">Face is too dark. Please uncover light source.</string>
+    <string name="face_acquired_too_dark">Too dark. Try brighter lighting.</string>
     <!-- Message shown during face acquisition when the user is too close to sensor [CHAR LIMIT=50] -->
-    <string name="face_acquired_too_close">Please move sensor farther from face.</string>
+    <string name="face_acquired_too_close">Move phone farther away.</string>
     <!-- Message shown during face acquisition when the user is too far from sensor [CHAR LIMIT=50] -->
-    <string name="face_acquired_too_far">Please bring sensor closer to face.</string>
+    <string name="face_acquired_too_far">Move phone closer.</string>
     <!-- Message shown during face acquisition when the user is too high relatively to sensor [CHAR LIMIT=50] -->
-    <string name="face_acquired_too_high">Please move sensor higher.</string>
+    <string name="face_acquired_too_high">Move phone higher.</string>
     <!-- Message shown during face acquisition when the user is too low relatively to sensor [CHAR LIMIT=50] -->
-    <string name="face_acquired_too_low">Please move sensor lower.</string>
+    <string name="face_acquired_too_low">Move phone lower.</string>
     <!-- Message shown during face acquisition when the user is too right relatively to sensor [CHAR LIMIT=50] -->
-    <string name="face_acquired_too_right">Please move sensor to the right.</string>
+    <string name="face_acquired_too_right">Move phone to the right.</string>
     <!-- Message shown during face acquisition when the user is too left relatively to sensor [CHAR LIMIT=50] -->
-    <string name="face_acquired_too_left">Please move sensor to the left.</string>
+    <string name="face_acquired_too_left">Move phone to the left.</string>
     <!-- Message shown during face acquisition when the user is not front facing the sensor [CHAR LIMIT=50] -->
-    <string name="face_acquired_poor_gaze">Please look at the sensor.</string>
+    <string name="face_acquired_poor_gaze">Look at the screen with your eyes open.</string>
     <!-- Message shown during face acquisition when the user is not detected [CHAR LIMIT=50] -->
-    <string name="face_acquired_not_detected">No face detected.</string>
+    <string name="face_acquired_not_detected">Can\u2019t see your face. Look at the phone.</string>
     <!-- Message shown during face acquisition when the device is not steady [CHAR LIMIT=50] -->
-    <string name="face_acquired_too_much_motion">Too much motion.</string>
+    <string name="face_acquired_too_much_motion">Too much motion. Hold phone steady.</string>
     <!-- Message shown during face acquisition when the sensor needs to be recalibrated [CHAR LIMIT=50] -->
     <string name="face_acquired_recalibrate">Please re-enroll your face.</string>
     <!-- Message shown during face enrollment when a different person's face is detected [CHAR LIMIT=50] -->
-    <string name="face_acquired_too_different">Different face detected.</string>
+    <string name="face_acquired_too_different">No longer able to recognize face. Try again.</string>
     <!-- Message shown during face enrollment when the face is too similar to a previous acquisition [CHAR LIMIT=50] -->
     <string name="face_acquired_too_similar">Too similar, please change your pose.</string>
     <!-- Message shown during acqusition when the user's face is turned too far left or right [CHAR LIMIT=50] -->
-    <string name="face_acquired_pan_too_extreme">Please look more directly at the camera.</string>
+    <string name="face_acquired_pan_too_extreme">Please look more directly at the screen.</string>
     <!-- Message shown during acqusition when the user's face is tilted too high or too low [CHAR LIMIT=50] -->
-    <string name="face_acquired_tilt_too_extreme">Please look more directly at the camera.</string>
+    <string name="face_acquired_tilt_too_extreme">Please look more directly at the screen.</string>
     <!-- Message shown during acquisiton when the user's face is tilted too far left or right [CHAR LIMIT=50] -->
     <string name="face_acquired_roll_too_extreme">Please straighten your head vertically.</string>
     <!-- Message shown during acquisition when the user's face is obscured [CHAR LIMIT=50] -->
-    <string name="face_acquired_obscured">Please uncover your face.</string>
+    <string name="face_acquired_obscured">Clear the space between your head and the phone.</string>
+    <!-- Message shown during acquisition when the sensor is dirty [CHAR LIMIT=50] -->
+    <string name="face_acquired_sensor_dirty">Please clean the camera.</string>
     <!-- Array containing custom messages shown during face acquisition from vendor.  Vendor is expected to add and translate these strings -->
     <string-array name="face_acquired_vendor">
     </string-array>
@@ -5293,6 +5295,14 @@
     <!-- Summary of notification letting users know why battery saver was turned on automatically [CHAR_LIMIT=NONE]-->
     <string name="dynamic_mode_notification_summary">Battery Saver activated to extend battery life</string>
 
+    <!-- Battery saver strings -->
+    <!-- The user visible name of the notification channel for battery saver notifications [CHAR_LIMIT=80] -->
+    <string name="battery_saver_notification_channel_name">Battery Saver</string>
+    <!-- Title of notification letting users know why battery saver didn't turn back on automatically after the device was unplugged [CHAR_LIMIT=NONE] -->
+    <string name="battery_saver_sticky_disabled_notification_title">Battery Saver won\u2019t reactivate until battery low again</string>
+    <!-- Summary of notification letting users know why battery saver didn't turn back on automatically after the device was unplugged [CHAR_LIMIT=NONE] -->
+    <string name="battery_saver_sticky_disabled_notification_summary">Battery has been charged to a sufficient level. Battery Saver won\u2019t reactivate until the battery is low again.</string>
+
     <!-- Description of media type: folder or directory that contains additional files. [CHAR LIMIT=32] -->
     <string name="mime_type_folder">Folder</string>
     <!-- Description of media type: application file, such as APK. [CHAR LIMIT=32] -->
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index e5fc104..ba964bb 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -2546,6 +2546,7 @@
   <java-symbol type="string" name="face_acquired_tilt_too_extreme" />
   <java-symbol type="string" name="face_acquired_roll_too_extreme" />
   <java-symbol type="string" name="face_acquired_obscured" />
+  <java-symbol type="string" name="face_acquired_sensor_dirty" />
   <java-symbol type="array" name="face_acquired_vendor" />
   <java-symbol type="string" name="face_name_template" />
   <java-symbol type="string" name="face_authenticated_no_confirmation_required" />
@@ -2923,6 +2924,7 @@
   <java-symbol type="string" name="status_bar_vpn" />
   <java-symbol type="string" name="status_bar_microphone" />
   <java-symbol type="string" name="status_bar_camera" />
+  <java-symbol type="string" name="status_bar_sensors_off" />
 
   <!-- Locale picker -->
   <java-symbol type="id" name="locale_search_menu" />
@@ -3587,6 +3589,7 @@
   <java-symbol type="dimen" name="car_fullscreen_user_pod_icon_text_size" />
   <java-symbol type="dimen" name="car_fullscreen_user_pod_image_avatar_height" />
   <java-symbol type="dimen" name="car_fullscreen_user_pod_image_avatar_width" />
+  <java-symbol type="dimen" name="car_large_avatar_size" />
   <java-symbol type="layout" name="car_user_switching_dialog" />
   <java-symbol type="id" name="user_loading_avatar" />
   <java-symbol type="id" name="user_loading" />
@@ -3642,6 +3645,9 @@
   <!-- For Secondary Launcher -->
   <java-symbol type="string" name="config_secondaryHomeComponent" />
 
+  <java-symbol type="string" name="battery_saver_notification_channel_name" />
+  <java-symbol type="string" name="battery_saver_sticky_disabled_notification_title" />
+  <java-symbol type="string" name="battery_saver_sticky_disabled_notification_summary" />
   <java-symbol type="string" name="dynamic_mode_notification_channel_name" />
   <java-symbol type="string" name="dynamic_mode_notification_title" />
   <java-symbol type="string" name="dynamic_mode_notification_summary" />
diff --git a/core/tests/coretests/src/android/provider/SettingsBackupTest.java b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
index 7322a54..85947bd 100644
--- a/core/tests/coretests/src/android/provider/SettingsBackupTest.java
+++ b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
@@ -623,7 +623,6 @@
                  Settings.Secure.DEFAULT_INPUT_METHOD,
                  Settings.Secure.DEVICE_PAIRED,
                  Settings.Secure.DIALER_DEFAULT_APPLICATION,
-                 Settings.Secure.DISABLE_AIRPLANE_MODE_AFTER_SP_DISABLED,
                  Settings.Secure.DISABLED_PRINT_SERVICES,
                  Settings.Secure.DISABLED_SYSTEM_INPUT_METHODS,
                  Settings.Secure.DISPLAY_DENSITY_FORCED,
@@ -647,8 +646,6 @@
                  Settings.Secure.LOCK_SCREEN_ALLOW_REMOTE_INPUT, // Candidate?
                  Settings.Secure.LOCK_SCREEN_LOCK_AFTER_TIMEOUT,
                  Settings.Secure.LOCK_TO_APP_EXIT_LOCKED,
-                 Settings.Secure.MAINTAIN_AIRPLANE_MODE_AFTER_SP_DISABLED,
-                 Settings.Secure.MAINTAIN_LOCATION_AFTER_SP_DISABLED,
                  Settings.Secure.MANAGED_PROFILE_CONTACT_REMOTE_SEARCH,
                  Settings.Secure.MULTI_PRESS_TIMEOUT,
                  Settings.Secure.NFC_PAYMENT_FOREGROUND,
@@ -656,12 +653,12 @@
                  Settings.Secure.NIGHT_DISPLAY_LAST_ACTIVATED_TIME,
                  Settings.Secure.NUM_ROTATION_SUGGESTIONS_ACCEPTED,
                  Settings.Secure.ODI_CAPTIONS_ENABLED,
+                 Settings.Secure.ODI_CAPTIONS_OPTED_OUT,
                  Settings.Secure.PACKAGE_VERIFIER_STATE,
                  Settings.Secure.PACKAGE_VERIFIER_USER_CONSENT,
                  Settings.Secure.PARENTAL_CONTROL_LAST_UPDATE,
                  Settings.Secure.PAYMENT_SERVICE_SEARCH_URI,
                  Settings.Secure.PRINT_SERVICE_SEARCH_URI,
-                 Settings.Secure.REENABLE_LOCATION_AFTER_SP_DISABLED,
                  Settings.Secure.SCREENSAVER_DEFAULT_COMPONENT, // Candidate?
                  Settings.Secure.SEARCH_GLOBAL_SEARCH_ACTIVITY,
                  Settings.Secure.SEARCH_MAX_RESULTS_PER_SOURCE,
@@ -685,7 +682,6 @@
                  Settings.Secure.SELECTED_INPUT_METHOD_SUBTYPE,
                  Settings.Secure.SELECTED_SPELL_CHECKER,  // Intentionally removed in Q
                  Settings.Secure.SELECTED_SPELL_CHECKER_SUBTYPE,  // Intentionally removed in Q
-                 Settings.Secure.SENSOR_PRIVACY_SENSOR_STATE,
                  Settings.Secure.SETTINGS_CLASSNAME,
                  Settings.Secure.SHOW_NOTE_ABOUT_NOTIFICATION_HIDING, // candidate?
                  Settings.Secure.SHOW_ROTATION_SUGGESTIONS,
diff --git a/core/tests/coretests/src/android/view/InsetsSourceConsumerTest.java b/core/tests/coretests/src/android/view/InsetsSourceConsumerTest.java
index 66146c9..4266ba9f 100644
--- a/core/tests/coretests/src/android/view/InsetsSourceConsumerTest.java
+++ b/core/tests/coretests/src/android/view/InsetsSourceConsumerTest.java
@@ -24,10 +24,16 @@
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.verifyZeroInteractions;
 
+import android.app.Instrumentation;
+import android.content.Context;
 import android.graphics.Point;
 import android.platform.test.annotations.Presubmit;
 import android.view.SurfaceControl.Transaction;
+import android.view.WindowManager.BadTokenException;
+import android.view.WindowManager.LayoutParams;
+import android.widget.TextView;
 
+import androidx.test.InstrumentationRegistry;
 import androidx.test.filters.FlakyTest;
 import androidx.test.runner.AndroidJUnit4;
 
@@ -47,7 +53,6 @@
     private SurfaceSession mSession = new SurfaceSession();
     private SurfaceControl mLeash;
     @Mock Transaction mMockTransaction;
-    @Mock InsetsController mMockController;
 
     @Before
     public void setup() {
@@ -55,8 +60,21 @@
         mLeash = new SurfaceControl.Builder(mSession)
                 .setName("testSurface")
                 .build();
-        mConsumer = new InsetsSourceConsumer(TYPE_TOP_BAR, new InsetsState(),
-                () -> mMockTransaction, mMockController);
+        final Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation();
+        instrumentation.runOnMainSync(() -> {
+            final Context context = instrumentation.getTargetContext();
+            // cannot mock ViewRootImpl since it's final.
+            final ViewRootImpl viewRootImpl = new ViewRootImpl(context, context.getDisplay());
+            try {
+                viewRootImpl.setView(new TextView(context), new LayoutParams(), null);
+            } catch (BadTokenException e) {
+                // activity isn't running, lets ignore BadTokenException.
+            }
+            mConsumer = new InsetsSourceConsumer(TYPE_TOP_BAR, new InsetsState(),
+                    () -> mMockTransaction, new InsetsController(viewRootImpl));
+        });
+        instrumentation.waitForIdleSync();
+
         mConsumer.setControl(new InsetsSourceControl(TYPE_TOP_BAR, mLeash, new Point()));
     }
 
diff --git a/core/tests/coretests/src/android/view/textclassifier/ActionsSuggestionsHelperTest.java b/core/tests/coretests/src/android/view/textclassifier/ActionsSuggestionsHelperTest.java
index 5c7287f..67423c8 100644
--- a/core/tests/coretests/src/android/view/textclassifier/ActionsSuggestionsHelperTest.java
+++ b/core/tests/coretests/src/android/view/textclassifier/ActionsSuggestionsHelperTest.java
@@ -215,6 +215,7 @@
                         ConversationAction.TYPE_OPEN_URL,
                         1.0f,
                         null,
+                        null,
                         null
                 );
 
@@ -235,6 +236,7 @@
                         ConversationAction.TYPE_OPEN_URL,
                         1.0f,
                         null,
+                        null,
                         new RemoteActionTemplate[0]
                 );
 
@@ -255,6 +257,7 @@
                         ConversationAction.TYPE_OPEN_URL,
                         1.0f,
                         null,
+                        null,
                         new RemoteActionTemplate[]{
                                 new RemoteActionTemplate(
                                         "title",
diff --git a/core/tests/coretests/src/android/view/textclassifier/intent/LegacyIntentClassificationFactoryTest.java b/core/tests/coretests/src/android/view/textclassifier/intent/LegacyIntentClassificationFactoryTest.java
index 19e5b0a..72d1ab1 100644
--- a/core/tests/coretests/src/android/view/textclassifier/intent/LegacyIntentClassificationFactoryTest.java
+++ b/core/tests/coretests/src/android/view/textclassifier/intent/LegacyIntentClassificationFactoryTest.java
@@ -63,6 +63,7 @@
                         null,
                         null,
                         null,
+                        null,
                         null);
 
         List<LabeledIntent> intents = mLegacyIntentClassificationFactory.create(
@@ -96,6 +97,7 @@
                         null,
                         null,
                         null,
+                        null,
                         null);
 
         List<LabeledIntent> intents = mLegacyIntentClassificationFactory.create(
diff --git a/core/tests/coretests/src/android/view/textclassifier/intent/TemplateClassificationIntentFactoryTest.java b/core/tests/coretests/src/android/view/textclassifier/intent/TemplateClassificationIntentFactoryTest.java
index eaef0a0..ccf8607 100644
--- a/core/tests/coretests/src/android/view/textclassifier/intent/TemplateClassificationIntentFactoryTest.java
+++ b/core/tests/coretests/src/android/view/textclassifier/intent/TemplateClassificationIntentFactoryTest.java
@@ -81,6 +81,7 @@
                         null,
                         null,
                         null,
+                        null,
                         createRemoteActionTemplates());
 
         List<LabeledIntent> intents =
@@ -119,6 +120,7 @@
                         null,
                         null,
                         null,
+                        null,
                         createRemoteActionTemplates());
 
         List<LabeledIntent> intents =
@@ -153,6 +155,7 @@
                         null,
                         null,
                         null,
+                        null,
                         null);
 
         mTemplateClassificationIntentFactory.create(
@@ -185,6 +188,7 @@
                         null,
                         null,
                         null,
+                        null,
                         new RemoteActionTemplate[0]);
 
         mTemplateClassificationIntentFactory.create(
diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryStatsCounterTest.java b/core/tests/coretests/src/com/android/internal/os/BatteryStatsCounterTest.java
index 37f818a..ade3a99 100644
--- a/core/tests/coretests/src/com/android/internal/os/BatteryStatsCounterTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryStatsCounterTest.java
@@ -44,8 +44,6 @@
         counter.stepAtomic();
         counter.stepAtomic();
         assertEquals(0, counter.getCountLocked(BatteryStats.STATS_SINCE_CHARGED));
-        assertEquals(0, counter.getCountLocked(BatteryStats.STATS_CURRENT));
-        assertEquals(0, counter.getCountLocked(BatteryStats.STATS_SINCE_UNPLUGGED));
 
         // timeBase on (i.e. unplugged)
         timeBase.setRunning(true, 2, 2);
@@ -54,8 +52,6 @@
         counter.stepAtomic();
         counter.stepAtomic();
         assertEquals(4, counter.getCountLocked(BatteryStats.STATS_SINCE_CHARGED));
-        assertEquals(4, counter.getCountLocked(BatteryStats.STATS_CURRENT));
-        assertEquals(4, counter.getCountLocked(BatteryStats.STATS_SINCE_UNPLUGGED));
 
         // timeBase off (i.e. plugged in)
         timeBase.setRunning(false, 3, 3);
@@ -63,16 +59,12 @@
         counter.stepAtomic();
         counter.stepAtomic();
         assertEquals(4, counter.getCountLocked(BatteryStats.STATS_SINCE_CHARGED));
-        assertEquals(4, counter.getCountLocked(BatteryStats.STATS_CURRENT));
-        assertEquals(4, counter.getCountLocked(BatteryStats.STATS_SINCE_UNPLUGGED));
 
         // timeBase on (i.e. unplugged)
         timeBase.setRunning(true, 4, 4);
         counter.stepAtomic();
         counter.stepAtomic();
         assertEquals(6, counter.getCountLocked(BatteryStats.STATS_SINCE_CHARGED));
-        assertEquals(6, counter.getCountLocked(BatteryStats.STATS_CURRENT));
-        assertEquals(2, counter.getCountLocked(BatteryStats.STATS_SINCE_UNPLUGGED));
     }
 
 
@@ -88,8 +80,6 @@
         timeBase.setRunning(true, 1, 1);
         origCounter.stepAtomic(); origCounter.stepAtomic(); origCounter.stepAtomic(); // three times
         assertEquals(3, origCounter.getCountLocked(BatteryStats.STATS_SINCE_CHARGED));
-        assertEquals(3, origCounter.getCountLocked(BatteryStats.STATS_CURRENT));
-        assertEquals(3, origCounter.getCountLocked(BatteryStats.STATS_SINCE_UNPLUGGED));
 
         // Test summary parcelling (from origCounter)
         final Parcel summaryParcel = Parcel.obtain();
@@ -102,22 +92,16 @@
         // timeBase still on (i.e. unplugged)
         summaryCounter.stepAtomic(); // once
         assertEquals(4, summaryCounter.getCountLocked(BatteryStats.STATS_SINCE_CHARGED));
-        assertEquals(1, summaryCounter.getCountLocked(BatteryStats.STATS_CURRENT));
-        assertEquals(1, summaryCounter.getCountLocked(BatteryStats.STATS_SINCE_UNPLUGGED));
 
         // timeBase off (i.e. plugged in)
         timeBase.setRunning(false, 3, 3);
         summaryCounter.stepAtomic(); summaryCounter.stepAtomic(); // twice
         assertEquals(4, summaryCounter.getCountLocked(BatteryStats.STATS_SINCE_CHARGED));
-        assertEquals(1, summaryCounter.getCountLocked(BatteryStats.STATS_CURRENT));
-        assertEquals(1, summaryCounter.getCountLocked(BatteryStats.STATS_SINCE_UNPLUGGED));
 
         // timeBase on (i.e. unplugged)
         timeBase.setRunning(true, 4, 4);
         summaryCounter.stepAtomic(); summaryCounter.stepAtomic(); // twice
         assertEquals(6, summaryCounter.getCountLocked(BatteryStats.STATS_SINCE_CHARGED));
-        assertEquals(3, summaryCounter.getCountLocked(BatteryStats.STATS_CURRENT));
-        assertEquals(2, summaryCounter.getCountLocked(BatteryStats.STATS_SINCE_UNPLUGGED));
 
 
         // Test full parcelling (from summaryCounter)
@@ -130,21 +114,15 @@
         // timeBase still on (i.e. unplugged)
         fullParcelCounter.stepAtomic(); // once
         assertEquals(7, fullParcelCounter.getCountLocked(BatteryStats.STATS_SINCE_CHARGED));
-        assertEquals(4, fullParcelCounter.getCountLocked(BatteryStats.STATS_CURRENT));
-        assertEquals(3, fullParcelCounter.getCountLocked(BatteryStats.STATS_SINCE_UNPLUGGED));
 
         // timeBase off (i.e. plugged in)
         timeBase.setRunning(false, 5, 5);
         fullParcelCounter.stepAtomic(); fullParcelCounter.stepAtomic(); // twice
         assertEquals(7, fullParcelCounter.getCountLocked(BatteryStats.STATS_SINCE_CHARGED));
-        assertEquals(4, fullParcelCounter.getCountLocked(BatteryStats.STATS_CURRENT));
-        assertEquals(3, fullParcelCounter.getCountLocked(BatteryStats.STATS_SINCE_UNPLUGGED));
 
         // timeBase on (i.e. unplugged)
         timeBase.setRunning(true, 6, 6);
         fullParcelCounter.stepAtomic(); fullParcelCounter.stepAtomic(); // twice
         assertEquals(9, fullParcelCounter.getCountLocked(BatteryStats.STATS_SINCE_CHARGED));
-        assertEquals(6, fullParcelCounter.getCountLocked(BatteryStats.STATS_CURRENT));
-        assertEquals(2, fullParcelCounter.getCountLocked(BatteryStats.STATS_SINCE_UNPLUGGED));
     }
 }
diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryStatsDurationTimerTest.java b/core/tests/coretests/src/com/android/internal/os/BatteryStatsDurationTimerTest.java
index a42286f..78fa3fb 100644
--- a/core/tests/coretests/src/com/android/internal/os/BatteryStatsDurationTimerTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryStatsDurationTimerTest.java
@@ -100,8 +100,70 @@
         assertEquals(30802, timer.getTotalDurationMsLocked(220302));
     }
 
+    /**
+     * Tests that reset(boolean detachIfReset) clears the correct times if detachIfReset is false.
+     */
     @SmallTest
     public void testReset() throws Exception {
+        final MockClocks clocks = new MockClocks();
+
+        final BatteryStatsImpl.TimeBase timeBase = new BatteryStatsImpl.TimeBase();
+        timeBase.init(clocks.uptimeMillis(), clocks.elapsedRealtime());
+
+        final BatteryStatsImpl.DurationTimer timer = new BatteryStatsImpl.DurationTimer(clocks,
+                null, BatteryStats.WAKE_TYPE_PARTIAL, null, timeBase);
+
+        timeBase.setRunning(true, /* uptimeUs */ 0, /* realtimeUs */ 100_000);
+        timer.startRunningLocked(700);
+        timer.stopRunningLocked(3_100);
+        assertFalse(timer.isRunningLocked());
+        assertEquals(0, timer.getCurrentDurationMsLocked(6_300));
+        assertEquals(2_400, timer.getMaxDurationMsLocked(6_301));
+        assertEquals(2_400, timer.getTotalDurationMsLocked(6_302));
+
+        timer.reset(false);
+        assertEquals(0, timer.getCurrentDurationMsLocked(12_000));
+        assertEquals(0, timer.getMaxDurationMsLocked(12_001));
+        assertEquals(0, timer.getTotalDurationMsLocked(12_002));
+
+        assertEquals(true, timeBase.hasObserver(timer));
+
+        timer.startRunningLocked(24_100);
+        clocks.uptime = clocks.realtime = 24_200;
+        timer.reset(false);
+        assertEquals(34_300, timer.getCurrentDurationMsLocked(58_500));
+        assertEquals(34_301, timer.getMaxDurationMsLocked(58_501));
+        assertEquals(34_302, timer.getTotalDurationMsLocked(58_502));
+    }
+
+    /**
+     * Tests that reset(boolean detachIfReset) clears the correct times if detachIfReset is true.
+     */
+    @SmallTest
+    public void testResetAndDetach() throws Exception {
+        final MockClocks clocks = new MockClocks();
+
+        final BatteryStatsImpl.TimeBase timeBase = new BatteryStatsImpl.TimeBase();
+        timeBase.init(clocks.uptimeMillis(), clocks.elapsedRealtime());
+
+        final BatteryStatsImpl.DurationTimer timer = new BatteryStatsImpl.DurationTimer(clocks,
+                null, BatteryStats.WAKE_TYPE_PARTIAL, null, timeBase);
+
+        timeBase.setRunning(true, /* uptimeUs */ 0, /* realtimeUs */ 100_000);
+        timer.startRunningLocked(700);
+        timer.stopRunningLocked(3_100);
+        assertFalse(timer.isRunningLocked());
+        assertEquals(0, timer.getCurrentDurationMsLocked(6_300));
+        assertEquals(2_400, timer.getMaxDurationMsLocked(6_301));
+        assertEquals(2_400, timer.getTotalDurationMsLocked(6_302));
+
+        timer.reset(true);
+        clocks.uptime = clocks.realtime = 7_000;
+        assertEquals(0, timer.getCurrentDurationMsLocked(8_000));
+        assertEquals(0, timer.getMaxDurationMsLocked(8_001));
+        assertEquals(0, timer.getTotalDurationMsLocked(8_002));
+
+        assertEquals(false, timeBase.hasObserver(timer));
     }
 
     @SmallTest
diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryStatsImplTest.java b/core/tests/coretests/src/com/android/internal/os/BatteryStatsImplTest.java
index 0771829..4b37dd2 100644
--- a/core/tests/coretests/src/com/android/internal/os/BatteryStatsImplTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryStatsImplTest.java
@@ -325,7 +325,7 @@
 
         // Get the total acquisition time
         long totalTime = u.getWifiMulticastTime(currentTimeMs*1000,
-                BatteryStats.STATS_SINCE_UNPLUGGED);
+                BatteryStats.STATS_SINCE_CHARGED);
         assertEquals("Miscalculations of Multicast wakelock acquisition time",
                 (releaseTimeMs - acquireTimeMs) * 1000, totalTime);
     }
@@ -347,7 +347,7 @@
 
         // Get the total acquisition time
         long totalTime =  u.getWifiMulticastTime(currentTimeMs*1000,
-                BatteryStats.STATS_SINCE_UNPLUGGED);
+                BatteryStats.STATS_SINCE_CHARGED);
         assertEquals("Miscalculations of Multicast wakelock acquisition time",
                 (currentTimeMs - acquireTimeMs) * 1000, totalTime);
     }
@@ -377,7 +377,7 @@
 
         // Get the total acquisition time
         long totalTime =  u.getWifiMulticastTime(currentTimeMs*1000,
-                BatteryStats.STATS_SINCE_UNPLUGGED);
+                BatteryStats.STATS_SINCE_CHARGED);
         assertEquals("Miscalculations of Multicast wakelock acquisition time",
                 (releaseTimeMs_2 - acquireTimeMs_1) * 1000, totalTime);
     }
@@ -407,7 +407,7 @@
 
         // Get the total acquisition time
         long totalTime =  u.getWifiMulticastTime(currentTimeMs*1000,
-                BatteryStats.STATS_SINCE_UNPLUGGED);
+                BatteryStats.STATS_SINCE_CHARGED);
         assertEquals("Miscalculations of Multicast wakelock acquisition time",
                 ((releaseTimeMs_1 - acquireTimeMs_1) + (releaseTimeMs_2 - acquireTimeMs_2))
                 * 1000, totalTime);
diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryStatsNoteTest.java b/core/tests/coretests/src/com/android/internal/os/BatteryStatsNoteTest.java
index 3e33273..8f5dfc5 100644
--- a/core/tests/coretests/src/com/android/internal/os/BatteryStatsNoteTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryStatsNoteTest.java
@@ -16,7 +16,6 @@
 
 package com.android.internal.os;
 
-import static android.os.BatteryStats.STATS_CURRENT;
 import static android.os.BatteryStats.STATS_SINCE_CHARGED;
 import static android.os.BatteryStats.WAKE_TYPE_PARTIAL;
 
@@ -388,7 +387,7 @@
         bi.noteWakupAlarmLocked("com.foo.bar", UID, null, "tag");
 
         Uid.Pkg pkg = bi.getPackageStatsLocked(UID, "com.foo.bar");
-        assertEquals(1, pkg.getWakeupAlarmStats().get("tag").getCountLocked(STATS_CURRENT));
+        assertEquals(1, pkg.getWakeupAlarmStats().get("tag").getCountLocked(STATS_SINCE_CHARGED));
         assertEquals(1, pkg.getWakeupAlarmStats().size());
     }
 
diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryStatsServTest.java b/core/tests/coretests/src/com/android/internal/os/BatteryStatsServTest.java
index b9995c4..df549c5 100644
--- a/core/tests/coretests/src/com/android/internal/os/BatteryStatsServTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryStatsServTest.java
@@ -44,15 +44,6 @@
             mLaunchedSince = 6064;
             mLaunched = true;
             mLaunches = 8085;
-            mLoadedStartTime = 9096;
-            mLoadedStarts = 10017;
-            mLoadedLaunches = 11118;
-            mLastStartTime = 12219;
-            mLastStarts = 13310;
-            mLastLaunches = 14411;
-            mUnpluggedStartTime = 15512;
-            mUnpluggedStarts = 16613;
-            mUnpluggedLaunches = 17714;
         }
 
         long getStartTime() {
@@ -94,42 +85,6 @@
         int getLaunches() {
             return mLaunches;
         }
-
-        long getLoadedStartTime() {
-            return mLoadedStartTime;
-        }
-
-        int getLoadedStarts() {
-            return mLoadedStarts;
-        }
-
-        int getLoadedLaunches() {
-            return mLoadedLaunches;
-        }
-
-        long getLastStartTime() {
-            return mLastStartTime;
-        }
-
-        int getLastStarts() {
-            return mLastStarts;
-        }
-
-        int getLastLaunches() {
-            return mLastLaunches;
-        }
-
-        long getUnpluggedStartTime() {
-            return mUnpluggedStartTime;
-        }
-
-        int getUnpluggedStarts() {
-            return mUnpluggedStarts;
-        }
-
-        int getUnpluggedLaunches() {
-            return mUnpluggedLaunches;
-        }
     }
 
     /**
@@ -147,29 +102,6 @@
     }
 
     /**
-     * Test OnTimeStarted
-     */
-    @SmallTest
-    public void testOnTimeStarted() throws Exception  {
-        MockBatteryStatsImpl bsi = new MockBatteryStatsImpl();
-        TestServ serv = new TestServ(bsi);
-
-        serv.populate();
-        serv.setRunning(true);
-        serv.onTimeStarted(111111, 20000, 222222);
-        Assert.assertEquals(18989, serv.getUnpluggedStartTime());
-        Assert.assertEquals(4042, serv.getUnpluggedStarts());
-        Assert.assertEquals(8085, serv.getUnpluggedLaunches());
-
-        serv.populate();
-        serv.setRunning(false);
-        serv.onTimeStarted(111111, 20000, 222222);
-        Assert.assertEquals(1010, serv.getUnpluggedStartTime());
-        Assert.assertEquals(4042, serv.getUnpluggedStarts());
-        Assert.assertEquals(8085, serv.getUnpluggedLaunches());
-    }
-
-    /**
      * Test parceling and unparceling.
      */
     @SmallTest
@@ -185,7 +117,7 @@
 
         TestServ serv = new TestServ(bsi);
         serv.readFromParcelLocked(parcel);
-   
+
         Assert.assertEquals(1010, serv.getStartTime());
         Assert.assertEquals(2021, serv.getRunningSince());
         Assert.assertTrue(serv.getRunning());
@@ -194,15 +126,8 @@
         Assert.assertEquals(6064, serv.getLaunchedSince());
         Assert.assertTrue(serv.getLaunched());
         Assert.assertEquals(8085, serv.getLaunches());
-        Assert.assertEquals(9096, serv.getLoadedStartTime());
-        Assert.assertEquals(10017, serv.getLoadedStarts());
-        Assert.assertEquals(11118, serv.getLoadedLaunches());
-        Assert.assertEquals(0, serv.getLastStartTime());
-        Assert.assertEquals(0, serv.getLastStarts());
-        Assert.assertEquals(0, serv.getLastLaunches());
-        Assert.assertEquals(15512, serv.getUnpluggedStartTime());
-        Assert.assertEquals(16613, serv.getUnpluggedStarts());
-        Assert.assertEquals(17714, serv.getUnpluggedLaunches());
+
+        parcel.recycle();
     }
 
     /**
@@ -267,15 +192,6 @@
         Assert.assertEquals(6064, serv.getLaunchedSince());
         Assert.assertTrue(serv.getLaunched());
         Assert.assertEquals(8085, serv.getLaunches());
-        Assert.assertEquals(9096, serv.getLoadedStartTime());
-        Assert.assertEquals(10017, serv.getLoadedStarts());
-        Assert.assertEquals(11118, serv.getLoadedLaunches());
-        Assert.assertEquals(12219, serv.getLastStartTime());
-        Assert.assertEquals(13310, serv.getLastStarts());
-        Assert.assertEquals(14411, serv.getLastLaunches());
-        Assert.assertEquals(15512, serv.getUnpluggedStartTime());
-        Assert.assertEquals(16613, serv.getUnpluggedStarts());
-        Assert.assertEquals(17714, serv.getUnpluggedLaunches());
     }
 
     /**
@@ -303,15 +219,6 @@
         Assert.assertEquals(777777L, serv.getLaunchedSince()); // <-- changed
         Assert.assertTrue(serv.getLaunched()); // <-- changed
         Assert.assertEquals(8086, serv.getLaunches()); // <-- changed
-        Assert.assertEquals(9096, serv.getLoadedStartTime());
-        Assert.assertEquals(10017, serv.getLoadedStarts());
-        Assert.assertEquals(11118, serv.getLoadedLaunches());
-        Assert.assertEquals(12219, serv.getLastStartTime());
-        Assert.assertEquals(13310, serv.getLastStarts());
-        Assert.assertEquals(14411, serv.getLastLaunches());
-        Assert.assertEquals(15512, serv.getUnpluggedStartTime());
-        Assert.assertEquals(16613, serv.getUnpluggedStarts());
-        Assert.assertEquals(17714, serv.getUnpluggedLaunches());
     }
 
     /**
@@ -341,15 +248,6 @@
         Assert.assertEquals(6064, serv.getLaunchedSince());
         Assert.assertFalse(serv.getLaunched());
         Assert.assertEquals(8085, serv.getLaunches());
-        Assert.assertEquals(9096, serv.getLoadedStartTime());
-        Assert.assertEquals(10017, serv.getLoadedStarts());
-        Assert.assertEquals(11118, serv.getLoadedLaunches());
-        Assert.assertEquals(12219, serv.getLastStartTime());
-        Assert.assertEquals(13310, serv.getLastStarts());
-        Assert.assertEquals(14411, serv.getLastLaunches());
-        Assert.assertEquals(15512, serv.getUnpluggedStartTime());
-        Assert.assertEquals(16613, serv.getUnpluggedStarts());
-        Assert.assertEquals(17714, serv.getUnpluggedLaunches());
     }
 
     /**
@@ -375,19 +273,10 @@
         Assert.assertEquals(2021, serv.getRunningSince());
         Assert.assertTrue(serv.getRunning());
         Assert.assertEquals(4042, serv.getStarts());
-        Assert.assertEquals(777777L-6064+5053, serv.getLaunchedTime()); // <-- changed 
+        Assert.assertEquals(777777L-6064+5053, serv.getLaunchedTime()); // <-- changed
         Assert.assertEquals(6064, serv.getLaunchedSince());
         Assert.assertFalse(serv.getLaunched());
         Assert.assertEquals(8085, serv.getLaunches());
-        Assert.assertEquals(9096, serv.getLoadedStartTime());
-        Assert.assertEquals(10017, serv.getLoadedStarts());
-        Assert.assertEquals(11118, serv.getLoadedLaunches());
-        Assert.assertEquals(12219, serv.getLastStartTime());
-        Assert.assertEquals(13310, serv.getLastStarts());
-        Assert.assertEquals(14411, serv.getLastLaunches());
-        Assert.assertEquals(15512, serv.getUnpluggedStartTime());
-        Assert.assertEquals(16613, serv.getUnpluggedStarts());
-        Assert.assertEquals(17714, serv.getUnpluggedLaunches());
     }
 
     /**
@@ -416,16 +305,7 @@
         Assert.assertEquals(5053, serv.getLaunchedTime());
         Assert.assertEquals(6064, serv.getLaunchedSince());
         Assert.assertFalse(serv.getLaunched());
-        Assert.assertEquals(8085-1, serv.getLaunches()); // <-- changed 
-        Assert.assertEquals(9096, serv.getLoadedStartTime());
-        Assert.assertEquals(10017, serv.getLoadedStarts());
-        Assert.assertEquals(11118, serv.getLoadedLaunches());
-        Assert.assertEquals(12219, serv.getLastStartTime());
-        Assert.assertEquals(13310, serv.getLastStarts());
-        Assert.assertEquals(14411, serv.getLastLaunches());
-        Assert.assertEquals(15512, serv.getUnpluggedStartTime());
-        Assert.assertEquals(16613, serv.getUnpluggedStarts());
-        Assert.assertEquals(17714, serv.getUnpluggedLaunches());
+        Assert.assertEquals(8085-1, serv.getLaunches()); // <-- changed
     }
 
     /**
@@ -455,15 +335,6 @@
         Assert.assertEquals(6064, serv.getLaunchedSince());
         Assert.assertTrue(serv.getLaunched());
         Assert.assertEquals(8085, serv.getLaunches());
-        Assert.assertEquals(9096, serv.getLoadedStartTime());
-        Assert.assertEquals(10017, serv.getLoadedStarts());
-        Assert.assertEquals(11118, serv.getLoadedLaunches());
-        Assert.assertEquals(12219, serv.getLastStartTime());
-        Assert.assertEquals(13310, serv.getLastStarts());
-        Assert.assertEquals(14411, serv.getLastLaunches());
-        Assert.assertEquals(15512, serv.getUnpluggedStartTime());
-        Assert.assertEquals(16613, serv.getUnpluggedStarts());
-        Assert.assertEquals(17714, serv.getUnpluggedLaunches());
     }
 
     /**
@@ -492,15 +363,6 @@
         Assert.assertEquals(6064, serv.getLaunchedSince());
         Assert.assertTrue(serv.getLaunched());
         Assert.assertEquals(8085, serv.getLaunches());
-        Assert.assertEquals(9096, serv.getLoadedStartTime());
-        Assert.assertEquals(10017, serv.getLoadedStarts());
-        Assert.assertEquals(11118, serv.getLoadedLaunches());
-        Assert.assertEquals(12219, serv.getLastStartTime());
-        Assert.assertEquals(13310, serv.getLastStarts());
-        Assert.assertEquals(14411, serv.getLastLaunches());
-        Assert.assertEquals(15512, serv.getUnpluggedStartTime());
-        Assert.assertEquals(16613, serv.getUnpluggedStarts());
-        Assert.assertEquals(17714, serv.getUnpluggedLaunches());
     }
 
     /**
@@ -530,15 +392,6 @@
         Assert.assertEquals(6064, serv.getLaunchedSince());
         Assert.assertTrue(serv.getLaunched());
         Assert.assertEquals(8085, serv.getLaunches());
-        Assert.assertEquals(9096, serv.getLoadedStartTime());
-        Assert.assertEquals(10017, serv.getLoadedStarts());
-        Assert.assertEquals(11118, serv.getLoadedLaunches());
-        Assert.assertEquals(12219, serv.getLastStartTime());
-        Assert.assertEquals(13310, serv.getLastStarts());
-        Assert.assertEquals(14411, serv.getLastLaunches());
-        Assert.assertEquals(15512, serv.getUnpluggedStartTime());
-        Assert.assertEquals(16613, serv.getUnpluggedStarts());
-        Assert.assertEquals(17714, serv.getUnpluggedLaunches());
     }
 
     /**
@@ -568,15 +421,6 @@
         Assert.assertEquals(6064, serv.getLaunchedSince());
         Assert.assertTrue(serv.getLaunched());
         Assert.assertEquals(8085, serv.getLaunches());
-        Assert.assertEquals(9096, serv.getLoadedStartTime());
-        Assert.assertEquals(10017, serv.getLoadedStarts());
-        Assert.assertEquals(11118, serv.getLoadedLaunches());
-        Assert.assertEquals(12219, serv.getLastStartTime());
-        Assert.assertEquals(13310, serv.getLastStarts());
-        Assert.assertEquals(14411, serv.getLastLaunches());
-        Assert.assertEquals(15512, serv.getUnpluggedStartTime());
-        Assert.assertEquals(16613, serv.getUnpluggedStarts());
-        Assert.assertEquals(17714, serv.getUnpluggedLaunches());
     }
 
     /**
@@ -600,8 +444,6 @@
         serv.populate();
 
         Assert.assertEquals(8085, serv.getLaunches(BatteryStats.STATS_SINCE_CHARGED));
-        Assert.assertEquals(8085-11118, serv.getLaunches(BatteryStats.STATS_CURRENT));
-        Assert.assertEquals(8085-17714, serv.getLaunches(BatteryStats.STATS_SINCE_UNPLUGGED));
 
         // No change to fields
         Assert.assertEquals(1010, serv.getStartTime());
@@ -612,15 +454,6 @@
         Assert.assertEquals(6064, serv.getLaunchedSince());
         Assert.assertTrue(serv.getLaunched());
         Assert.assertEquals(8085, serv.getLaunches());
-        Assert.assertEquals(9096, serv.getLoadedStartTime());
-        Assert.assertEquals(10017, serv.getLoadedStarts());
-        Assert.assertEquals(11118, serv.getLoadedLaunches());
-        Assert.assertEquals(12219, serv.getLastStartTime());
-        Assert.assertEquals(13310, serv.getLastStarts());
-        Assert.assertEquals(14411, serv.getLastLaunches());
-        Assert.assertEquals(15512, serv.getUnpluggedStartTime());
-        Assert.assertEquals(16613, serv.getUnpluggedStarts());
-        Assert.assertEquals(17714, serv.getUnpluggedLaunches());
     }
 
     /**
@@ -637,10 +470,6 @@
 
         Assert.assertEquals(startTimeToNow,
                 serv.getStartTime(20000, BatteryStats.STATS_SINCE_CHARGED));
-        Assert.assertEquals(startTimeToNow-9096,
-                serv.getStartTime(20000, BatteryStats.STATS_CURRENT));
-        Assert.assertEquals(startTimeToNow-15512,
-                serv.getStartTime(20000, BatteryStats.STATS_SINCE_UNPLUGGED));
 
         // No change to fields
         Assert.assertEquals(1010, serv.getStartTime());
@@ -651,15 +480,6 @@
         Assert.assertEquals(6064, serv.getLaunchedSince());
         Assert.assertTrue(serv.getLaunched());
         Assert.assertEquals(8085, serv.getLaunches());
-        Assert.assertEquals(9096, serv.getLoadedStartTime());
-        Assert.assertEquals(10017, serv.getLoadedStarts());
-        Assert.assertEquals(11118, serv.getLoadedLaunches());
-        Assert.assertEquals(12219, serv.getLastStartTime());
-        Assert.assertEquals(13310, serv.getLastStarts());
-        Assert.assertEquals(14411, serv.getLastLaunches());
-        Assert.assertEquals(15512, serv.getUnpluggedStartTime());
-        Assert.assertEquals(16613, serv.getUnpluggedStarts());
-        Assert.assertEquals(17714, serv.getUnpluggedLaunches());
     }
 
     /**
@@ -676,10 +496,6 @@
 
         Assert.assertEquals(startTimeToNow,
                 serv.getStartTime(20000, BatteryStats.STATS_SINCE_CHARGED));
-        Assert.assertEquals(startTimeToNow-9096,
-                serv.getStartTime(20000, BatteryStats.STATS_CURRENT));
-        Assert.assertEquals(startTimeToNow-15512,
-                serv.getStartTime(20000, BatteryStats.STATS_SINCE_UNPLUGGED));
 
         // No change to fields
         Assert.assertEquals(1010, serv.getStartTime());
@@ -690,15 +506,6 @@
         Assert.assertEquals(6064, serv.getLaunchedSince());
         Assert.assertTrue(serv.getLaunched());
         Assert.assertEquals(8085, serv.getLaunches());
-        Assert.assertEquals(9096, serv.getLoadedStartTime());
-        Assert.assertEquals(10017, serv.getLoadedStarts());
-        Assert.assertEquals(11118, serv.getLoadedLaunches());
-        Assert.assertEquals(12219, serv.getLastStartTime());
-        Assert.assertEquals(13310, serv.getLastStarts());
-        Assert.assertEquals(14411, serv.getLastLaunches());
-        Assert.assertEquals(15512, serv.getUnpluggedStartTime());
-        Assert.assertEquals(16613, serv.getUnpluggedStarts());
-        Assert.assertEquals(17714, serv.getUnpluggedLaunches());
     }
 
 
@@ -712,8 +519,6 @@
         serv.populate();
 
         Assert.assertEquals(4042, serv.getStarts(BatteryStats.STATS_SINCE_CHARGED));
-        Assert.assertEquals(4042-10017, serv.getStarts(BatteryStats.STATS_CURRENT));
-        Assert.assertEquals(4042-16613, serv.getStarts(BatteryStats.STATS_SINCE_UNPLUGGED));
 
         // No change to fields
         Assert.assertEquals(1010, serv.getStartTime());
@@ -724,15 +529,6 @@
         Assert.assertEquals(6064, serv.getLaunchedSince());
         Assert.assertTrue(serv.getLaunched());
         Assert.assertEquals(8085, serv.getLaunches());
-        Assert.assertEquals(9096, serv.getLoadedStartTime());
-        Assert.assertEquals(10017, serv.getLoadedStarts());
-        Assert.assertEquals(11118, serv.getLoadedLaunches());
-        Assert.assertEquals(12219, serv.getLastStartTime());
-        Assert.assertEquals(13310, serv.getLastStarts());
-        Assert.assertEquals(14411, serv.getLastLaunches());
-        Assert.assertEquals(15512, serv.getUnpluggedStartTime());
-        Assert.assertEquals(16613, serv.getUnpluggedStarts());
-        Assert.assertEquals(17714, serv.getUnpluggedLaunches());
     }
     
 }
diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryStatsTimeBaseTest.java b/core/tests/coretests/src/com/android/internal/os/BatteryStatsTimeBaseTest.java
index bce8b40..e5441c0 100644
--- a/core/tests/coretests/src/com/android/internal/os/BatteryStatsTimeBaseTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryStatsTimeBaseTest.java
@@ -282,12 +282,6 @@
 
         Assert.assertEquals(100+300+666-400,
                 tb.computeUptime(666, BatteryStats.STATS_SINCE_CHARGED));
-        Assert.assertEquals(300+666-400,
-                tb.computeUptime(666, BatteryStats.STATS_CURRENT));
-        Assert.assertEquals(300+666-400-50,
-                tb.computeUptime(666, BatteryStats.STATS_SINCE_UNPLUGGED));
-
-        Assert.assertEquals(0, tb.computeUptime(666, 6000));
     }
 
     /**
@@ -301,12 +295,6 @@
 
         Assert.assertEquals(200+500+6666-600,
                 tb.computeRealtime(6666, BatteryStats.STATS_SINCE_CHARGED));
-        Assert.assertEquals(500+6666-600,
-                tb.computeRealtime(6666, BatteryStats.STATS_CURRENT));
-        Assert.assertEquals(500+6666-600-60,
-                tb.computeRealtime(6666, BatteryStats.STATS_SINCE_UNPLUGGED));
-
-        Assert.assertEquals(0, tb.computeUptime(666, 6000));
     }
 
     /**
diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryStatsTimerTest.java b/core/tests/coretests/src/com/android/internal/os/BatteryStatsTimerTest.java
index 87dc2f3..40e3a5f 100644
--- a/core/tests/coretests/src/com/android/internal/os/BatteryStatsTimerTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryStatsTimerTest.java
@@ -66,30 +66,6 @@
             mCount = val;
         }
 
-        public int getLoadedCount() {
-            return mLoadedCount;
-        }
-
-        public void setLoadedCount(int val) {
-            mLoadedCount = val;
-        }
-
-        public int getLastCount() {
-            return mLastCount;
-        }
-
-        public void setLastCount(int val) {
-            mLastCount = val;
-        }
-
-        public int getUnpluggedCount() {
-            return mUnpluggedCount;
-        }
-
-        public void setUnpluggedCount(int val) {
-            mUnpluggedCount = val;
-        }
-
         public long getTotalTime() {
             return mTotalTime;
         }
@@ -98,30 +74,6 @@
             mTotalTime = val;
         }
 
-        public long getLoadedTime() {
-            return mLoadedTime;
-        }
-
-        public void setLoadedTime(long val) {
-            mLoadedTime = val;
-        }
-
-        public long getLastTime() {
-            return mLastTime;
-        }
-
-        public void setLastTime(long val) {
-            mLastTime = val;
-        }
-
-        public long getUnpluggedTime() {
-            return mUnpluggedTime;
-        }
-
-        public void setUnpluggedTime(long val) {
-            mUnpluggedTime = val;
-        }
-
         public long getTimeBeforeMark() {
             return mTimeBeforeMark;
         }
@@ -143,16 +95,12 @@
         TestTimer timer = new TestTimer(clocks, 0, timeBase);
         timer.nextComputeCurrentCount = 3000;
 
-        // Test that starting the timer counts the unplugged time and counters
+        // Test that stopping the timer updates mTotalTime and mCount
         timer.nextComputeRunTime = 4;
         timer.onTimeStarted(10, 20, 50);
-        Assert.assertEquals(50, timer.lastComputeRunTimeRealtime);
-        Assert.assertEquals(4, timer.getUnpluggedTime());
-        Assert.assertEquals(3000, timer.getUnpluggedCount());
-
-        // Test that stopping the timer updates mTotalTime and mCount
         timer.nextComputeRunTime = 17;
         timer.onTimeStopped(100, 130, 170);
+        Assert.assertEquals(170, timer.lastComputeRunTimeRealtime);
         Assert.assertEquals(17, timer.getTotalTime());
         Assert.assertEquals(3000, timer.getCount());
     }
@@ -168,13 +116,7 @@
         // Test write then read
         TestTimer timer1 = new TestTimer(clocks, 0, timeBase);
         timer1.setCount(1);
-        timer1.setLoadedCount(3);
-        timer1.setLastCount(4);
-        timer1.setUnpluggedCount(5);
         timer1.setTotalTime(9223372036854775807L);
-        timer1.setLoadedTime(9223372036854775806L);
-        timer1.setLastTime(9223372036854775805L);
-        timer1.setUnpluggedTime(9223372036854775804L);
         timer1.setTimeBeforeMark(9223372036854775803L);
         timer1.nextComputeRunTime = 201;
         timer1.nextComputeCurrentCount = 2;
@@ -187,13 +129,7 @@
 
         TestTimer timer2 = new TestTimer(clocks, 0, timeBase, parcel);
         Assert.assertEquals(2, timer2.getCount()); // from computeTotalCountLocked()
-        Assert.assertEquals(3, timer2.getLoadedCount());
-        Assert.assertEquals(0, timer2.getLastCount()); // NOT saved
-        Assert.assertEquals(5, timer2.getUnpluggedCount());
         Assert.assertEquals(201, timer2.getTotalTime()); // from computeRunTimeLocked()
-        Assert.assertEquals(9223372036854775806L, timer2.getLoadedTime());
-        Assert.assertEquals(0, timer2.getLastTime()); // NOT saved
-        Assert.assertEquals(9223372036854775804L, timer2.getUnpluggedTime());
         Assert.assertEquals(9223372036854775803L, timer2.getTimeBeforeMark());
 
         parcel.recycle();
@@ -224,25 +160,13 @@
 
         TestTimer timer = new TestTimer(clocks, 0, timeBase);
         timer.setCount(1);
-        timer.setLoadedCount(2);
-        timer.setLastCount(3);
-        timer.setUnpluggedCount(4);
         timer.setTotalTime(9223372036854775807L);
-        timer.setLoadedTime(9223372036854775806L);
-        timer.setLastTime(9223372036854775805L);
-        timer.setUnpluggedTime(9223372036854775804L);
         timer.setTimeBeforeMark(9223372036854775803L);
 
         timer.reset(false);
 
         Assert.assertEquals(0, timer.getCount());
-        Assert.assertEquals(0, timer.getLoadedCount());
-        Assert.assertEquals(0, timer.getLastCount());
-        Assert.assertEquals(4, timer.getUnpluggedCount());
         Assert.assertEquals(0, timer.getTotalTime());
-        Assert.assertEquals(0, timer.getLoadedTime());
-        Assert.assertEquals(0, timer.getLastTime());
-        Assert.assertEquals(9223372036854775804L, timer.getUnpluggedTime());
         Assert.assertEquals(0, timer.getTimeBeforeMark());
 
         // reset(false) shouldn't remove it from the list
@@ -259,25 +183,13 @@
 
         TestTimer timer = new TestTimer(clocks, 0, timeBase);
         timer.setCount(1);
-        timer.setLoadedCount(2);
-        timer.setLastCount(3);
-        timer.setUnpluggedCount(4);
         timer.setTotalTime(9223372036854775807L);
-        timer.setLoadedTime(9223372036854775806L);
-        timer.setLastTime(9223372036854775805L);
-        timer.setUnpluggedTime(9223372036854775804L);
         timer.setTimeBeforeMark(9223372036854775803L);
 
         timer.reset(true);
 
         Assert.assertEquals(0, timer.getCount());
-        Assert.assertEquals(0, timer.getLoadedCount());
-        Assert.assertEquals(0, timer.getLastCount());
-        Assert.assertEquals(4, timer.getUnpluggedCount());
         Assert.assertEquals(0, timer.getTotalTime());
-        Assert.assertEquals(0, timer.getLoadedTime());
-        Assert.assertEquals(0, timer.getLastTime());
-        Assert.assertEquals(9223372036854775804L, timer.getUnpluggedTime());
         Assert.assertEquals(0, timer.getTimeBeforeMark());
 
         // reset(true) should remove it from the list
@@ -299,13 +211,7 @@
 
         TestTimer timer1 = new TestTimer(clocks, 0, timeBase);
         timer1.setCount(1);
-        timer1.setLoadedCount(2);
-        timer1.setLastCount(3);
-        timer1.setUnpluggedCount(4);
         timer1.setTotalTime(9223372036854775807L);
-        timer1.setLoadedTime(9223372036854775806L);
-        timer1.setLastTime(9223372036854775805L);
-        timer1.setUnpluggedTime(9223372036854775804L);
         timer1.setTimeBeforeMark(9223372036854775803L);
 
         Parcel parcel = Parcel.obtain();
@@ -318,13 +224,7 @@
 
         // Make sure that all the values get touched
         timer2.setCount(666);
-        timer2.setLoadedCount(666);
-        timer2.setLastCount(666);
-        timer2.setUnpluggedCount(666);
         timer2.setTotalTime(666);
-        timer2.setLoadedTime(666);
-        timer2.setLastTime(666);
-        timer2.setUnpluggedTime(666);
         timer2.setTimeBeforeMark(666);
 
         parcel.setDataPosition(0);
@@ -333,13 +233,7 @@
         timer2.readSummaryFromParcelLocked(parcel);
 
         Assert.assertEquals(1, timer2.getCount());
-        Assert.assertEquals(1, timer2.getLoadedCount());
-        Assert.assertEquals(0, timer2.getLastCount());
-        Assert.assertEquals(1, timer2.getUnpluggedCount());
         Assert.assertEquals(9223372036854775800L, timer2.getTotalTime());
-        Assert.assertEquals(9223372036854775800L, timer2.getLoadedTime());
-        Assert.assertEquals(0, timer2.getLastTime());
-        Assert.assertEquals(9223372036854775800L, timer2.getUnpluggedTime());
         Assert.assertEquals(9223372036854775800L, timer2.getTimeBeforeMark());
 
         parcel.recycle();
@@ -359,32 +253,15 @@
 
         TestTimer timer = new TestTimer(clocks, 0, timeBase);
         timer.setCount(1);
-        timer.setLoadedCount(2);
-        timer.setLastCount(3);
-        timer.setUnpluggedCount(4);
         timer.setTotalTime(100);
-        timer.setLoadedTime(200);
-        timer.setLastTime(300);
-        timer.setUnpluggedTime(400);
         timer.setTimeBeforeMark(500);
 
         timer.nextComputeRunTime = 10000;
 
-        // Timer.getTotalTimeLocked(STATS_SINCE_CHARGED)
         timer.lastComputeRunTimeRealtime = -1;
         Assert.assertEquals(10000,
                 timer.getTotalTimeLocked(66, BatteryStats.STATS_SINCE_CHARGED));
         Assert.assertEquals(40, timer.lastComputeRunTimeRealtime);
-
-        // Timer.getTotalTimeLocked(STATS_CURRENT)
-        timer.lastComputeRunTimeRealtime = -1;
-        Assert.assertEquals(9800, timer.getTotalTimeLocked(66, BatteryStats.STATS_CURRENT));
-        Assert.assertEquals(40, timer.lastComputeRunTimeRealtime);
-
-        // Timer.getTotalTimeLocked(STATS_SINCE_UNPLUGGED)
-        timer.lastComputeRunTimeRealtime = -1;
-        Assert.assertEquals(9600, timer.getTotalTimeLocked(66, BatteryStats.STATS_SINCE_UNPLUGGED));
-        Assert.assertEquals(40, timer.lastComputeRunTimeRealtime);
     }
 
     /**
@@ -401,26 +278,11 @@
 
         TestTimer timer = new TestTimer(clocks, 0, timeBase);
         timer.setCount(1);
-        timer.setLoadedCount(2);
-        timer.setLastCount(3);
-        timer.setUnpluggedCount(4);
         timer.setTotalTime(100);
-        timer.setLoadedTime(200);
-        timer.setLastTime(300);
-        timer.setUnpluggedTime(400);
         timer.setTimeBeforeMark(500);
 
-        // Timer.getCountLocked(STATS_SINCE_CHARGED)
         timer.nextComputeCurrentCount = 10000;
         Assert.assertEquals(10000, timer.getCountLocked(BatteryStats.STATS_SINCE_CHARGED));
-
-        // Timer.getCountLocked(STATS_CURRENT)
-        timer.nextComputeCurrentCount = 10000;
-        Assert.assertEquals(9998, timer.getCountLocked(BatteryStats.STATS_CURRENT));
-
-        // Timer.getCountLocked(STATS_SINCE_UNPLUGGED)
-        timer.nextComputeCurrentCount = 10000;
-        Assert.assertEquals(9996, timer.getCountLocked(BatteryStats.STATS_SINCE_UNPLUGGED));
     }
 
     /**
@@ -437,13 +299,7 @@
 
         TestTimer timer = new TestTimer(clocks, 0, timeBase);
         timer.setCount(1);
-        timer.setLoadedCount(2);
-        timer.setLastCount(3);
-        timer.setUnpluggedCount(4);
         timer.setTotalTime(100);
-        timer.setLoadedTime(200);
-        timer.setLastTime(300);
-        timer.setUnpluggedTime(400);
         timer.setTimeBeforeMark(500);
 
         timer.nextComputeRunTime = 10000;
@@ -460,30 +316,16 @@
 
         TestTimer timer = new TestTimer(clocks, 0, timeBase);
         timer.setTotalTime(100);
-        timer.setLoadedTime(200);
-        timer.setLastTime(300);
-        timer.setUnpluggedTime(400);
         timer.setTimeBeforeMark(500);
         timer.setCount(1);
-        timer.setLoadedCount(2);
-        timer.setLastCount(3);
-        timer.setUnpluggedCount(4);
         timer.setTotalTime(9223372036854775807L);
-        timer.setLoadedTime(9223372036854775806L);
-        timer.setLastTime(9223372036854775805L);
-        timer.setUnpluggedTime(9223372036854775804L);
         timer.setTimeBeforeMark(9223372036854775803L);
 
         StringBuilder sb = new StringBuilder();
         StringBuilderPrinter pw = new StringBuilderPrinter(sb);
 
         timer.logState(pw, "  ");
-
-        Assert.assertEquals(
-                      "  mCount=1 mLoadedCount=2 mLastCount=3 mUnpluggedCount=4\n"
-                    + "  mTotalTime=9223372036854775807 mLoadedTime=9223372036854775806\n"
-                    + "  mLastTime=9223372036854775805 mUnpluggedTime=9223372036854775804\n",
-                sb.toString());
+        Assert.assertEquals("  mCount=1\n  mTotalTime=9223372036854775807\n", sb.toString());
     }
 }
 
diff --git a/core/tests/coretests/src/com/android/internal/os/LongSamplingCounterArrayTest.java b/core/tests/coretests/src/com/android/internal/os/LongSamplingCounterArrayTest.java
index 0516bb7..ee5d2d6 100644
--- a/core/tests/coretests/src/com/android/internal/os/LongSamplingCounterArrayTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/LongSamplingCounterArrayTest.java
@@ -16,14 +16,12 @@
 
 package com.android.internal.os;
 
-import static android.os.BatteryStats.STATS_CURRENT;
 import static android.os.BatteryStats.STATS_SINCE_CHARGED;
-import static android.os.BatteryStats.STATS_SINCE_UNPLUGGED;
 
 import static com.android.internal.os.BatteryStatsImpl.LongSamplingCounterArray;
 import static com.android.internal.os.BatteryStatsImpl.TimeBase;
 
-import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.assertArrayEquals;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.verifyNoMoreInteractions;
 import static org.mockito.Mockito.verifyZeroInteractions;
@@ -41,8 +39,6 @@
 import org.mockito.Mockito;
 import org.mockito.MockitoAnnotations;
 
-import java.util.Arrays;
-
 /**
  * Test class for {@link BatteryStatsImpl.LongSamplingCounterArray}.
  *
@@ -57,14 +53,15 @@
  *     ${ANDROID_PRODUCT_OUT}/data/app/FrameworksCoreTests/FrameworksCoreTests.apk
  * Run: adb shell am instrument -e class com.android.internal.os.LongSamplingCounterArrayTest -w \
  *     com.android.frameworks.coretests/androidx.test.runner.AndroidJUnitRunner
+ *
+ * or just do
+ * atest frameworks/base/core/tests/coretests/src/com/android/internal/os/LongSamplingCounterArrayTest.java
  */
 @SmallTest
 @RunWith(AndroidJUnit4.class)
 public class LongSamplingCounterArrayTest {
 
     private static final long[] COUNTS = {1111, 2222, 3333, 4444};
-    private static final long[] LOADED_COUNTS = {5555, 6666, 7777, 8888};
-    private static final long[] UNPLUGGED_COUNTS = {44444, 55555, 66666, 77777};
     private static final long[] ZEROES = {0, 0, 0, 0};
 
     @Mock private TimeBase mTimeBase;
@@ -80,75 +77,54 @@
     @Test
     public void testReadWriteParcel() {
         final Parcel parcel = Parcel.obtain();
-        initializeCounterArrayWithDefaultValues();
+        updateCounts(COUNTS);
         LongSamplingCounterArray.writeToParcel(parcel, mCounterArray);
         parcel.setDataPosition(0);
 
         // Now clear counterArray and verify values are read from parcel correctly.
-        updateCounts(null, null, null);
+        updateCounts(null);
         mCounterArray = LongSamplingCounterArray.readFromParcel(parcel, mTimeBase);
-        assertArrayEquals(COUNTS, mCounterArray.mCounts, "Unexpected counts");
-        assertArrayEquals(LOADED_COUNTS, mCounterArray.mLoadedCounts, "Unexpected loadedCounts");
-        assertArrayEquals(UNPLUGGED_COUNTS, mCounterArray.mUnpluggedCounts,
-                "Unexpected unpluggedCounts");
+        assertArrayEquals(COUNTS, mCounterArray.mCounts);
         parcel.recycle();
     }
 
     @Test
     public void testReadWriteSummaryParcel() {
         final Parcel parcel = Parcel.obtain();
-        initializeCounterArrayWithDefaultValues();
+        updateCounts(COUNTS);
         LongSamplingCounterArray.writeSummaryToParcelLocked(parcel, mCounterArray);
         parcel.setDataPosition(0);
 
         // Now clear counterArray and verify values are read from parcel correctly.
-        updateCounts(null, null, null);
+        updateCounts(null);
         mCounterArray = LongSamplingCounterArray.readSummaryFromParcelLocked(parcel, mTimeBase);
-        assertArrayEquals(COUNTS, mCounterArray.mCounts, "Unexpected counts");
-        assertArrayEquals(COUNTS, mCounterArray.mLoadedCounts, "Unexpected loadedCounts");
-        assertArrayEquals(COUNTS, mCounterArray.mUnpluggedCounts, "Unexpected unpluggedCounts");
+        assertArrayEquals(COUNTS, mCounterArray.mCounts);
         parcel.recycle();
     }
 
     @Test
     public void testOnTimeStarted() {
-        initializeCounterArrayWithDefaultValues();
+        updateCounts(COUNTS);
         mCounterArray.onTimeStarted(0, 0, 0);
-        assertArrayEquals(COUNTS, mCounterArray.mCounts, "Unexpected counts");
-        assertArrayEquals(LOADED_COUNTS, mCounterArray.mLoadedCounts, "Unexpected loadedCounts");
-        assertArrayEquals(COUNTS, mCounterArray.mUnpluggedCounts,
-                "Unexpected unpluggedCounts");
+        assertArrayEquals(COUNTS, mCounterArray.mCounts);
     }
 
     @Test
     public void testOnTimeStopped() {
-        initializeCounterArrayWithDefaultValues();
+        updateCounts(COUNTS);
         mCounterArray.onTimeStopped(0, 0, 0);
-        assertArrayEquals(COUNTS, mCounterArray.mCounts, "Unexpected counts");
-        assertArrayEquals(LOADED_COUNTS, mCounterArray.mLoadedCounts, "Unexpected loadedCounts");
-        assertArrayEquals(UNPLUGGED_COUNTS, mCounterArray.mUnpluggedCounts,
-                "Unexpected unpluggedCounts");
+        assertArrayEquals(COUNTS, mCounterArray.mCounts);
     }
 
     @Test
     public void testGetCountsLocked() {
-        initializeCounterArrayWithDefaultValues();
+        updateCounts(COUNTS);
 
         when(mTimeBase.isRunning()).thenReturn(false);
-        assertArrayEquals(COUNTS, mCounterArray.getCountsLocked(STATS_SINCE_CHARGED),
-                "Unexpected values");
-        assertArrayEquals(subtract(COUNTS, LOADED_COUNTS),
-                mCounterArray.getCountsLocked(STATS_CURRENT), "Unexpected values");
-        assertArrayEquals(subtract(COUNTS, UNPLUGGED_COUNTS),
-                mCounterArray.getCountsLocked(STATS_SINCE_UNPLUGGED), "Unexpected values");
+        assertArrayEquals(COUNTS, mCounterArray.getCountsLocked(STATS_SINCE_CHARGED));
 
         when(mTimeBase.isRunning()).thenReturn(true);
-        assertArrayEquals(COUNTS, mCounterArray.getCountsLocked(STATS_SINCE_CHARGED),
-                "Unexpected values");
-        assertArrayEquals(subtract(COUNTS, LOADED_COUNTS),
-                mCounterArray.getCountsLocked(STATS_CURRENT), "Unexpected values");
-        assertArrayEquals(subtract(COUNTS, UNPLUGGED_COUNTS),
-                mCounterArray.getCountsLocked(STATS_SINCE_UNPLUGGED), "Unexpected values");
+        assertArrayEquals(COUNTS, mCounterArray.getCountsLocked(STATS_SINCE_CHARGED));
     }
 
     private long[] subtract(long[] val, long[] toSubtract) {
@@ -163,64 +139,45 @@
 
     @Test
     public void testAddCountLocked() {
-        updateCounts(null, null, null);
+        updateCounts(null);
         final long[] deltas = {123, 234, 345, 456};
         when(mTimeBase.isRunning()).thenReturn(true);
         mCounterArray.addCountLocked(deltas);
-        assertArrayEquals(deltas, mCounterArray.mCounts, "Unexpected counts");
-        assertArrayEquals(null, mCounterArray.mLoadedCounts, "Unexpected loadedCounts");
-        assertArrayEquals(null, mCounterArray.mUnpluggedCounts, "Unexpected unpluggedCounts");
+        assertArrayEquals(deltas, mCounterArray.mCounts);
 
-        updateCounts(null, null, null);
+        updateCounts(null);
         mCounterArray.addCountLocked(deltas, false);
-        assertArrayEquals(null, mCounterArray.mCounts, "Unexpected counts");
-        assertArrayEquals(null, mCounterArray.mLoadedCounts, "Unexpected loadedCounts");
-        assertArrayEquals(null, mCounterArray.mUnpluggedCounts, "Unexpected unpluggedCounts");
+        assertArrayEquals(null, mCounterArray.mCounts);
         mCounterArray.addCountLocked(deltas, true);
-        assertArrayEquals(deltas, mCounterArray.mCounts, "Unexpected counts");
-        assertArrayEquals(null, mCounterArray.mLoadedCounts, "Unexpected loadedCounts");
-        assertArrayEquals(null, mCounterArray.mUnpluggedCounts, "Unexpected unpluggedCounts");
+        assertArrayEquals(deltas, mCounterArray.mCounts);
 
-        initializeCounterArrayWithDefaultValues();
+        updateCounts(COUNTS);
         final long[] newCounts = new long[deltas.length];
         for (int i = 0; i < deltas.length; ++i) {
             newCounts[i] = COUNTS[i] + deltas[i];
         }
         mCounterArray.addCountLocked(deltas);
-        assertArrayEquals(newCounts, mCounterArray.mCounts, "Unexpected counts");
-        assertArrayEquals(LOADED_COUNTS, mCounterArray.mLoadedCounts, "Unexpected loadedCounts");
-        assertArrayEquals(UNPLUGGED_COUNTS, mCounterArray.mUnpluggedCounts,
-                "Unexpected unpluggedCounts");
+        assertArrayEquals(newCounts, mCounterArray.mCounts);
 
-        initializeCounterArrayWithDefaultValues();
+        updateCounts(COUNTS);
         mCounterArray.addCountLocked(deltas, false);
-        assertArrayEquals(COUNTS, mCounterArray.mCounts, "Unexpected counts");
-        assertArrayEquals(LOADED_COUNTS, mCounterArray.mLoadedCounts, "Unexpected loadedCounts");
-        assertArrayEquals(UNPLUGGED_COUNTS, mCounterArray.mUnpluggedCounts,
-                "Unexpected unpluggedCounts");
+        assertArrayEquals(COUNTS, mCounterArray.mCounts);
         mCounterArray.addCountLocked(deltas, true);
-        assertArrayEquals(newCounts, mCounterArray.mCounts, "Unexpected counts");
-        assertArrayEquals(LOADED_COUNTS, mCounterArray.mLoadedCounts, "Unexpected loadedCounts");
-        assertArrayEquals(UNPLUGGED_COUNTS, mCounterArray.mUnpluggedCounts,
-                "Unexpected unpluggedCounts");
+        assertArrayEquals(newCounts, mCounterArray.mCounts);
     }
 
     @Test
     public void testReset() {
-        initializeCounterArrayWithDefaultValues();
+        updateCounts(COUNTS);
         // Test with detachIfReset=false
         mCounterArray.reset(false /* detachIfReset */);
-        assertArrayEquals(ZEROES, mCounterArray.mCounts, "Unexpected counts");
-        assertArrayEquals(ZEROES, mCounterArray.mLoadedCounts, "Unexpected loadedCounts");
-        assertArrayEquals(ZEROES, mCounterArray.mUnpluggedCounts, "Unexpected unpluggedCounts");
+        assertArrayEquals(ZEROES, mCounterArray.mCounts);
         verifyZeroInteractions(mTimeBase);
 
-        initializeCounterArrayWithDefaultValues();
+        updateCounts(COUNTS);
         // Test with detachIfReset=true
         mCounterArray.reset(true /* detachIfReset */);
-        assertArrayEquals(ZEROES, mCounterArray.mCounts, "Unexpected counts");
-        assertArrayEquals(ZEROES, mCounterArray.mLoadedCounts, "Unexpected loadedCounts");
-        assertArrayEquals(ZEROES, mCounterArray.mUnpluggedCounts, "Unexpected unpluggedCounts");
+        assertArrayEquals(ZEROES, mCounterArray.mCounts);
         verify(mTimeBase).remove(mCounterArray);
         verifyNoMoreInteractions(mTimeBase);
     }
@@ -232,18 +189,7 @@
         verifyNoMoreInteractions(mTimeBase);
     }
 
-    private void initializeCounterArrayWithDefaultValues() {
-        updateCounts(COUNTS, LOADED_COUNTS, UNPLUGGED_COUNTS);
-    }
-
-    private void assertArrayEquals(long[] expected, long[] actual, String msg) {
-        assertTrue(msg + ", expected: " + Arrays.toString(expected)
-                + ", actual: " + Arrays.toString(actual), Arrays.equals(expected, actual));
-    }
-
-    private void updateCounts(long[] counts, long[] loadedCounts, long[] unpluggedCounts) {
+    private void updateCounts(long[] counts) {
         mCounterArray.mCounts = counts == null ? null : counts.clone();
-        mCounterArray.mLoadedCounts = loadedCounts == null ? null : loadedCounts.clone();
-        mCounterArray.mUnpluggedCounts = unpluggedCounts == null ? null : unpluggedCounts.clone();
     }
 }
diff --git a/core/tests/coretests/src/com/android/internal/os/LongSamplingCounterTest.java b/core/tests/coretests/src/com/android/internal/os/LongSamplingCounterTest.java
index d2f5735..dccc3d3 100644
--- a/core/tests/coretests/src/com/android/internal/os/LongSamplingCounterTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/LongSamplingCounterTest.java
@@ -51,7 +51,6 @@
 public class LongSamplingCounterTest {
 
     private static final long COUNT = 1111;
-    private static final long CURRENT_COUNT = 5555;
 
     @Mock
     private TimeBase mTimeBase;
@@ -67,116 +66,87 @@
     @Test
     public void testReadWriteParcel() {
         final Parcel parcel = Parcel.obtain();
-        updateCounts(COUNT, CURRENT_COUNT);
+        mCounter.addCountLocked(COUNT, true);
+        assertEquals(COUNT, getCount());
         mCounter.writeToParcel(parcel);
         parcel.setDataPosition(0);
 
-        // Now clear counterArray and verify values are read from parcel correctly.
-        updateCounts(0, 0);
+        // Now change count but verify values are read from parcel correctly.
+        mCounter.addCountLocked(7 * COUNT, true);
+        assertEquals(8 * COUNT, getCount());
 
         mCounter = new LongSamplingCounter(mTimeBase, parcel);
-        assertEquals(COUNT, mCounter.mCount);
-        assertEquals(CURRENT_COUNT, mCounter.mCurrentCount);
+        assertEquals(COUNT, getCount());
         parcel.recycle();
     }
 
     @Test
     public void testReadWriteSummaryParcel() {
         final Parcel parcel = Parcel.obtain();
-        updateCounts(COUNT, CURRENT_COUNT);
+        mCounter.addCountLocked(COUNT, true);
+        assertEquals(COUNT, getCount());
         mCounter.writeSummaryFromParcelLocked(parcel);
         parcel.setDataPosition(0);
 
-        // Now clear counterArray and verify values are read from parcel correctly.
-        updateCounts(0, 0);
+        // Now change count but verify values are read from parcel correctly.
+        mCounter.addCountLocked(7 * COUNT, true);
+        assertEquals(8 * COUNT, getCount());
 
         mCounter.readSummaryFromParcelLocked(parcel);
-        assertEquals(COUNT, mCounter.mCount);
+        assertEquals(COUNT, getCount());
         parcel.recycle();
     }
 
     @Test
     public void testOnTimeStarted() {
-        updateCounts(COUNT, CURRENT_COUNT);
+        mCounter.addCountLocked(COUNT, true);
+        assertEquals(COUNT, getCount());
         mCounter.onTimeStarted(0, 0, 0);
-        assertEquals(COUNT, mCounter.mCount);
-        assertEquals(COUNT, mCounter.mUnpluggedCount);
+        assertEquals(COUNT, getCount());
     }
 
     @Test
     public void testOnTimeStopped() {
-        updateCounts(COUNT, CURRENT_COUNT);
+        mCounter.addCountLocked(COUNT, true);
+        assertEquals(COUNT, getCount());
         mCounter.onTimeStopped(0, 0, 0);
-        assertEquals(COUNT, mCounter.mCount);
+        assertEquals(COUNT, getCount());
     }
 
     @Test
     public void testAddCountLocked() {
-        updateCounts(0, 0);
-        assertEquals(0, mCounter.getCountLocked(0));
+        assertEquals(0, getCount());
         when(mTimeBase.isRunning()).thenReturn(true);
         mCounter.addCountLocked(111);
         assertEquals(111, mCounter.getCountLocked(STATS_SINCE_CHARGED));
-        assertEquals(111, mCounter.mCurrentCount);
         mCounter.addCountLocked(222);
         assertEquals(333, mCounter.getCountLocked(STATS_SINCE_CHARGED));
-        assertEquals(333, mCounter.mCurrentCount);
 
         when(mTimeBase.isRunning()).thenReturn(false);
         mCounter.addCountLocked(456);
         assertEquals(333, mCounter.getCountLocked(STATS_SINCE_CHARGED));
-        assertEquals(789, mCounter.mCurrentCount);
 
         mCounter.addCountLocked(444, true);
         assertEquals(777, mCounter.getCountLocked(STATS_SINCE_CHARGED));
-        assertEquals(1233, mCounter.mCurrentCount);
         mCounter.addCountLocked(567, false);
         assertEquals(777, mCounter.getCountLocked(STATS_SINCE_CHARGED));
-        assertEquals(1800, mCounter.mCurrentCount);
     }
 
-    @Test
-    public void testUpdate() {
-        updateCounts(0, 0);
-        assertEquals(0, mCounter.getCountLocked(0));
-        when(mTimeBase.isRunning()).thenReturn(true);
-        mCounter.update(111);
-        assertEquals(111, mCounter.getCountLocked(STATS_SINCE_CHARGED));
-        assertEquals(111, mCounter.mCurrentCount);
-        mCounter.update(333);
-        assertEquals(333, mCounter.getCountLocked(STATS_SINCE_CHARGED));
-        assertEquals(333, mCounter.mCurrentCount);
-
-        when(mTimeBase.isRunning()).thenReturn(false);
-        mCounter.update(789);
-        assertEquals(333, mCounter.getCountLocked(STATS_SINCE_CHARGED));
-        assertEquals(789, mCounter.mCurrentCount);
-        mCounter.update(100);
-        assertEquals(333, mCounter.getCountLocked(STATS_SINCE_CHARGED));
-        assertEquals(100, mCounter.mCurrentCount);
-
-        mCounter.update(544, true);
-        assertEquals(777, mCounter.getCountLocked(STATS_SINCE_CHARGED));
-        assertEquals(544, mCounter.mCurrentCount);
-        mCounter.update(1544, false);
-        assertEquals(777, mCounter.getCountLocked(STATS_SINCE_CHARGED));
-        assertEquals(1544, mCounter.mCurrentCount);
-    }
 
     @Test
     public void testReset() {
-        updateCounts(COUNT, CURRENT_COUNT);
+        mCounter.addCountLocked(COUNT, true);
+        assertEquals(COUNT, getCount());
         // Test with detachIfReset=false
         mCounter.reset(false /* detachIfReset */);
-        assertEquals(0, mCounter.mCount);
-        assertEquals(CURRENT_COUNT, mCounter.mCurrentCount);
+        assertEquals(0, getCount());
         verifyZeroInteractions(mTimeBase);
 
-        updateCounts(COUNT, CURRENT_COUNT);
+        mCounter.addCountLocked(COUNT, true);
+        assertEquals(COUNT, getCount());
         // Test with detachIfReset=true
         mCounter.reset(true /* detachIfReset */);
-        assertEquals(0, mCounter.mCount);
-        assertEquals(CURRENT_COUNT, mCounter.mCurrentCount);
+        assertEquals(0, getCount());
         verify(mTimeBase).remove(mCounter);
         verifyNoMoreInteractions(mTimeBase);
     }
@@ -188,8 +158,7 @@
         verifyNoMoreInteractions(mTimeBase);
     }
 
-    private void updateCounts(long total, long current) {
-        mCounter.mCount = total;
-        mCounter.mCurrentCount = current;
+    private long getCount() {
+        return mCounter.getCountLocked(STATS_SINCE_CHARGED);
     }
 }
diff --git a/core/tests/overlaytests/device/assets/package-name.txt b/core/tests/overlaytests/device/assets/package-name.txt
new file mode 100644
index 0000000..8094438
--- /dev/null
+++ b/core/tests/overlaytests/device/assets/package-name.txt
@@ -0,0 +1 @@
+com.android.overlaytest
diff --git a/core/tests/overlaytests/device/src/com/android/overlaytest/OverlayBaseTest.java b/core/tests/overlaytests/device/src/com/android/overlaytest/OverlayBaseTest.java
index 91fcdbb..f86743a 100644
--- a/core/tests/overlaytests/device/src/com/android/overlaytest/OverlayBaseTest.java
+++ b/core/tests/overlaytests/device/src/com/android/overlaytest/OverlayBaseTest.java
@@ -17,9 +17,12 @@
 package com.android.overlaytest;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 
 import android.app.UiAutomation;
+import android.content.res.AssetManager;
 import android.content.res.Configuration;
 import android.content.res.Resources;
 import android.content.res.XmlResourceParser;
@@ -30,6 +33,8 @@
 
 import androidx.test.InstrumentationRegistry;
 
+import com.android.internal.util.ArrayUtils;
+
 import org.junit.Before;
 import org.junit.Ignore;
 import org.junit.Test;
@@ -291,6 +296,33 @@
         assertEquals(getExpected(no, so, mo), actual);
     }
 
+    @Test
+    public void testAssetsNotPossibleToOverlay() throws Throwable {
+        final AssetManager am = mResources.getAssets();
+
+        // AssetManager#list will include assets from all loaded non-overlay
+        // APKs, including the framework; framework-res.apk contains at least
+        // assets/{images,webkit}. Rather than checking the list, verify that
+        // assets only present in overlays are never part of the list.
+        String[] files = am.list("");
+        assertTrue(ArrayUtils.contains(files, "package-name.txt"));
+        assertFalse(ArrayUtils.contains(files, "foo.txt"));
+        assertFalse(ArrayUtils.contains(files, "bar.txt"));
+
+        String contents = null;
+        try (InputStream is = am.open("package-name.txt")) {
+            final BufferedReader reader = new BufferedReader(
+                    new InputStreamReader(is, StandardCharsets.UTF_8));
+            StringBuilder str = new StringBuilder();
+            String line;
+            while ((line = reader.readLine()) != null) {
+                str.append(line);
+            }
+            contents = str.toString();
+        }
+        assertEquals("com.android.overlaytest", contents);
+    }
+
     /*
      * testMatrix* tests
      *
diff --git a/core/tests/overlaytests/device/test-apps/AppOverlayOne/AndroidManifest.xml b/core/tests/overlaytests/device/test-apps/AppOverlayOne/AndroidManifest.xml
index 1719158..8ac6953 100644
--- a/core/tests/overlaytests/device/test-apps/AppOverlayOne/AndroidManifest.xml
+++ b/core/tests/overlaytests/device/test-apps/AppOverlayOne/AndroidManifest.xml
@@ -18,5 +18,6 @@
         package="com.android.overlaytest.app_overlay_one"
         android:versionCode="1"
         android:versionName="1.0">
+        <application android:hasCode="false" />
         <overlay android:targetPackage="com.android.overlaytest" android:priority="1" />
 </manifest>
diff --git a/core/tests/overlaytests/device/test-apps/AppOverlayOne/assets/foo.txt b/core/tests/overlaytests/device/test-apps/AppOverlayOne/assets/foo.txt
new file mode 100644
index 0000000..257cc56
--- /dev/null
+++ b/core/tests/overlaytests/device/test-apps/AppOverlayOne/assets/foo.txt
@@ -0,0 +1 @@
+foo
diff --git a/core/tests/overlaytests/device/test-apps/AppOverlayOne/assets/package-name.txt b/core/tests/overlaytests/device/test-apps/AppOverlayOne/assets/package-name.txt
new file mode 100644
index 0000000..087cb96
--- /dev/null
+++ b/core/tests/overlaytests/device/test-apps/AppOverlayOne/assets/package-name.txt
@@ -0,0 +1 @@
+com.android.overlaytest.app_overlay_one
diff --git a/core/tests/overlaytests/device/test-apps/AppOverlayTwo/AndroidManifest.xml b/core/tests/overlaytests/device/test-apps/AppOverlayTwo/AndroidManifest.xml
index ae8307c..f3c39cc 100644
--- a/core/tests/overlaytests/device/test-apps/AppOverlayTwo/AndroidManifest.xml
+++ b/core/tests/overlaytests/device/test-apps/AppOverlayTwo/AndroidManifest.xml
@@ -18,5 +18,6 @@
         package="com.android.overlaytest.app_overlay_two"
         android:versionCode="1"
         android:versionName="1.0">
+        <application android:hasCode="false" />
         <overlay android:targetPackage="com.android.overlaytest" android:priority="2" />
 </manifest>
diff --git a/core/tests/overlaytests/device/test-apps/AppOverlayTwo/assets/bar.txt b/core/tests/overlaytests/device/test-apps/AppOverlayTwo/assets/bar.txt
new file mode 100644
index 0000000..5716ca5
--- /dev/null
+++ b/core/tests/overlaytests/device/test-apps/AppOverlayTwo/assets/bar.txt
@@ -0,0 +1 @@
+bar
diff --git a/core/tests/overlaytests/device/test-apps/AppOverlayTwo/assets/package-name.txt b/core/tests/overlaytests/device/test-apps/AppOverlayTwo/assets/package-name.txt
new file mode 100644
index 0000000..1318565
--- /dev/null
+++ b/core/tests/overlaytests/device/test-apps/AppOverlayTwo/assets/package-name.txt
@@ -0,0 +1 @@
+com.android.overlaytest.app_overlay_two
diff --git a/core/tests/overlaytests/device/test-apps/FrameworkOverlay/AndroidManifest.xml b/core/tests/overlaytests/device/test-apps/FrameworkOverlay/AndroidManifest.xml
index 77ea16a..73a83e0 100644
--- a/core/tests/overlaytests/device/test-apps/FrameworkOverlay/AndroidManifest.xml
+++ b/core/tests/overlaytests/device/test-apps/FrameworkOverlay/AndroidManifest.xml
@@ -18,5 +18,6 @@
         package="com.android.overlaytest.framework"
         android:versionCode="1"
         android:versionName="1.0">
+        <application android:hasCode="false" />
         <overlay android:targetPackage="android" android:priority="1" />
 </manifest>
diff --git a/core/tests/overlaytests/host/src/com/android/server/om/hosttest/InstallOverlayTests.java b/core/tests/overlaytests/host/src/com/android/server/om/hosttest/InstallOverlayTests.java
index 27986cc..f9672d2 100644
--- a/core/tests/overlaytests/host/src/com/android/server/om/hosttest/InstallOverlayTests.java
+++ b/core/tests/overlaytests/host/src/com/android/server/om/hosttest/InstallOverlayTests.java
@@ -155,12 +155,26 @@
         }
     }
 
+    private void delay() {
+        try {
+            Thread.sleep(100);
+        } catch (InterruptedException e) {
+        }
+    }
+
+    private void installPackage(String pkg) throws Exception {
+        super.installPackage(pkg);
+        delay();
+    }
+
     private void setPackageEnabled(String pkg, boolean enabled) throws Exception {
         getDevice().executeShellCommand("cmd package " + (enabled ? "enable " : "disable ") + pkg);
+        delay();
     }
 
     private void setOverlayEnabled(String pkg, boolean enabled) throws Exception {
         getDevice().executeShellCommand("cmd overlay " + (enabled ? "enable " : "disable ") + pkg);
+        delay();
     }
 
     private boolean overlayManagerContainsPackage(String pkg) throws Exception {
diff --git a/core/tests/overlaytests/host/test-apps/SignatureOverlay/AndroidManifest.xml b/core/tests/overlaytests/host/test-apps/SignatureOverlay/AndroidManifest.xml
index b08ac96..26b3875 100644
--- a/core/tests/overlaytests/host/test-apps/SignatureOverlay/AndroidManifest.xml
+++ b/core/tests/overlaytests/host/test-apps/SignatureOverlay/AndroidManifest.xml
@@ -16,5 +16,6 @@
 
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
     package="com.android.server.om.hosttest.signature_overlay">
+    <application android:hasCode="false" />
     <overlay android:targetPackage="android" />
 </manifest>
diff --git a/core/tests/overlaytests/host/test-apps/SignatureOverlay/static/AndroidManifest.xml b/core/tests/overlaytests/host/test-apps/SignatureOverlay/static/AndroidManifest.xml
index 139dd96..8a66423 100644
--- a/core/tests/overlaytests/host/test-apps/SignatureOverlay/static/AndroidManifest.xml
+++ b/core/tests/overlaytests/host/test-apps/SignatureOverlay/static/AndroidManifest.xml
@@ -16,5 +16,6 @@
 
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
           package="com.android.server.om.hosttest.signature_overlay">
+    <application android:hasCode="false" />
     <overlay android:targetPackage="android" android:isStatic="true" />
 </manifest>
diff --git a/core/tests/overlaytests/host/test-apps/UpdateOverlay/app/v1/AndroidManifest.xml b/core/tests/overlaytests/host/test-apps/UpdateOverlay/app/v1/AndroidManifest.xml
index 73804eb..b6ff0c3 100644
--- a/core/tests/overlaytests/host/test-apps/UpdateOverlay/app/v1/AndroidManifest.xml
+++ b/core/tests/overlaytests/host/test-apps/UpdateOverlay/app/v1/AndroidManifest.xml
@@ -16,5 +16,6 @@
 
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
     package="com.android.server.om.hosttest.app_overlay">
+    <application android:hasCode="false" />
     <overlay android:targetPackage="com.android.server.om.hosttest.update_overlay_test" />
 </manifest>
diff --git a/core/tests/overlaytests/host/test-apps/UpdateOverlay/app/v2/AndroidManifest.xml b/core/tests/overlaytests/host/test-apps/UpdateOverlay/app/v2/AndroidManifest.xml
index 9ec7d06..f1a3981 100644
--- a/core/tests/overlaytests/host/test-apps/UpdateOverlay/app/v2/AndroidManifest.xml
+++ b/core/tests/overlaytests/host/test-apps/UpdateOverlay/app/v2/AndroidManifest.xml
@@ -16,6 +16,7 @@
 
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
     package="com.android.server.om.hosttest.app_overlay">
+    <application android:hasCode="false" />
     <overlay android:targetPackage="com.android.server.om.hosttest.update_overlay_test"
         android:category="android.theme" />
 </manifest>
diff --git a/core/tests/overlaytests/host/test-apps/UpdateOverlay/framework/AndroidManifest.xml b/core/tests/overlaytests/host/test-apps/UpdateOverlay/framework/AndroidManifest.xml
index 8c8fe94..025d1a2 100644
--- a/core/tests/overlaytests/host/test-apps/UpdateOverlay/framework/AndroidManifest.xml
+++ b/core/tests/overlaytests/host/test-apps/UpdateOverlay/framework/AndroidManifest.xml
@@ -16,5 +16,6 @@
 
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
     package="com.android.server.om.hosttest.framework_overlay">
+    <application android:hasCode="false" />
     <overlay android:targetPackage="android" />
 </manifest>
diff --git a/data/etc/platform.xml b/data/etc/platform.xml
index 44d71e2..28d311e 100644
--- a/data/etc/platform.xml
+++ b/data/etc/platform.xml
@@ -202,17 +202,15 @@
         <new-permission name="android.permission.ACCESS_BACKGROUND_LOCATION" />
     </split-permission>
 
-    <!-- Apps holding either the legacy READ or WRITE permissions will inherit
-         the ability to <em>read</em> new typed permissions in the Q release; they
-         won't gain the ability to <em>write</em> that content. -->
-    <!-- STOPSHIP(b/112545973): change targetSdk to Q when SDK version finalised -->
+    <!-- STOPSHIP: change targetSdk to Q when SDK version finalised -->
+    <!-- Old apps might not understand the modern permission model, hence their view needs to be expanded -->
     <split-permission name="android.permission.READ_EXTERNAL_STORAGE"
                       targetSdk="10000">
         <new-permission name="android.permission.READ_MEDIA_AUDIO" />
         <new-permission name="android.permission.READ_MEDIA_VIDEO" />
         <new-permission name="android.permission.READ_MEDIA_IMAGES" />
     </split-permission>
-    <!-- STOPSHIP(b/112545973): change targetSdk to Q when SDK version finalised -->
+    <!-- STOPSHIP: change targetSdk to Q when SDK version finalised -->
     <split-permission name="android.permission.WRITE_EXTERNAL_STORAGE"
                       targetSdk="10000">
         <new-permission name="android.permission.READ_MEDIA_AUDIO" />
@@ -220,6 +218,20 @@
         <new-permission name="android.permission.READ_MEDIA_IMAGES" />
     </split-permission>
 
+    <!-- An app using the typed media permissions might be grandfathered and then uses the old storage model -->
+    <split-permission name="android.permission.READ_MEDIA_AUDIO">
+        <new-permission name="android.permission.READ_EXTERNAL_STORAGE" />
+        <new-permission name="android.permission.WRITE_EXTERNAL_STORAGE" />
+    </split-permission>
+    <split-permission name="android.permission.READ_MEDIA_VIDEO">
+        <new-permission name="android.permission.READ_EXTERNAL_STORAGE" />
+        <new-permission name="android.permission.WRITE_EXTERNAL_STORAGE" />
+    </split-permission>
+    <split-permission name="android.permission.READ_MEDIA_IMAGES">
+        <new-permission name="android.permission.READ_EXTERNAL_STORAGE" />
+        <new-permission name="android.permission.WRITE_EXTERNAL_STORAGE" />
+    </split-permission>
+
     <!-- This is a list of all the libraries available for application
          code to link against. -->
 
diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml
index d4b3f8d..a0d14f9 100644
--- a/data/etc/privapp-permissions-platform.xml
+++ b/data/etc/privapp-permissions-platform.xml
@@ -123,6 +123,7 @@
         <permission name="android.permission.UPDATE_APP_OPS_STATS"/>
         <permission name="android.permission.REQUEST_INCIDENT_REPORT_APPROVAL"/>
         <permission name="android.permission.APPROVE_INCIDENT_REPORTS"/>
+        <permission name="android.permission.READ_PRIVILEGED_PHONE_STATE" />
     </privapp-permissions>
 
     <privapp-permissions package="com.android.phone">
@@ -306,6 +307,7 @@
         <permission name="android.permission.WRITE_SECURE_SETTINGS"/>
         <permission name="android.permission.STATUS_BAR_SERVICE"/>
         <permission name="android.permission.REQUEST_INCIDENT_REPORT_APPROVAL"/>
+        <permission name="android.permission.CONTROL_KEYGUARD_SECURE_NOTIFICATIONS"/>
     </privapp-permissions>
 
     <privapp-permissions package="com.android.statementservice">
diff --git a/docs/html/reference/images/text/style/linebackgroundspan.png b/docs/html/reference/images/text/style/linebackgroundspan.png
new file mode 100644
index 0000000..37d5253
--- /dev/null
+++ b/docs/html/reference/images/text/style/linebackgroundspan.png
Binary files differ
diff --git a/docs/html/reference/images/text/style/lineheightspan.png b/docs/html/reference/images/text/style/lineheightspan.png
new file mode 100644
index 0000000..18f5753
--- /dev/null
+++ b/docs/html/reference/images/text/style/lineheightspan.png
Binary files differ
diff --git a/graphics/java/android/graphics/ColorSpace.java b/graphics/java/android/graphics/ColorSpace.java
index 0d52338..9c4b5e8 100644
--- a/graphics/java/android/graphics/ColorSpace.java
+++ b/graphics/java/android/graphics/ColorSpace.java
@@ -1809,6 +1809,45 @@
     }
 
     /**
+     * <p>Computes the chromaticity coordinates of a specified correlated color
+     * temperature (CCT) on the Planckian locus. The specified CCT must be
+     * greater than 0. A meaningful CCT range is [1667, 25000].</p>
+     *
+     * <p>The transform is computed using the methods in Kang et
+     * al., <i>Design of Advanced Color - Temperature Control System for HDTV
+     * Applications</i>, Journal of Korean Physical Society 41, 865-871
+     * (2002).</p>
+     *
+     * @param cct The correlated color temperature, in Kelvin
+     * @return Corresponding XYZ values
+     * @throws IllegalArgumentException If cct is invalid
+     *
+     * @hide
+     */
+    @NonNull
+    @Size(3)
+    public static float[] cctToXyz(@IntRange(from = 1) int cct) {
+        if (cct < 1) {
+            throw new IllegalArgumentException("Temperature must be greater than 0");
+        }
+
+        final float icct = 1e3f / cct;
+        final float icct2 = icct * icct;
+        final float x = cct <= 4000.0f ?
+            0.179910f + 0.8776956f * icct - 0.2343589f * icct2 - 0.2661239f * icct2 * icct :
+            0.240390f + 0.2226347f * icct + 2.1070379f * icct2 - 3.0258469f * icct2 * icct;
+
+        final float x2 = x * x;
+        final float y = cct <= 2222.0f ?
+            -0.20219683f + 2.18555832f * x - 1.34811020f * x2 - 1.1063814f * x2 * x :
+            cct <= 4000.0f ?
+            -0.16748867f + 2.09137015f * x - 1.37418593f * x2 - 0.9549476f * x2 * x :
+            -0.37001483f + 3.75112997f * x - 5.8733867f * x2 + 3.0817580f * x2 * x;
+
+        return xyYToXyz(new float[] {x, y});
+    }
+
+    /**
      * <p>Computes the chromaticity coordinates of a CIE series D illuminant
      * from the specified correlated color temperature (CCT). The specified CCT
      * must be greater than 0. A meaningful CCT range is [4000, 25000].</p>
diff --git a/graphics/java/android/graphics/Typeface.java b/graphics/java/android/graphics/Typeface.java
index 9995f1e..c8b361b 100644
--- a/graphics/java/android/graphics/Typeface.java
+++ b/graphics/java/android/graphics/Typeface.java
@@ -33,7 +33,6 @@
 import android.graphics.fonts.FontVariationAxis;
 import android.graphics.fonts.SystemFonts;
 import android.os.Build;
-import android.os.Build.VERSION_CODES;
 import android.os.ParcelFileDescriptor;
 import android.provider.FontRequest;
 import android.provider.FontsContract;
@@ -48,7 +47,6 @@
 import com.android.internal.util.Preconditions;
 
 import dalvik.annotation.optimization.CriticalNative;
-import dalvik.system.VMRuntime;
 
 import libcore.util.NativeAllocationRegistry;
 
@@ -266,16 +264,7 @@
                 if (familyBuilder == null) {
                     familyBuilder = new FontFamily.Builder(fontBuilder.build());
                 } else {
-                    try {
-                        familyBuilder.addFont(fontBuilder.build());
-                    } catch (IllegalArgumentException e) {
-                        if (VMRuntime.getRuntime().getTargetSdkVersion() <= VERSION_CODES.P) {
-                            // Surpress the IllegalArgumentException for keeping the backward
-                            // compatibility.
-                            continue;
-                        }
-                        throw e;
-                    }
+                    familyBuilder.addFont(fontBuilder.build());
                 }
             }
             if (familyBuilder == null) {
@@ -297,6 +286,10 @@
             typeface = new Typeface.CustomFallbackBuilder(family)
                     .setStyle(bestFont.getStyle())
                     .build();
+        } catch (IllegalArgumentException e) {
+            // To be a compatible behavior with API28 or before, catch IllegalArgumentExcetpion
+            // thrown by native code and returns null.
+            return null;
         } catch (IOException e) {
             typeface = Typeface.DEFAULT;
         }
diff --git a/graphics/java/android/graphics/text/MeasuredText.java b/graphics/java/android/graphics/text/MeasuredText.java
index 66bcd865..9db7533 100644
--- a/graphics/java/android/graphics/text/MeasuredText.java
+++ b/graphics/java/android/graphics/text/MeasuredText.java
@@ -65,6 +65,7 @@
 
     /**
      * Returns the characters in the paragraph used to compute this MeasuredText instance.
+     * @hide
      */
     public @NonNull char[] getChars() {
         return mChars;
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreSpi.java b/keystore/java/android/security/keystore/AndroidKeyStoreSpi.java
index 105af6e..51c4252 100644
--- a/keystore/java/android/security/keystore/AndroidKeyStoreSpi.java
+++ b/keystore/java/android/security/keystore/AndroidKeyStoreSpi.java
@@ -16,7 +16,6 @@
 
 package android.security.keystore;
 
-import libcore.util.EmptyArray;
 import android.security.Credentials;
 import android.security.GateKeeper;
 import android.security.KeyStore;
@@ -31,6 +30,8 @@
 import android.security.keystore.WrappedKeyEntry;
 import android.util.Log;
 
+import libcore.util.EmptyArray;
+
 import java.io.ByteArrayInputStream;
 import java.io.IOException;
 import java.io.InputStream;
@@ -123,7 +124,14 @@
 
         final Certificate[] caList;
 
-        final byte[] caBytes = mKeyStore.get(Credentials.CA_CERTIFICATE + alias, mUid);
+        // Suppress the key not found warning for this call. It seems that this error is exclusively
+        // being thrown when there is a self signed certificate chain, so when the keystore service
+        // attempts to query for the CA details, it obviously fails to find them and returns a
+        // key not found exception. This is WAI, and throwing a stack trace here can be very
+        // misleading since the trace is not clear.
+        final byte[] caBytes = mKeyStore.get(Credentials.CA_CERTIFICATE + alias,
+                                             mUid,
+                                             true /* suppressKeyNotFoundWarning */);
         if (caBytes != null) {
             final Collection<X509Certificate> caChain = toCertificates(caBytes);
 
diff --git a/libs/androidfw/Asset.cpp b/libs/androidfw/Asset.cpp
index c512a6b..9a95fdf 100644
--- a/libs/androidfw/Asset.cpp
+++ b/libs/androidfw/Asset.cpp
@@ -292,8 +292,10 @@
 
     pAsset = new _FileAsset;
     result = pAsset->openChunk(dataMap);
-    if (result != NO_ERROR)
+    if (result != NO_ERROR) {
+        delete pAsset;
         return NULL;
+    }
 
     pAsset->mAccessMode = mode;
     return pAsset;
diff --git a/libs/androidfw/AssetManager2.cpp b/libs/androidfw/AssetManager2.cpp
index d74f27c..9519704 100644
--- a/libs/androidfw/AssetManager2.cpp
+++ b/libs/androidfw/AssetManager2.cpp
@@ -310,6 +310,9 @@
   // Start from the back.
   for (auto iter = apk_assets_.rbegin(); iter != apk_assets_.rend(); ++iter) {
     const ApkAssets* apk_assets = *iter;
+    if (apk_assets->IsOverlay()) {
+      continue;
+    }
 
     auto func = [&](const StringPiece& name, FileType type) {
       AssetDir::FileInfo info;
@@ -336,6 +339,13 @@
                                                    Asset::AccessMode mode,
                                                    ApkAssetsCookie* out_cookie) const {
   for (int32_t i = apk_assets_.size() - 1; i >= 0; i--) {
+    // Prevent RRO from modifying assets and other entries accessed by file
+    // path. Explicitly asking for a path in a given package (denoted by a
+    // cookie) is still OK.
+    if (apk_assets_[i]->IsOverlay()) {
+      continue;
+    }
+
     std::unique_ptr<Asset> asset = apk_assets_[i]->Open(filename, mode);
     if (asset) {
       if (out_cookie != nullptr) {
diff --git a/libs/androidfw/include/androidfw/ApkAssets.h b/libs/androidfw/include/androidfw/ApkAssets.h
index db2d038..35bbb58 100644
--- a/libs/androidfw/include/androidfw/ApkAssets.h
+++ b/libs/androidfw/include/androidfw/ApkAssets.h
@@ -80,6 +80,10 @@
     return loaded_arsc_.get();
   }
 
+  inline bool IsOverlay() const {
+    return idmap_asset_.get() != nullptr;
+  }
+
  private:
   DISALLOW_COPY_AND_ASSIGN(ApkAssets);
 
diff --git a/libs/hwui/Android.bp b/libs/hwui/Android.bp
index 4f1b2a4..ebba4cb 100644
--- a/libs/hwui/Android.bp
+++ b/libs/hwui/Android.bp
@@ -191,7 +191,7 @@
         "surfacetexture/EGLConsumer.cpp",
         "surfacetexture/ImageConsumer.cpp",
         "surfacetexture/SurfaceTexture.cpp",
-        "thread/TaskManager.cpp",
+        "thread/CommonPool.cpp",
         "utils/Blur.cpp",
         "utils/Color.cpp",
         "utils/GLUtils.cpp",
@@ -308,6 +308,7 @@
         "tests/unit/main.cpp",
         "tests/unit/CacheManagerTests.cpp",
         "tests/unit/CanvasContextTests.cpp",
+        "tests/unit/CommonPoolTests.cpp",
         "tests/unit/DamageAccumulatorTests.cpp",
         "tests/unit/DeferredLayerUpdaterTests.cpp",
         "tests/unit/FatVectorTests.cpp",
@@ -381,7 +382,6 @@
         "tests/microbench/LinearAllocatorBench.cpp",
         "tests/microbench/PathParserBench.cpp",
         "tests/microbench/RenderNodeBench.cpp",
-        "tests/microbench/TaskManagerBench.cpp",
     ],
 }
 
diff --git a/libs/hwui/HardwareBitmapUploader.cpp b/libs/hwui/HardwareBitmapUploader.cpp
index aeeb32c..8f7e814 100644
--- a/libs/hwui/HardwareBitmapUploader.cpp
+++ b/libs/hwui/HardwareBitmapUploader.cpp
@@ -18,6 +18,7 @@
 
 #include "hwui/Bitmap.h"
 #include "renderthread/EglManager.h"
+#include "renderthread/VulkanManager.h"
 #include "thread/ThreadBase.h"
 #include "utils/TimeUtils.h"
 
@@ -25,7 +26,9 @@
 #include <GLES2/gl2.h>
 #include <GLES2/gl2ext.h>
 #include <GLES3/gl3.h>
+#include <GrContext.h>
 #include <SkCanvas.h>
+#include <SkImage.h>
 #include <utils/GLUtils.h>
 #include <utils/Trace.h>
 #include <utils/TraceUtils.h>
@@ -33,58 +36,247 @@
 
 namespace android::uirenderer {
 
-static std::mutex sLock{};
-static sp<ThreadBase> sUploadThread = nullptr;
-static renderthread::EglManager sEglManager;
-static int sPendingUploads = 0;
-static nsecs_t sLastUpload = 0;
+class AHBUploader;
+// This helper uploader classes allows us to upload using either EGL or Vulkan using the same
+// interface.
+static sp<AHBUploader> sUploader = nullptr;
 
-static bool shouldTimeOutLocked() {
-    nsecs_t durationSince = systemTime() - sLastUpload;
-    return durationSince > 2000_ms;
-}
+struct FormatInfo {
+    PixelFormat pixelFormat;
+    GLint format, type;
+    VkFormat vkFormat;
+    bool isSupported = false;
+    bool valid = true;
+};
 
-static void checkIdleTimeout() {
-    std::lock_guard _lock{sLock};
-    if (sPendingUploads == 0 && shouldTimeOutLocked()) {
-        sEglManager.destroy();
-    } else {
-        sUploadThread->queue().postDelayed(5000_ms, checkIdleTimeout);
-    }
-}
+class AHBUploader : public RefBase {
+public:
+    virtual ~AHBUploader() {}
 
-static void beginUpload() {
-    std::lock_guard _lock{sLock};
-    sPendingUploads++;
-
-    if (!sUploadThread) {
-        sUploadThread = new ThreadBase{};
+    // Called to start creation of the Vulkan and EGL contexts on another thread before we actually
+    // need to do an upload.
+    void initialize() {
+        onInitialize();
     }
 
-    if (!sUploadThread->isRunning()) {
-        sUploadThread->start("GrallocUploadThread");
+    void destroy() {
+        std::lock_guard _lock{mLock};
+        LOG_ALWAYS_FATAL_IF(mPendingUploads, "terminate called while uploads in progress");
+        if (mUploadThread) {
+            mUploadThread->requestExit();
+            mUploadThread->join();
+            mUploadThread = nullptr;
+        }
+        onDestroy();
     }
 
-    if (!sEglManager.hasEglContext()) {
-        sUploadThread->queue().runSync([]() {
-            sEglManager.initialize();
-            glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
+    bool uploadHardwareBitmap(const SkBitmap& bitmap, const FormatInfo& format,
+                              sp<GraphicBuffer> graphicBuffer) {
+        ATRACE_CALL();
+        beginUpload();
+        bool result = onUploadHardwareBitmap(bitmap, format, graphicBuffer);
+        endUpload();
+        return result;
+    }
+
+    void postIdleTimeoutCheck() {
+        mUploadThread->queue().postDelayed(5000_ms, [this](){ this->idleTimeoutCheck(); });
+    }
+
+protected:
+    std::mutex mLock;
+    sp<ThreadBase> mUploadThread = nullptr;
+
+private:
+    virtual void onInitialize() = 0;
+    virtual void onIdle() = 0;
+    virtual void onDestroy() = 0;
+
+    virtual bool onUploadHardwareBitmap(const SkBitmap& bitmap, const FormatInfo& format,
+                                        sp<GraphicBuffer> graphicBuffer) = 0;
+    virtual void onBeginUpload() = 0;
+
+    bool shouldTimeOutLocked() {
+        nsecs_t durationSince = systemTime() - mLastUpload;
+        return durationSince > 2000_ms;
+    }
+
+    void idleTimeoutCheck() {
+        std::lock_guard _lock{mLock};
+        if (mPendingUploads == 0 && shouldTimeOutLocked()) {
+            onIdle();
+        } else {
+            this->postIdleTimeoutCheck();
+        }
+    }
+
+    void beginUpload() {
+        std::lock_guard _lock{mLock};
+        mPendingUploads++;
+
+        if (!mUploadThread) {
+            mUploadThread = new ThreadBase{};
+        }
+        if (!mUploadThread->isRunning()) {
+            mUploadThread->start("GrallocUploadThread");
+        }
+
+        onBeginUpload();
+    }
+
+    void endUpload() {
+        std::lock_guard _lock{mLock};
+        mPendingUploads--;
+        mLastUpload = systemTime();
+    }
+
+    int mPendingUploads = 0;
+    nsecs_t mLastUpload = 0;
+};
+
+#define FENCE_TIMEOUT 2000000000
+
+class EGLUploader : public AHBUploader {
+private:
+    void onInitialize() override {}
+    void onDestroy() override {
+        mEglManager.destroy();
+    }
+    void onIdle() override {
+        mEglManager.destroy();
+    }
+
+    void onBeginUpload() override {
+        if (!mEglManager.hasEglContext()) {
+            mUploadThread->queue().runSync([this]() {
+                this->mEglManager.initialize();
+                glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
+            });
+
+            this->postIdleTimeoutCheck();
+        }
+    }
+
+
+    EGLDisplay getUploadEglDisplay() {
+        std::lock_guard _lock{mLock};
+        LOG_ALWAYS_FATAL_IF(!mEglManager.hasEglContext(), "Forgot to begin an upload?");
+        return mEglManager.eglDisplay();
+    }
+
+    bool onUploadHardwareBitmap(const SkBitmap& bitmap, const FormatInfo& format,
+                                sp<GraphicBuffer> graphicBuffer) override {
+        ATRACE_CALL();
+
+        EGLDisplay display = getUploadEglDisplay();
+
+        LOG_ALWAYS_FATAL_IF(display == EGL_NO_DISPLAY, "Failed to get EGL_DEFAULT_DISPLAY! err=%s",
+                            uirenderer::renderthread::EglManager::eglErrorString());
+        // We use an EGLImage to access the content of the GraphicBuffer
+        // The EGL image is later bound to a 2D texture
+        EGLClientBuffer clientBuffer = (EGLClientBuffer)graphicBuffer->getNativeBuffer();
+        AutoEglImage autoImage(display, clientBuffer);
+        if (autoImage.image == EGL_NO_IMAGE_KHR) {
+            ALOGW("Could not create EGL image, err =%s",
+                  uirenderer::renderthread::EglManager::eglErrorString());
+            return false;
+        }
+
+        {
+            ATRACE_FORMAT("CPU -> gralloc transfer (%dx%d)", bitmap.width(), bitmap.height());
+            EGLSyncKHR fence = mUploadThread->queue().runSync([&]() -> EGLSyncKHR {
+                AutoSkiaGlTexture glTexture;
+                glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, autoImage.image);
+                GL_CHECKPOINT(MODERATE);
+
+                // glTexSubImage2D is synchronous in sense that it memcpy() from pointer that we
+                // provide.
+                // But asynchronous in sense that driver may upload texture onto hardware buffer
+                // when we first use it in drawing
+                glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, bitmap.width(), bitmap.height(),
+                                format.format, format.type, bitmap.getPixels());
+                GL_CHECKPOINT(MODERATE);
+
+                EGLSyncKHR uploadFence =
+                        eglCreateSyncKHR(eglGetCurrentDisplay(), EGL_SYNC_FENCE_KHR, NULL);
+                LOG_ALWAYS_FATAL_IF(uploadFence == EGL_NO_SYNC_KHR,
+                                    "Could not create sync fence %#x", eglGetError());
+                glFlush();
+                return uploadFence;
+            });
+
+            EGLint waitStatus = eglClientWaitSyncKHR(display, fence, 0, FENCE_TIMEOUT);
+            LOG_ALWAYS_FATAL_IF(waitStatus != EGL_CONDITION_SATISFIED_KHR,
+                                "Failed to wait for the fence %#x", eglGetError());
+
+            eglDestroySyncKHR(display, fence);
+        }
+        return true;
+    }
+
+    renderthread::EglManager mEglManager;
+};
+
+class VkUploader : public AHBUploader {
+private:
+    void onInitialize() override {
+        std::lock_guard _lock{mLock};
+        if (!mUploadThread) {
+            mUploadThread = new ThreadBase{};
+        }
+        if (!mUploadThread->isRunning()) {
+            mUploadThread->start("GrallocUploadThread");
+        }
+
+        mUploadThread->queue().post([this]() {
+            std::lock_guard _lock{mVkLock};
+            if (!mVulkanManager.hasVkContext()) {
+                mVulkanManager.initialize();
+            }
         });
-        sUploadThread->queue().postDelayed(5000_ms, checkIdleTimeout);
     }
-}
+    void onDestroy() override {
+        mGrContext.reset();
+        mVulkanManager.destroy();
+    }
+    void onIdle() override {
+        mGrContext.reset();
+    }
 
-static void endUpload() {
-    std::lock_guard _lock{sLock};
-    sPendingUploads--;
-    sLastUpload = systemTime();
-}
+    void onBeginUpload() override {
+        {
+            std::lock_guard _lock{mVkLock};
+            if (!mVulkanManager.hasVkContext()) {
+                LOG_ALWAYS_FATAL_IF(mGrContext,
+                    "GrContext exists with no VulkanManager for vulkan uploads");
+                mUploadThread->queue().runSync([this]() {
+                    mVulkanManager.initialize();
+                });
+            }
+        }
+        if (!mGrContext) {
+            GrContextOptions options;
+            mGrContext = mVulkanManager.createContext(options);
+            LOG_ALWAYS_FATAL_IF(!mGrContext, "failed to create GrContext for vulkan uploads");
+            this->postIdleTimeoutCheck();
+        }
+    }
 
-static EGLDisplay getUploadEglDisplay() {
-    std::lock_guard _lock{sLock};
-    LOG_ALWAYS_FATAL_IF(!sEglManager.hasEglContext(), "Forgot to begin an upload?");
-    return sEglManager.eglDisplay();
-}
+    bool onUploadHardwareBitmap(const SkBitmap& bitmap, const FormatInfo& format,
+                                sp<GraphicBuffer> graphicBuffer) override {
+        ATRACE_CALL();
+
+        std::lock_guard _lock{mLock};
+
+        sk_sp<SkImage> image = SkImage::MakeFromAHardwareBufferWithData(mGrContext.get(),
+            bitmap.pixmap(), reinterpret_cast<AHardwareBuffer*>(graphicBuffer.get()));
+        return (image.get() != nullptr);
+    }
+
+    sk_sp<GrContext> mGrContext;
+    renderthread::VulkanManager mVulkanManager;
+    std::mutex mVkLock;
+};
 
 bool HardwareBitmapUploader::hasFP16Support() {
     static std::once_flag sOnce;
@@ -105,16 +297,7 @@
     return hasFP16Support;
 }
 
-#define FENCE_TIMEOUT 2000000000
-
-struct FormatInfo {
-    PixelFormat pixelFormat;
-    GLint format, type;
-    bool isSupported = false;
-    bool valid = true;
-};
-
-static FormatInfo determineFormat(const SkBitmap& skBitmap) {
+static FormatInfo determineFormat(const SkBitmap& skBitmap, bool usingGL) {
     FormatInfo formatInfo;
     switch (skBitmap.info().colorType()) {
         case kRGBA_8888_SkColorType:
@@ -124,15 +307,18 @@
             formatInfo.pixelFormat = PIXEL_FORMAT_RGBA_8888;
             formatInfo.format = GL_RGBA;
             formatInfo.type = GL_UNSIGNED_BYTE;
+            formatInfo.vkFormat = VK_FORMAT_R8G8B8A8_UNORM;
             break;
         case kRGBA_F16_SkColorType:
             formatInfo.isSupported = HardwareBitmapUploader::hasFP16Support();
             if (formatInfo.isSupported) {
                 formatInfo.type = GL_HALF_FLOAT;
                 formatInfo.pixelFormat = PIXEL_FORMAT_RGBA_FP16;
+                formatInfo.vkFormat = VK_FORMAT_R16G16B16A16_SFLOAT;
             } else {
                 formatInfo.type = GL_UNSIGNED_BYTE;
                 formatInfo.pixelFormat = PIXEL_FORMAT_RGBA_8888;
+                formatInfo.vkFormat = VK_FORMAT_R8G8B8A8_UNORM;
             }
             formatInfo.format = GL_RGBA;
             break;
@@ -141,12 +327,14 @@
             formatInfo.pixelFormat = PIXEL_FORMAT_RGB_565;
             formatInfo.format = GL_RGB;
             formatInfo.type = GL_UNSIGNED_SHORT_5_6_5;
+            formatInfo.vkFormat = VK_FORMAT_R5G6B5_UNORM_PACK16;
             break;
         case kGray_8_SkColorType:
-            formatInfo.isSupported = true;
+            formatInfo.isSupported = usingGL;
             formatInfo.pixelFormat = PIXEL_FORMAT_RGBA_8888;
             formatInfo.format = GL_LUMINANCE;
             formatInfo.type = GL_UNSIGNED_BYTE;
+            formatInfo.vkFormat = VK_FORMAT_R8G8B8A8_UNORM;
             break;
         default:
             ALOGW("unable to create hardware bitmap of colortype: %d", skBitmap.info().colorType());
@@ -172,29 +360,37 @@
     }
 }
 
-class ScopedUploadRequest {
-public:
-    ScopedUploadRequest() { beginUpload(); }
-    ~ScopedUploadRequest() { endUpload(); }
-};
+
+static void createUploader(bool usingGL) {
+    static std::mutex lock;
+    std::lock_guard _lock{lock};
+    if (!sUploader.get()) {
+        if (usingGL) {
+            sUploader = new EGLUploader();
+        } else {
+            sUploader = new VkUploader();
+        }
+    }
+}
 
 sk_sp<Bitmap> HardwareBitmapUploader::allocateHardwareBitmap(const SkBitmap& sourceBitmap) {
     ATRACE_CALL();
 
-    FormatInfo format = determineFormat(sourceBitmap);
+    bool usingGL = uirenderer::Properties::getRenderPipelineType() ==
+            uirenderer::RenderPipelineType::SkiaGL;
+
+    FormatInfo format = determineFormat(sourceBitmap, usingGL);
     if (!format.valid) {
         return nullptr;
     }
 
-    ScopedUploadRequest _uploadRequest{};
-
     SkBitmap bitmap = makeHwCompatible(format, sourceBitmap);
     sp<GraphicBuffer> buffer = new GraphicBuffer(
             static_cast<uint32_t>(bitmap.width()), static_cast<uint32_t>(bitmap.height()),
             format.pixelFormat,
             GraphicBuffer::USAGE_HW_TEXTURE | GraphicBuffer::USAGE_SW_WRITE_NEVER |
                     GraphicBuffer::USAGE_SW_READ_NEVER,
-            std::string("Bitmap::allocateSkiaHardwareBitmap pid [") + std::to_string(getpid()) +
+            std::string("Bitmap::allocateHardwareBitmap pid [") + std::to_string(getpid()) +
                     "]");
 
     status_t error = buffer->initCheck();
@@ -203,64 +399,24 @@
         return nullptr;
     }
 
-    EGLDisplay display = getUploadEglDisplay();
+    createUploader(usingGL);
 
-    LOG_ALWAYS_FATAL_IF(display == EGL_NO_DISPLAY, "Failed to get EGL_DEFAULT_DISPLAY! err=%s",
-                        uirenderer::renderthread::EglManager::eglErrorString());
-    // We use an EGLImage to access the content of the GraphicBuffer
-    // The EGL image is later bound to a 2D texture
-    EGLClientBuffer clientBuffer = (EGLClientBuffer)buffer->getNativeBuffer();
-    AutoEglImage autoImage(display, clientBuffer);
-    if (autoImage.image == EGL_NO_IMAGE_KHR) {
-        ALOGW("Could not create EGL image, err =%s",
-              uirenderer::renderthread::EglManager::eglErrorString());
+    if (!sUploader->uploadHardwareBitmap(bitmap, format, buffer)) {
         return nullptr;
     }
-
-    {
-        ATRACE_FORMAT("CPU -> gralloc transfer (%dx%d)", bitmap.width(), bitmap.height());
-        EGLSyncKHR fence = sUploadThread->queue().runSync([&]() -> EGLSyncKHR {
-            AutoSkiaGlTexture glTexture;
-            glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, autoImage.image);
-            GL_CHECKPOINT(MODERATE);
-
-            // glTexSubImage2D is synchronous in sense that it memcpy() from pointer that we
-            // provide.
-            // But asynchronous in sense that driver may upload texture onto hardware buffer when we
-            // first
-            // use it in drawing
-            glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, bitmap.width(), bitmap.height(), format.format,
-                            format.type, bitmap.getPixels());
-            GL_CHECKPOINT(MODERATE);
-
-            EGLSyncKHR uploadFence =
-                    eglCreateSyncKHR(eglGetCurrentDisplay(), EGL_SYNC_FENCE_KHR, NULL);
-            LOG_ALWAYS_FATAL_IF(uploadFence == EGL_NO_SYNC_KHR, "Could not create sync fence %#x",
-                                eglGetError());
-            glFlush();
-            return uploadFence;
-        });
-
-        EGLint waitStatus = eglClientWaitSyncKHR(display, fence, 0, FENCE_TIMEOUT);
-        LOG_ALWAYS_FATAL_IF(waitStatus != EGL_CONDITION_SATISFIED_KHR,
-                            "Failed to wait for the fence %#x", eglGetError());
-
-        eglDestroySyncKHR(display, fence);
-    }
-
-    return Bitmap::createFrom(buffer.get(), bitmap.colorType(), bitmap.refColorSpace(),
+    return Bitmap::createFrom(buffer, bitmap.colorType(), bitmap.refColorSpace(),
                               bitmap.alphaType(), Bitmap::computePalette(bitmap));
 }
 
+void HardwareBitmapUploader::initialize() {
+    bool usingGL = uirenderer::Properties::getRenderPipelineType() ==
+            uirenderer::RenderPipelineType::SkiaGL;
+    createUploader(usingGL);
+    sUploader->initialize();
+}
+
 void HardwareBitmapUploader::terminate() {
-    std::lock_guard _lock{sLock};
-    LOG_ALWAYS_FATAL_IF(sPendingUploads, "terminate called while uploads in progress");
-    if (sUploadThread) {
-        sUploadThread->requestExit();
-        sUploadThread->join();
-        sUploadThread = nullptr;
-    }
-    sEglManager.destroy();
+    sUploader->destroy();
 }
 
 }  // namespace android::uirenderer
diff --git a/libs/hwui/HardwareBitmapUploader.h b/libs/hwui/HardwareBitmapUploader.h
index 6f41e6d..c300593 100644
--- a/libs/hwui/HardwareBitmapUploader.h
+++ b/libs/hwui/HardwareBitmapUploader.h
@@ -22,9 +22,11 @@
 
 class ANDROID_API HardwareBitmapUploader {
 public:
-    static sk_sp<Bitmap> allocateHardwareBitmap(const SkBitmap& sourceBitmap);
+    static void initialize();
     static void terminate();
 
+    static sk_sp<Bitmap> allocateHardwareBitmap(const SkBitmap& sourceBitmap);
+
     static bool hasFP16Support();
 };
 
diff --git a/libs/hwui/Readback.cpp b/libs/hwui/Readback.cpp
index fe633e9..fb60a96 100644
--- a/libs/hwui/Readback.cpp
+++ b/libs/hwui/Readback.cpp
@@ -28,6 +28,7 @@
 #include "hwui/Bitmap.h"
 #include "utils/Color.h"
 #include "utils/MathUtils.h"
+#include "utils/TraceUtils.h"
 
 using namespace android::uirenderer::renderthread;
 
diff --git a/libs/hwui/pipeline/skia/SkiaPipeline.cpp b/libs/hwui/pipeline/skia/SkiaPipeline.cpp
index a00a36f..721a115 100644
--- a/libs/hwui/pipeline/skia/SkiaPipeline.cpp
+++ b/libs/hwui/pipeline/skia/SkiaPipeline.cpp
@@ -25,6 +25,7 @@
 #include <SkPictureRecorder.h>
 #include "TreeInfo.h"
 #include "VectorDrawable.h"
+#include "thread/CommonPool.h"
 #include "utils/TraceUtils.h"
 
 #include <unistd.h>
@@ -49,10 +50,6 @@
     unpinImages();
 }
 
-TaskManager* SkiaPipeline::getTaskManager() {
-    return mRenderThread.cacheManager().getTaskManager();
-}
-
 void SkiaPipeline::onDestroyHardwareResources() {
     unpinImages();
     mRenderThread.cacheManager().trimStaleResources();
@@ -225,42 +222,21 @@
     }
 }
 
-class SkiaPipeline::SavePictureProcessor : public TaskProcessor<bool> {
-public:
-    explicit SavePictureProcessor(TaskManager* taskManager) : TaskProcessor<bool>(taskManager) {}
-
-    struct SavePictureTask : public Task<bool> {
-        sk_sp<SkData> data;
-        std::string filename;
-    };
-
-    void savePicture(const sk_sp<SkData>& data, const std::string& filename) {
-        sp<SavePictureTask> task(new SavePictureTask());
-        task->data = data;
-        task->filename = filename;
-        TaskProcessor<bool>::add(task);
-    }
-
-    virtual void onProcess(const sp<Task<bool>>& task) override {
-        ATRACE_NAME("SavePictureTask");
-        SavePictureTask* t = static_cast<SavePictureTask*>(task.get());
-
-        if (0 == access(t->filename.c_str(), F_OK)) {
-            task->setResult(false);
+static void savePictureAsync(const sk_sp<SkData>& data, const std::string& filename) {
+    CommonPool::post([data, filename] {
+        if (0 == access(filename.c_str(), F_OK)) {
             return;
         }
 
-        SkFILEWStream stream(t->filename.c_str());
+        SkFILEWStream stream(filename.c_str());
         if (stream.isValid()) {
-            stream.write(t->data->data(), t->data->size());
+            stream.write(data->data(), data->size());
             stream.flush();
             SkDebugf("SKP Captured Drawing Output (%d bytes) for frame. %s", stream.bytesWritten(),
-                     t->filename.c_str());
+                     filename.c_str());
         }
-
-        task->setResult(true);
-    }
-};
+    });
+}
 
 SkCanvas* SkiaPipeline::tryCapture(SkSurface* surface) {
     if (CC_UNLIKELY(Properties::skpCaptureEnabled)) {
@@ -297,16 +273,10 @@
                 ATRACE_END();
 
                 // offload saving to file in a different thread
-                if (!mSavePictureProcessor.get()) {
-                    TaskManager* taskManager = getTaskManager();
-                    mSavePictureProcessor = new SavePictureProcessor(
-                            taskManager->canRunTasks() ? taskManager : nullptr);
-                }
                 if (1 == mCaptureSequence) {
-                    mSavePictureProcessor->savePicture(data, mCapturedFile);
+                    savePictureAsync(data, mCapturedFile);
                 } else {
-                    mSavePictureProcessor->savePicture(
-                            data,
+                    savePictureAsync(data,
                             mCapturedFile + "_" + std::to_string(mCaptureSequence));
                 }
                 mCaptureSequence--;
diff --git a/libs/hwui/pipeline/skia/SkiaPipeline.h b/libs/hwui/pipeline/skia/SkiaPipeline.h
index 7381e04..41d8646 100644
--- a/libs/hwui/pipeline/skia/SkiaPipeline.h
+++ b/libs/hwui/pipeline/skia/SkiaPipeline.h
@@ -33,8 +33,6 @@
     explicit SkiaPipeline(renderthread::RenderThread& thread);
     virtual ~SkiaPipeline();
 
-    TaskManager* getTaskManager() override;
-
     void onDestroyHardwareResources() override;
 
     bool pinImages(std::vector<SkImage*>& mutableImages) override;
@@ -157,11 +155,7 @@
      *  mCaptureSequence counts how many frames are left to take in the sequence.
      */
     int mCaptureSequence = 0;
-    /**
-     *  mSavePictureProcessor is used to run the file saving code in a separate thread.
-     */
-    class SavePictureProcessor;
-    sp<SavePictureProcessor> mSavePictureProcessor;
+
     /**
      *  mRecorder holds the current picture recorder. We could store it on the stack to support
      *  parallel tryCapture calls (not really needed).
diff --git a/libs/hwui/renderthread/CacheManager.cpp b/libs/hwui/renderthread/CacheManager.cpp
index 6c04232..8b02c11 100644
--- a/libs/hwui/renderthread/CacheManager.cpp
+++ b/libs/hwui/renderthread/CacheManager.cpp
@@ -23,6 +23,7 @@
 #include "pipeline/skia/SkiaMemoryTracer.h"
 #include "Properties.h"
 #include "renderstate/RenderState.h"
+#include "thread/CommonPool.h"
 
 #include <GrContextOptions.h>
 #include <SkExecutor.h>
@@ -76,29 +77,15 @@
     mGrContext->setResourceCacheLimits(mMaxResources, mMaxResourceBytes);
 }
 
-class CacheManager::SkiaTaskProcessor : public TaskProcessor<bool>, public SkExecutor {
+class CommonPoolExecutor : public SkExecutor {
 public:
-    explicit SkiaTaskProcessor(TaskManager* taskManager) : TaskProcessor<bool>(taskManager) {}
-
-    // This is really a Task<void> but that doesn't really work when Future<>
-    // expects to be able to get/set a value
-    struct SkiaTask : public Task<bool> {
-        std::function<void()> func;
-    };
-
     virtual void add(std::function<void(void)> func) override {
-        sp<SkiaTask> task(new SkiaTask());
-        task->func = func;
-        TaskProcessor<bool>::add(task);
-    }
-
-    virtual void onProcess(const sp<Task<bool> >& task) override {
-        SkiaTask* t = static_cast<SkiaTask*>(task.get());
-        t->func();
-        task->setResult(true);
+        CommonPool::post(std::move(func));
     }
 };
 
+static CommonPoolExecutor sDefaultExecutor;
+
 void CacheManager::configureContext(GrContextOptions* contextOptions, const void* identity, ssize_t size) {
     contextOptions->fAllowPathMaskCaching = true;
 
@@ -107,12 +94,7 @@
     // provided to Skia.
     contextOptions->fGlyphCacheTextureMaximumBytes = GrNextSizePow2(mMaxSurfaceArea);
 
-    if (mTaskManager.canRunTasks()) {
-        if (!mTaskProcessor.get()) {
-            mTaskProcessor = new SkiaTaskProcessor(&mTaskManager);
-        }
-        contextOptions->fExecutor = mTaskProcessor.get();
-    }
+    contextOptions->fExecutor = &sDefaultExecutor;
 
     auto& cache = skiapipeline::ShaderCache::get();
     cache.initShaderDiskCache(identity, size);
diff --git a/libs/hwui/renderthread/CacheManager.h b/libs/hwui/renderthread/CacheManager.h
index 66f04f1..b0286e8 100644
--- a/libs/hwui/renderthread/CacheManager.h
+++ b/libs/hwui/renderthread/CacheManager.h
@@ -24,8 +24,6 @@
 #include <vector>
 
 #include "pipeline/skia/VectorDrawableAtlas.h"
-#include "thread/TaskManager.h"
-#include "thread/TaskProcessor.h"
 
 namespace android {
 
@@ -54,8 +52,6 @@
     size_t getCacheSize() const { return mMaxResourceBytes; }
     size_t getBackgroundCacheSize() const { return mBackgroundResourceBytes; }
 
-    TaskManager* getTaskManager() { return &mTaskManager; }
-
 private:
     friend class RenderThread;
 
@@ -78,10 +74,6 @@
     };
 
     sp<skiapipeline::VectorDrawableAtlas> mVectorDrawableAtlas;
-
-    class SkiaTaskProcessor;
-    sp<SkiaTaskProcessor> mTaskProcessor;
-    TaskManager mTaskManager;
 };
 
 } /* namespace renderthread */
diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp
index f5b4d93..baa41c1 100644
--- a/libs/hwui/renderthread/CanvasContext.cpp
+++ b/libs/hwui/renderthread/CanvasContext.cpp
@@ -27,8 +27,10 @@
 #include "pipeline/skia/SkiaOpenGLPipeline.h"
 #include "pipeline/skia/SkiaPipeline.h"
 #include "pipeline/skia/SkiaVulkanPipeline.h"
+#include "thread/CommonPool.h"
 #include "utils/GLUtils.h"
 #include "utils/TimeUtils.h"
+#include "utils/TraceUtils.h"
 #include "../Properties.h"
 
 #include <cutils/properties.h>
@@ -603,31 +605,14 @@
     if (mFrameFences.size()) {
         ATRACE_CALL();
         for (auto& fence : mFrameFences) {
-            fence->getResult();
+            fence.get();
         }
         mFrameFences.clear();
     }
 }
 
-class CanvasContext::FuncTaskProcessor : public TaskProcessor<bool> {
-public:
-    explicit FuncTaskProcessor(TaskManager* taskManager) : TaskProcessor<bool>(taskManager) {}
-
-    virtual void onProcess(const sp<Task<bool> >& task) override {
-        FuncTask* t = static_cast<FuncTask*>(task.get());
-        t->func();
-        task->setResult(true);
-    }
-};
-
 void CanvasContext::enqueueFrameWork(std::function<void()>&& func) {
-    if (!mFrameWorkProcessor.get()) {
-        mFrameWorkProcessor = new FuncTaskProcessor(mRenderPipeline->getTaskManager());
-    }
-    sp<FuncTask> task(new FuncTask());
-    task->func = func;
-    mFrameFences.push_back(task);
-    mFrameWorkProcessor->add(task);
+    mFrameFences.push_back(CommonPool::async(std::move(func)));
 }
 
 int64_t CanvasContext::getFrameNumber() {
diff --git a/libs/hwui/renderthread/CanvasContext.h b/libs/hwui/renderthread/CanvasContext.h
index 4da0eac..abca342 100644
--- a/libs/hwui/renderthread/CanvasContext.h
+++ b/libs/hwui/renderthread/CanvasContext.h
@@ -28,8 +28,6 @@
 #include "ReliableSurface.h"
 #include "renderthread/RenderTask.h"
 #include "renderthread/RenderThread.h"
-#include "thread/Task.h"
-#include "thread/TaskProcessor.h"
 
 #include <EGL/egl.h>
 #include <SkBitmap.h>
@@ -42,6 +40,7 @@
 #include <set>
 #include <string>
 #include <vector>
+#include <future>
 
 namespace android {
 namespace uirenderer {
@@ -274,15 +273,7 @@
     // Stores the bounds of the main content.
     Rect mContentDrawBounds;
 
-    // TODO: This is really a Task<void> but that doesn't really work
-    // when Future<> expects to be able to get/set a value
-    struct FuncTask : public Task<bool> {
-        std::function<void()> func;
-    };
-    class FuncTaskProcessor;
-
-    std::vector<sp<FuncTask>> mFrameFences;
-    sp<TaskProcessor<bool>> mFrameWorkProcessor;
+    std::vector<std::future<void>> mFrameFences;
     std::unique_ptr<IRenderPipeline> mRenderPipeline;
 
     std::vector<std::function<void(int64_t)>> mFrameCompleteCallbacks;
diff --git a/libs/hwui/renderthread/IRenderPipeline.h b/libs/hwui/renderthread/IRenderPipeline.h
index 2cfc8df3..0502eb8 100644
--- a/libs/hwui/renderthread/IRenderPipeline.h
+++ b/libs/hwui/renderthread/IRenderPipeline.h
@@ -75,7 +75,6 @@
     virtual void renderLayers(const LightGeometry& lightGeometry,
                               LayerUpdateQueue* layerUpdateQueue, bool opaque,
                               const LightInfo& lightInfo) = 0;
-    virtual TaskManager* getTaskManager() = 0;
     virtual bool createOrUpdateLayer(RenderNode* node, const DamageAccumulator& damageAccumulator,
                                      ErrorHandler* errorHandler) = 0;
     virtual bool pinImages(std::vector<SkImage*>& mutableImages) = 0;
diff --git a/libs/hwui/renderthread/RenderProxy.cpp b/libs/hwui/renderthread/RenderProxy.cpp
index 34f76d9..1bcb819 100644
--- a/libs/hwui/renderthread/RenderProxy.cpp
+++ b/libs/hwui/renderthread/RenderProxy.cpp
@@ -31,6 +31,7 @@
 #include "renderthread/RenderThread.h"
 #include "utils/Macros.h"
 #include "utils/TimeUtils.h"
+#include "utils/TraceUtils.h"
 
 #include <ui/GraphicBuffer.h>
 
diff --git a/libs/hwui/renderthread/RenderThread.cpp b/libs/hwui/renderthread/RenderThread.cpp
index c784d64..6cce319 100644
--- a/libs/hwui/renderthread/RenderThread.cpp
+++ b/libs/hwui/renderthread/RenderThread.cpp
@@ -28,6 +28,8 @@
 #include "renderstate/RenderState.h"
 #include "utils/FatVector.h"
 #include "utils/TimeUtils.h"
+#include "utils/TraceUtils.h"
+#include "../HardwareBitmapUploader.h"
 
 #ifdef HWUI_GLES_WRAP_ENABLED
 #include "debug/GlesDriver.h"
@@ -414,6 +416,7 @@
     if (Properties::getRenderPipelineType() == RenderPipelineType::SkiaVulkan) {
         requireVkContext();
     }
+    HardwareBitmapUploader::initialize();
 }
 
 } /* namespace renderthread */
diff --git a/libs/hwui/renderthread/RenderThread.h b/libs/hwui/renderthread/RenderThread.h
index 9298be6..5f43b48 100644
--- a/libs/hwui/renderthread/RenderThread.h
+++ b/libs/hwui/renderthread/RenderThread.h
@@ -41,6 +41,7 @@
 namespace android {
 
 class Bitmap;
+class AutoBackendTextureRelease;
 
 namespace uirenderer {
 
@@ -135,6 +136,7 @@
     friend class DispatchFrameCallbacks;
     friend class RenderProxy;
     friend class DummyVsyncSource;
+    friend class android::AutoBackendTextureRelease;
     friend class android::uirenderer::TestUtils;
     friend class android::uirenderer::WebViewFunctor;
     friend class android::uirenderer::skiapipeline::VkFunctorDrawHandler;
diff --git a/libs/hwui/renderthread/VulkanManager.cpp b/libs/hwui/renderthread/VulkanManager.cpp
index 6dacc7a..9916da5 100644
--- a/libs/hwui/renderthread/VulkanManager.cpp
+++ b/libs/hwui/renderthread/VulkanManager.cpp
@@ -23,6 +23,7 @@
 #include "RenderThread.h"
 #include "renderstate/RenderState.h"
 #include "utils/FatVector.h"
+#include "utils/TraceUtils.h"
 
 #include <GrBackendSemaphore.h>
 #include <GrBackendSurface.h>
diff --git a/libs/hwui/surfacetexture/ImageConsumer.cpp b/libs/hwui/surfacetexture/ImageConsumer.cpp
index 077a8f7..65d95ad 100644
--- a/libs/hwui/surfacetexture/ImageConsumer.cpp
+++ b/libs/hwui/surfacetexture/ImageConsumer.cpp
@@ -24,13 +24,17 @@
 #include "renderthread/VulkanManager.h"
 #include "utils/Color.h"
 #include <GrAHardwareBufferUtils.h>
+#include <GrBackendSurface.h>
 
 // Macro for including the SurfaceTexture name in log messages
 #define IMG_LOGE(x, ...) ALOGE("[%s] " x, st.mName.string(), ##__VA_ARGS__)
 
+using namespace android::uirenderer::renderthread;
+
 namespace android {
 
 void ImageConsumer::onFreeBufferLocked(int slotIndex) {
+    // This callback may be invoked on any thread.
     mImageSlots[slotIndex].clear();
 }
 
@@ -46,55 +50,141 @@
     mImageSlots[buf].eglFence() = EGL_NO_SYNC_KHR;
 }
 
+/**
+ * AutoBackendTextureRelease manages EglImage/VkImage lifetime. It is a ref-counted object
+ * that keeps GPU resources alive until the last SKImage object using them is destroyed.
+ */
+class AutoBackendTextureRelease {
+public:
+    static void releaseProc(SkImage::ReleaseContext releaseContext);
+
+    AutoBackendTextureRelease(GrContext* context, GraphicBuffer* buffer);
+
+    const GrBackendTexture& getTexture() const { return mBackendTexture; }
+
+    void ref() { mUsageCount++; }
+
+    void unref(bool releaseImage);
+
+    inline sk_sp<SkImage> getImage() { return mImage; }
+
+    void makeImage(sp<GraphicBuffer>& graphicBuffer, android_dataspace dataspace,
+                   GrContext* context);
+
+private:
+    // The only way to invoke dtor is with unref, when mUsageCount is 0.
+    ~AutoBackendTextureRelease() {}
+
+    GrBackendTexture mBackendTexture;
+    GrAHardwareBufferUtils::DeleteImageProc mDeleteProc;
+    GrAHardwareBufferUtils::DeleteImageCtx mDeleteCtx;
+
+    // Starting with refcount 1, because the first ref is held by SurfaceTexture. Additional refs
+    // are held by SkImages.
+    int mUsageCount = 1;
+
+    // mImage is the SkImage created from mBackendTexture.
+    sk_sp<SkImage> mImage;
+};
+
+AutoBackendTextureRelease::AutoBackendTextureRelease(GrContext* context, GraphicBuffer* buffer) {
+    bool createProtectedImage =
+        0 != (buffer->getUsage() & GraphicBuffer::USAGE_PROTECTED);
+    GrBackendFormat backendFormat = GrAHardwareBufferUtils::GetBackendFormat(
+        context,
+        reinterpret_cast<AHardwareBuffer*>(buffer),
+        buffer->getPixelFormat(),
+        false);
+    mBackendTexture = GrAHardwareBufferUtils::MakeBackendTexture(
+        context,
+        reinterpret_cast<AHardwareBuffer*>(buffer),
+        buffer->getWidth(),
+        buffer->getHeight(),
+        &mDeleteProc,
+        &mDeleteCtx,
+        createProtectedImage,
+        backendFormat,
+        false);
+}
+
+void AutoBackendTextureRelease::unref(bool releaseImage) {
+    if (!RenderThread::isCurrent()) {
+        // EGLImage needs to be destroyed on RenderThread to prevent memory leak.
+        // ~SkImage dtor for both pipelines needs to be invoked on RenderThread, because it is not
+        // thread safe.
+        RenderThread::getInstance().queue().post([this, releaseImage]() { unref(releaseImage); });
+        return;
+    }
+
+    if (releaseImage) {
+        mImage.reset();
+    }
+
+    mUsageCount--;
+    if (mUsageCount <= 0) {
+        if (mBackendTexture.isValid()) {
+            mDeleteProc(mDeleteCtx);
+            mBackendTexture = {};
+        }
+        delete this;
+    }
+}
+
+void AutoBackendTextureRelease::releaseProc(SkImage::ReleaseContext releaseContext) {
+    AutoBackendTextureRelease* textureRelease =
+        reinterpret_cast<AutoBackendTextureRelease*>(releaseContext);
+    textureRelease->unref(false);
+}
+
+void AutoBackendTextureRelease::makeImage(sp<GraphicBuffer>& graphicBuffer,
+                                          android_dataspace dataspace, GrContext* context) {
+    SkColorType colorType = GrAHardwareBufferUtils::GetSkColorTypeFromBufferFormat(
+        graphicBuffer->getPixelFormat());
+    mImage = SkImage::MakeFromTexture(context,
+        mBackendTexture,
+        kTopLeft_GrSurfaceOrigin,
+        colorType,
+        kPremul_SkAlphaType,
+        uirenderer::DataSpaceToColorSpace(dataspace),
+        releaseProc,
+        this);
+    if (mImage.get()) {
+        // The following ref will be counteracted by releaseProc, when SkImage is discarded.
+        ref();
+    }
+}
+
 void ImageConsumer::ImageSlot::createIfNeeded(sp<GraphicBuffer> graphicBuffer,
                                               android_dataspace dataspace, bool forceCreate,
                                               GrContext* context) {
-    if (!mImage.get() || dataspace != mDataspace || forceCreate) {
+    if (!mTextureRelease || !mTextureRelease->getImage().get() || dataspace != mDataspace
+            || forceCreate) {
         if (!graphicBuffer.get()) {
             clear();
             return;
         }
 
-        if (!mBackendTexture.isValid()) {
-            clear();
-            bool createProtectedImage =
-                0 != (graphicBuffer->getUsage() & GraphicBuffer::USAGE_PROTECTED);
-            GrBackendFormat backendFormat = GrAHardwareBufferUtils::GetBackendFormat(
-                context,
-                reinterpret_cast<AHardwareBuffer*>(graphicBuffer.get()),
-                graphicBuffer->getPixelFormat(),
-                false);
-            mBackendTexture = GrAHardwareBufferUtils::MakeBackendTexture(
-                context,
-                reinterpret_cast<AHardwareBuffer*>(graphicBuffer.get()),
-                graphicBuffer->getWidth(),
-                graphicBuffer->getHeight(),
-                &mDeleteProc,
-                &mDeleteCtx,
-                createProtectedImage,
-                backendFormat,
-                false);
+        if (!mTextureRelease) {
+            mTextureRelease = new AutoBackendTextureRelease(context, graphicBuffer.get());
         }
+
         mDataspace = dataspace;
-        SkColorType colorType = GrAHardwareBufferUtils::GetSkColorTypeFromBufferFormat(
-            graphicBuffer->getPixelFormat());
-        mImage = SkImage::MakeFromTexture(context,
-            mBackendTexture,
-            kTopLeft_GrSurfaceOrigin,
-            colorType,
-            kPremul_SkAlphaType,
-            uirenderer::DataSpaceToColorSpace(dataspace));
+        mTextureRelease->makeImage(graphicBuffer, dataspace, context);
     }
 }
 
 void ImageConsumer::ImageSlot::clear() {
-    mImage.reset();
-    if (mBackendTexture.isValid()) {
-        mDeleteProc(mDeleteCtx);
-        mBackendTexture = {};
+    if (mTextureRelease) {
+        // The following unref counteracts the initial mUsageCount of 1, set by default initializer.
+        mTextureRelease->unref(true);
+        mTextureRelease = nullptr;
     }
 }
 
+sk_sp<SkImage> ImageConsumer::ImageSlot::getImage() {
+    return mTextureRelease ? mTextureRelease->getImage() : nullptr;
+}
+
 sk_sp<SkImage> ImageConsumer::dequeueImage(bool* queueEmpty, SurfaceTexture& st,
                                            uirenderer::RenderState& renderState) {
     BufferItem item;
diff --git a/libs/hwui/surfacetexture/ImageConsumer.h b/libs/hwui/surfacetexture/ImageConsumer.h
index eee0a0a..2fdece9 100644
--- a/libs/hwui/surfacetexture/ImageConsumer.h
+++ b/libs/hwui/surfacetexture/ImageConsumer.h
@@ -25,7 +25,6 @@
 #include <cutils/compiler.h>
 #include <gui/BufferItem.h>
 #include <system/graphics.h>
-#include <GrBackendSurface.h>
 
 namespace GrAHardwareBufferUtils {
 typedef void* DeleteImageCtx;
@@ -38,6 +37,7 @@
 class RenderState;
 }
 
+class AutoBackendTextureRelease;
 class SurfaceTexture;
 
 /*
@@ -81,16 +81,14 @@
 
         void createIfNeeded(sp<GraphicBuffer> graphicBuffer, android_dataspace dataspace,
                             bool forceCreate, GrContext* context);
+
         void clear();
 
         inline EGLSyncKHR& eglFence() { return mEglFence; }
 
-        inline sk_sp<SkImage> getImage() { return mImage; }
+        sk_sp<SkImage> getImage();
 
     private:
-        // mImage is the SkImage created from mGraphicBuffer.
-        sk_sp<SkImage> mImage;
-
         // the dataspace associated with the current image
         android_dataspace mDataspace;
 
@@ -100,11 +98,11 @@
          */
         EGLSyncKHR mEglFence;
 
-        GrBackendTexture mBackendTexture;
-
-        GrAHardwareBufferUtils::DeleteImageProc mDeleteProc;
-
-        GrAHardwareBufferUtils::DeleteImageCtx mDeleteCtx;
+        /**
+         * mTextureRelease may outlive ImageConsumer, if the last ref is held by an SkImage.
+         * ImageConsumer holds one ref to mTextureRelease, which is decremented by "clear".
+         */
+        AutoBackendTextureRelease* mTextureRelease = nullptr;
     };
 
     /**
diff --git a/libs/hwui/tests/macrobench/TestSceneRunner.cpp b/libs/hwui/tests/macrobench/TestSceneRunner.cpp
index 0e61899e..b45dbc8 100644
--- a/libs/hwui/tests/macrobench/TestSceneRunner.cpp
+++ b/libs/hwui/tests/macrobench/TestSceneRunner.cpp
@@ -21,6 +21,7 @@
 #include "tests/common/TestContext.h"
 #include "tests/common/TestScene.h"
 #include "tests/common/scenes/TestSceneBase.h"
+#include "utils/TraceUtils.h"
 
 #include <benchmark/benchmark.h>
 #include <gui/Surface.h>
diff --git a/libs/hwui/tests/microbench/TaskManagerBench.cpp b/libs/hwui/tests/microbench/TaskManagerBench.cpp
deleted file mode 100644
index 4153bae..0000000
--- a/libs/hwui/tests/microbench/TaskManagerBench.cpp
+++ /dev/null
@@ -1,134 +0,0 @@
-/*
- * Copyright (C) 2016 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 <benchmark/benchmark.h>
-
-#include "thread/Task.h"
-#include "thread/TaskManager.h"
-#include "thread/TaskProcessor.h"
-#include "thread/ThreadBase.h"
-
-#include <atomic>
-#include <vector>
-
-using namespace android;
-using namespace android::uirenderer;
-
-class TrivialTask : public Task<char> {};
-
-class TrivialProcessor : public TaskProcessor<char> {
-public:
-    explicit TrivialProcessor(TaskManager* manager) : TaskProcessor(manager) {}
-    virtual ~TrivialProcessor() {}
-    virtual void onProcess(const sp<Task<char>>& task) override {
-        TrivialTask* t = static_cast<TrivialTask*>(task.get());
-        t->setResult(reinterpret_cast<intptr_t>(t) % 16 == 0 ? 'a' : 'b');
-    }
-};
-
-class TestThread : public ThreadBase, public virtual RefBase {};
-
-void BM_TaskManager_allocateTask(benchmark::State& state) {
-    std::vector<sp<TrivialTask>> tasks;
-    tasks.reserve(state.max_iterations);
-
-    while (state.KeepRunning()) {
-        tasks.emplace_back(new TrivialTask);
-        benchmark::DoNotOptimize(tasks.back());
-    }
-}
-BENCHMARK(BM_TaskManager_allocateTask);
-
-void BM_TaskManager_enqueueTask(benchmark::State& state) {
-    TaskManager taskManager;
-    sp<TrivialProcessor> processor(new TrivialProcessor(&taskManager));
-    std::vector<sp<TrivialTask>> tasks;
-    tasks.reserve(state.max_iterations);
-
-    while (state.KeepRunning()) {
-        tasks.emplace_back(new TrivialTask);
-        benchmark::DoNotOptimize(tasks.back());
-        processor->add(tasks.back());
-    }
-
-    for (sp<TrivialTask>& task : tasks) {
-        task->getResult();
-    }
-}
-BENCHMARK(BM_TaskManager_enqueueTask);
-
-void BM_TaskManager_enqueueRunDeleteTask(benchmark::State& state) {
-    TaskManager taskManager;
-    sp<TrivialProcessor> processor(new TrivialProcessor(&taskManager));
-    std::vector<sp<TrivialTask>> tasks;
-    tasks.reserve(state.max_iterations);
-
-    while (state.KeepRunning()) {
-        tasks.emplace_back(new TrivialTask);
-        benchmark::DoNotOptimize(tasks.back());
-        processor->add(tasks.back());
-    }
-    state.ResumeTiming();
-    for (sp<TrivialTask>& task : tasks) {
-        benchmark::DoNotOptimize(task->getResult());
-    }
-    tasks.clear();
-    state.PauseTiming();
-}
-BENCHMARK(BM_TaskManager_enqueueRunDeleteTask);
-
-void BM_Thread_enqueueTask(benchmark::State& state) {
-    sp<TestThread> thread{new TestThread};
-    thread->start();
-
-    atomic_int counter(0);
-    int expected = 0;
-    while (state.KeepRunning()) {
-        expected++;
-        thread->queue().post([&counter]() { counter++; });
-    }
-    thread->queue().runSync([]() {});
-
-    thread->requestExit();
-    thread->join();
-    if (counter != expected) {
-        printf("Ran %d lambads, should have been %d\n", counter.load(), expected);
-    }
-}
-BENCHMARK(BM_Thread_enqueueTask);
-
-void BM_Thread_enqueueRunDeleteTask(benchmark::State& state) {
-    sp<TestThread> thread{new TestThread};
-    thread->start();
-    std::vector<std::future<int>> tasks;
-    tasks.reserve(state.max_iterations);
-
-    int expected = 0;
-    while (state.KeepRunning()) {
-        tasks.emplace_back(thread->queue().async([expected]() -> int { return expected + 1; }));
-        expected++;
-    }
-    state.ResumeTiming();
-    expected = 0;
-    for (auto& future : tasks) {
-        if (future.get() != ++expected) {
-            printf("Mismatch expected %d vs. observed %d\n", expected, future.get());
-        }
-    }
-    tasks.clear();
-    state.PauseTiming();
-}
-BENCHMARK(BM_Thread_enqueueRunDeleteTask);
\ No newline at end of file
diff --git a/libs/hwui/tests/unit/CommonPoolTests.cpp b/libs/hwui/tests/unit/CommonPoolTests.cpp
new file mode 100644
index 0000000..c564ed6
--- /dev/null
+++ b/libs/hwui/tests/unit/CommonPoolTests.cpp
@@ -0,0 +1,138 @@
+/*
+ * 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.
+ */
+
+#include <gtest/gtest.h>
+
+#include "thread/CommonPool.h"
+
+#include <array>
+#include <condition_variable>
+#include <set>
+#include <thread>
+#include "unistd.h"
+
+using namespace android;
+using namespace android::uirenderer;
+
+TEST(CommonPool, post) {
+    std::atomic_bool ran(false);
+    CommonPool::post([&ran] { ran = true; });
+    for (int i = 0; !ran && i < 1000; i++) {
+        usleep(1);
+    }
+    EXPECT_TRUE(ran) << "Failed to flip atomic after 1 second";
+}
+
+TEST(CommonPool, threadCount) {
+    std::set<pid_t> threads;
+    std::array<std::future<pid_t>, 64> futures;
+    for (int i = 0; i < futures.size(); i++) {
+        futures[i] = CommonPool::async([] {
+            usleep(10);
+            return gettid();
+        });
+    }
+    for (auto& f : futures) {
+        threads.insert(f.get());
+    }
+    EXPECT_EQ(threads.size(), CommonPool::THREAD_COUNT);
+    EXPECT_EQ(0, threads.count(gettid()));
+}
+
+TEST(CommonPool, singleThread) {
+    std::mutex mutex;
+    std::condition_variable fence;
+    bool isProcessing = false;
+    bool queuedSecond = false;
+
+    auto f1 = CommonPool::async([&] {
+        {
+            std::unique_lock lock{mutex};
+            isProcessing = true;
+            fence.notify_all();
+            while (!queuedSecond) {
+                fence.wait(lock);
+            }
+        }
+        return gettid();
+    });
+
+    {
+        std::unique_lock lock{mutex};
+        while (!isProcessing) {
+            fence.wait(lock);
+        }
+    }
+
+    auto f2 = CommonPool::async([] {
+        return gettid();
+    });
+
+    {
+        std::unique_lock lock{mutex};
+        queuedSecond = true;
+        fence.notify_all();
+    }
+
+    auto tid1 = f1.get();
+    auto tid2 = f2.get();
+    EXPECT_EQ(tid1, tid2);
+    EXPECT_NE(gettid(), tid1);
+}
+
+TEST(CommonPool, fullQueue) {
+    std::mutex lock;
+    std::condition_variable fence;
+    bool signaled = false;
+    static constexpr auto QUEUE_COUNT = CommonPool::THREAD_COUNT + CommonPool::QUEUE_SIZE + 10;
+    std::atomic_int queuedCount{0};
+    std::array<std::future<void>, QUEUE_COUNT> futures;
+
+    std::thread queueThread{[&] {
+        for (int i = 0; i < QUEUE_COUNT; i++) {
+            futures[i] = CommonPool::async([&] {
+                std::unique_lock _lock{lock};
+                while (!signaled) {
+                    fence.wait(_lock);
+                }
+            });
+            queuedCount++;
+        }
+    }};
+
+    int previous;
+    do {
+        previous = queuedCount.load();
+        usleep(10000);
+    } while (previous != queuedCount.load());
+
+    EXPECT_GT(queuedCount.load(), CommonPool::QUEUE_SIZE);
+    EXPECT_LT(queuedCount.load(), QUEUE_COUNT);
+
+    {
+        std::unique_lock _lock{lock};
+        signaled = true;
+        fence.notify_all();
+    }
+
+    queueThread.join();
+    EXPECT_EQ(queuedCount.load(), QUEUE_COUNT);
+
+    // Ensure all our tasks are finished before return as they have references to the stack
+    for (auto& f : futures) {
+        f.get();
+    }
+}
\ No newline at end of file
diff --git a/libs/hwui/tests/unit/main.cpp b/libs/hwui/tests/unit/main.cpp
index 63d1540..83d888c 100644
--- a/libs/hwui/tests/unit/main.cpp
+++ b/libs/hwui/tests/unit/main.cpp
@@ -22,9 +22,6 @@
 #include "debug/NullGlesDriver.h"
 #include "hwui/Typeface.h"
 #include "tests/common/LeakChecker.h"
-#include "thread/Task.h"
-#include "thread/TaskManager.h"
-#include "thread/TaskProcessor.h"
 
 #include <signal.h>
 
diff --git a/libs/hwui/thread/Barrier.h b/libs/hwui/thread/Barrier.h
deleted file mode 100644
index bb750ca..0000000
--- a/libs/hwui/thread/Barrier.h
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * Copyright (C) 2013 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.
- */
-
-#ifndef ANDROID_HWUI_BARRIER_H
-#define ANDROID_HWUI_BARRIER_H
-
-#include <utils/Condition.h>
-
-namespace android {
-namespace uirenderer {
-
-class Barrier {
-public:
-    explicit Barrier(Condition::WakeUpType type = Condition::WAKE_UP_ALL)
-            : mType(type), mOpened(false) {}
-    ~Barrier() {}
-
-    void open() {
-        Mutex::Autolock l(mLock);
-        mOpened = true;
-        mCondition.signal(mType);
-    }
-
-    void wait() const {
-        Mutex::Autolock l(mLock);
-        while (!mOpened) {
-            mCondition.wait(mLock);
-        }
-    }
-
-private:
-    Condition::WakeUpType mType;
-    volatile bool mOpened;
-    mutable Mutex mLock;
-    mutable Condition mCondition;
-};
-
-}  // namespace uirenderer
-}  // namespace android
-
-#endif  // ANDROID_HWUI_BARRIER_H
diff --git a/libs/hwui/thread/CommonPool.cpp b/libs/hwui/thread/CommonPool.cpp
new file mode 100644
index 0000000..7f94a15
--- /dev/null
+++ b/libs/hwui/thread/CommonPool.cpp
@@ -0,0 +1,90 @@
+/*
+ * 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.
+ */
+
+#include "CommonPool.h"
+
+#include <sys/resource.h>
+#include <utils/Trace.h>
+#include "renderthread/RenderThread.h"
+
+#include <array>
+
+namespace android {
+namespace uirenderer {
+
+CommonPool::CommonPool() {
+    ATRACE_CALL();
+
+    CommonPool* pool = this;
+    // Create 2 workers
+    for (int i = 0; i < THREAD_COUNT; i++) {
+        std::thread worker([pool, i] {
+            {
+                std::array<char, 20> name{"hwuiTask"};
+                snprintf(name.data(), name.size(), "hwuiTask%d", i);
+                auto self = pthread_self();
+                pthread_setname_np(self, name.data());
+                setpriority(PRIO_PROCESS, 0, PRIORITY_FOREGROUND);
+                auto startHook = renderthread::RenderThread::getOnStartHook();
+                if (startHook) {
+                    startHook(name.data());
+                }
+            }
+            pool->workerLoop();
+        });
+        worker.detach();
+    }
+}
+
+void CommonPool::post(Task&& task) {
+    static CommonPool pool;
+    pool.enqueue(std::move(task));
+}
+
+void CommonPool::enqueue(Task&& task) {
+    std::unique_lock lock(mLock);
+    while (!mWorkQueue.hasSpace()) {
+        lock.unlock();
+        usleep(100);
+        lock.lock();
+    }
+    mWorkQueue.push(std::move(task));
+    if (mWaitingThreads == THREAD_COUNT || (mWaitingThreads > 0 && mWorkQueue.size() > 1)) {
+        mCondition.notify_one();
+    }
+}
+
+void CommonPool::workerLoop() {
+    std::unique_lock lock(mLock);
+    while (true) {
+        if (!mWorkQueue.hasWork()) {
+            mWaitingThreads++;
+            mCondition.wait(lock);
+            mWaitingThreads--;
+        }
+        // Need to double-check that work is still available now that we have the lock
+        // It may have already been grabbed by a different thread
+        while (mWorkQueue.hasWork()) {
+            auto work = mWorkQueue.pop();
+            lock.unlock();
+            work();
+            lock.lock();
+        }
+    }
+}
+
+}  // namespace uirenderer
+}  // namespace android
\ No newline at end of file
diff --git a/libs/hwui/thread/CommonPool.h b/libs/hwui/thread/CommonPool.h
new file mode 100644
index 0000000..aef2990
--- /dev/null
+++ b/libs/hwui/thread/CommonPool.h
@@ -0,0 +1,115 @@
+/*
+ * 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.
+ */
+
+#ifndef FRAMEWORKS_BASE_COMMONPOOL_H
+#define FRAMEWORKS_BASE_COMMONPOOL_H
+
+#include "utils/Macros.h"
+
+#include <log/log.h>
+
+#include <condition_variable>
+#include <functional>
+#include <future>
+#include <mutex>
+
+namespace android {
+namespace uirenderer {
+
+template <class T, int SIZE>
+class ArrayQueue {
+    PREVENT_COPY_AND_ASSIGN(ArrayQueue);
+    static_assert(SIZE > 0, "Size must be positive");
+
+public:
+    ArrayQueue() = default;
+    ~ArrayQueue() = default;
+
+    constexpr size_t capacity() const { return SIZE; }
+    constexpr bool hasWork() const { return mHead != mTail; }
+    constexpr bool hasSpace() const { return ((mHead + 1) % SIZE) != mTail; }
+    constexpr int size() const {
+        if (mHead > mTail) {
+            return mHead - mTail;
+        } else {
+            return mTail - mHead + SIZE;
+        }
+    }
+
+    constexpr void push(T&& t) {
+        int newHead = (mHead + 1) % SIZE;
+        LOG_ALWAYS_FATAL_IF(newHead == mTail, "no space");
+
+        mBuffer[mHead] = std::move(t);
+        mHead = newHead;
+    }
+
+    constexpr T&& pop() {
+        LOG_ALWAYS_FATAL_IF(mTail == mHead, "empty");
+        int index = mTail;
+        mTail = (mTail + 1) % SIZE;
+        return std::move(mBuffer[index]);
+    }
+
+private:
+    T mBuffer[SIZE];
+    int mHead = 0;
+    int mTail = 0;
+};
+
+class CommonPool {
+    PREVENT_COPY_AND_ASSIGN(CommonPool);
+
+public:
+    using Task = std::function<void()>;
+    static constexpr auto THREAD_COUNT = 2;
+    static constexpr auto QUEUE_SIZE = 128;
+
+    static void post(Task&& func);
+
+    template <class F>
+    static auto async(F&& func) -> std::future<decltype(func())> {
+        typedef std::packaged_task<decltype(func())()> task_t;
+        auto task = std::make_shared<task_t>(std::forward<F>(func));
+        post([task]() { std::invoke(*task); });
+        return task->get_future();
+    }
+
+    template <class F>
+    static auto runSync(F&& func) -> decltype(func()) {
+        std::packaged_task<decltype(func())()> task{std::forward<F>(func)};
+        post([&task]() { std::invoke(task); });
+        return task.get_future().get();
+    };
+
+private:
+    CommonPool();
+    ~CommonPool() {}
+
+    void enqueue(Task&&);
+
+    void workerLoop();
+
+    std::mutex mLock;
+    std::condition_variable mCondition;
+    int mWaitingThreads = 0;
+    ArrayQueue<Task, QUEUE_SIZE> mWorkQueue;
+};
+
+}  // namespace uirenderer
+}  // namespace android
+
+#endif  // FRAMEWORKS_BASE_COMMONPOOL_H
diff --git a/libs/hwui/thread/Future.h b/libs/hwui/thread/Future.h
deleted file mode 100644
index df53348e..0000000
--- a/libs/hwui/thread/Future.h
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Copyright (C) 2013 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.
- */
-
-#ifndef ANDROID_HWUI_FUTURE_H
-#define ANDROID_HWUI_FUTURE_H
-
-#include <utils/RefBase.h>
-
-#include "Barrier.h"
-
-namespace android {
-namespace uirenderer {
-
-template <typename T>
-class Future : public LightRefBase<Future<T> > {
-public:
-    explicit Future(Condition::WakeUpType type = Condition::WAKE_UP_ONE)
-            : mBarrier(type), mResult() {}
-    ~Future() {}
-
-    /**
-     * Returns the result of this future, blocking if
-     * the result is not available yet.
-     */
-    T get() const {
-        mBarrier.wait();
-        return mResult;
-    }
-
-    /**
-     * This method must be called only once.
-     */
-    void produce(T result) {
-        mResult = result;
-        mBarrier.open();
-    }
-
-private:
-    Barrier mBarrier;
-    T mResult;
-};
-
-}  // namespace uirenderer
-}  // namespace android
-
-#endif  // ANDROID_HWUI_FUTURE_H
diff --git a/libs/hwui/thread/Signal.h b/libs/hwui/thread/Signal.h
deleted file mode 100644
index 6d33ac4..0000000
--- a/libs/hwui/thread/Signal.h
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Copyright (C) 2013 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.
- */
-
-#ifndef ANDROID_HWUI_SIGNAL_H
-#define ANDROID_HWUI_SIGNAL_H
-
-#include <stdint.h>
-#include <sys/types.h>
-#include <utils/threads.h>
-
-namespace android {
-namespace uirenderer {
-
-class Signal {
-public:
-    explicit Signal(Condition::WakeUpType type = Condition::WAKE_UP_ALL)
-            : mType(type), mSignaled(false) {}
-    ~Signal() {}
-
-    void signal() {
-        {
-            Mutex::Autolock l(mLock);
-            mSignaled = true;
-        }
-        mCondition.signal(mType);
-    }
-
-    void wait() {
-        Mutex::Autolock l(mLock);
-        while (!mSignaled) {
-            mCondition.wait(mLock);
-        }
-        mSignaled = false;
-    }
-
-private:
-    Condition::WakeUpType mType;
-    volatile bool mSignaled;
-    mutable Mutex mLock;
-    mutable Condition mCondition;
-};
-
-}  // namespace uirenderer
-}  // namespace android
-
-#endif  // ANDROID_HWUI_SIGNAL_H
diff --git a/libs/hwui/thread/Task.h b/libs/hwui/thread/Task.h
deleted file mode 100644
index 228ce19..0000000
--- a/libs/hwui/thread/Task.h
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * Copyright (C) 2013 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.
- */
-
-#ifndef ANDROID_HWUI_TASK_H
-#define ANDROID_HWUI_TASK_H
-
-#include <utils/RefBase.h>
-#include <utils/Trace.h>
-
-#include "Future.h"
-
-namespace android {
-namespace uirenderer {
-
-class TaskBase : public RefBase {
-public:
-    TaskBase() {}
-    virtual ~TaskBase() {}
-};
-
-template <typename T>
-class Task : public TaskBase {
-public:
-    Task() : mFuture(new Future<T>()) {}
-    virtual ~Task() {}
-
-    T getResult() const { return mFuture->get(); }
-
-    void setResult(T result) { mFuture->produce(result); }
-
-protected:
-    const sp<Future<T> >& future() const { return mFuture; }
-
-private:
-    sp<Future<T> > mFuture;
-};
-
-}  // namespace uirenderer
-}  // namespace android
-
-#endif  // ANDROID_HWUI_TASK_H
diff --git a/libs/hwui/thread/TaskManager.cpp b/libs/hwui/thread/TaskManager.cpp
deleted file mode 100644
index de10ff1..0000000
--- a/libs/hwui/thread/TaskManager.cpp
+++ /dev/null
@@ -1,139 +0,0 @@
-/*
- * Copyright (C) 2013 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 <sys/resource.h>
-#include <sys/sysinfo.h>
-
-#include "Task.h"
-#include "TaskManager.h"
-#include "TaskProcessor.h"
-#include "utils/MathUtils.h"
-#include "renderthread/RenderThread.h"
-
-namespace android {
-namespace uirenderer {
-
-///////////////////////////////////////////////////////////////////////////////
-// Manager
-///////////////////////////////////////////////////////////////////////////////
-
-TaskManager::TaskManager() {
-    // Get the number of available CPUs. This value does not change over time.
-    int cpuCount = sysconf(_SC_NPROCESSORS_CONF);
-
-    // Really no point in making more than 2 of these worker threads, but
-    // we do want to limit ourselves to 1 worker thread on dual-core devices.
-    int workerCount = cpuCount > 2 ? 2 : 1;
-    for (int i = 0; i < workerCount; i++) {
-        String8 name;
-        name.appendFormat("hwuiTask%d", i + 1);
-        mThreads.push_back(new WorkerThread(name));
-    }
-}
-
-TaskManager::~TaskManager() {
-    for (size_t i = 0; i < mThreads.size(); i++) {
-        mThreads[i]->exit();
-    }
-}
-
-bool TaskManager::canRunTasks() const {
-    return mThreads.size() > 0;
-}
-
-void TaskManager::stop() {
-    for (size_t i = 0; i < mThreads.size(); i++) {
-        mThreads[i]->exit();
-    }
-}
-
-bool TaskManager::addTaskBase(const sp<TaskBase>& task, const sp<TaskProcessorBase>& processor) {
-    if (mThreads.size() > 0) {
-        TaskWrapper wrapper(task, processor);
-
-        size_t minQueueSize = INT_MAX;
-        sp<WorkerThread> thread;
-
-        for (size_t i = 0; i < mThreads.size(); i++) {
-            if (mThreads[i]->getTaskCount() < minQueueSize) {
-                thread = mThreads[i];
-                minQueueSize = mThreads[i]->getTaskCount();
-            }
-        }
-
-        return thread->addTask(wrapper);
-    }
-    return false;
-}
-
-///////////////////////////////////////////////////////////////////////////////
-// Thread
-///////////////////////////////////////////////////////////////////////////////
-
-status_t TaskManager::WorkerThread::readyToRun() {
-    setpriority(PRIO_PROCESS, 0, PRIORITY_FOREGROUND);
-    auto onStartHook = renderthread::RenderThread::getOnStartHook();
-    if (onStartHook) {
-        onStartHook(mName.c_str());
-    }
-
-    return NO_ERROR;
-}
-
-bool TaskManager::WorkerThread::threadLoop() {
-    mSignal.wait();
-    std::vector<TaskWrapper> tasks;
-    {
-        Mutex::Autolock l(mLock);
-        tasks.swap(mTasks);
-    }
-
-    for (size_t i = 0; i < tasks.size(); i++) {
-        const TaskWrapper& task = tasks[i];
-        task.mProcessor->process(task.mTask);
-    }
-
-    return true;
-}
-
-bool TaskManager::WorkerThread::addTask(const TaskWrapper& task) {
-    if (!isRunning()) {
-        run(mName.string(), PRIORITY_DEFAULT);
-    } else if (exitPending()) {
-        return false;
-    }
-
-    {
-        Mutex::Autolock l(mLock);
-        mTasks.push_back(task);
-    }
-    mSignal.signal();
-
-    return true;
-}
-
-size_t TaskManager::WorkerThread::getTaskCount() const {
-    Mutex::Autolock l(mLock);
-    return mTasks.size();
-}
-
-void TaskManager::WorkerThread::exit() {
-    requestExit();
-    mSignal.signal();
-}
-
-}  // namespace uirenderer
-}  // namespace android
diff --git a/libs/hwui/thread/TaskManager.h b/libs/hwui/thread/TaskManager.h
deleted file mode 100644
index 6c67222..0000000
--- a/libs/hwui/thread/TaskManager.h
+++ /dev/null
@@ -1,108 +0,0 @@
-/*
- * Copyright (C) 2013 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.
- */
-
-#ifndef ANDROID_HWUI_TASK_MANAGER_H
-#define ANDROID_HWUI_TASK_MANAGER_H
-
-#include <utils/Mutex.h>
-#include <utils/String8.h>
-#include <utils/Thread.h>
-
-#include "Signal.h"
-
-#include <vector>
-
-namespace android {
-namespace uirenderer {
-
-template <typename T>
-class Task;
-class TaskBase;
-
-template <typename T>
-class TaskProcessor;
-class TaskProcessorBase;
-
-class TaskManager {
-public:
-    TaskManager();
-    ~TaskManager();
-
-    /**
-     * Returns true if this task  manager can run tasks,
-     * false otherwise. This method will typically return
-     * false on a single CPU core device.
-     */
-    bool canRunTasks() const;
-
-    /**
-     * Stops all allocated threads. Adding tasks will start
-     * the threads again as necessary.
-     */
-    void stop();
-
-private:
-    template <typename T>
-    friend class TaskProcessor;
-
-    template <typename T>
-    bool addTask(const sp<Task<T> >& task, const sp<TaskProcessor<T> >& processor) {
-        return addTaskBase(sp<TaskBase>(task), sp<TaskProcessorBase>(processor));
-    }
-
-    bool addTaskBase(const sp<TaskBase>& task, const sp<TaskProcessorBase>& processor);
-
-    struct TaskWrapper {
-        TaskWrapper() : mTask(), mProcessor() {}
-
-        TaskWrapper(const sp<TaskBase>& task, const sp<TaskProcessorBase>& processor)
-                : mTask(task), mProcessor(processor) {}
-
-        sp<TaskBase> mTask;
-        sp<TaskProcessorBase> mProcessor;
-    };
-
-    class WorkerThread : public Thread {
-    public:
-        explicit WorkerThread(const String8& name)
-                : Thread(false), mSignal(Condition::WAKE_UP_ONE), mName(name) {}
-
-        bool addTask(const TaskWrapper& task);
-        size_t getTaskCount() const;
-        void exit();
-
-    private:
-        virtual status_t readyToRun() override;
-        virtual bool threadLoop() override;
-
-        // Lock for the list of tasks
-        mutable Mutex mLock;
-        std::vector<TaskWrapper> mTasks;
-
-        // Signal used to wake up the thread when a new
-        // task is available in the list
-        mutable Signal mSignal;
-
-        const String8 mName;
-    };
-
-    std::vector<sp<WorkerThread> > mThreads;
-};
-
-}  // namespace uirenderer
-}  // namespace android
-
-#endif  // ANDROID_HWUI_TASK_MANAGER_H
diff --git a/libs/hwui/thread/TaskProcessor.h b/libs/hwui/thread/TaskProcessor.h
deleted file mode 100644
index 8117ae6..0000000
--- a/libs/hwui/thread/TaskProcessor.h
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * Copyright (C) 2013 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.
- */
-
-#ifndef ANDROID_HWUI_TASK_PROCESSOR_H
-#define ANDROID_HWUI_TASK_PROCESSOR_H
-
-#include <utils/RefBase.h>
-
-#include "Task.h"
-#include "TaskManager.h"
-
-namespace android {
-namespace uirenderer {
-
-class TaskProcessorBase : public RefBase {
-public:
-    TaskProcessorBase() {}
-    virtual ~TaskProcessorBase(){};
-
-    virtual void process(const sp<TaskBase>& task) = 0;
-};
-
-template <typename T>
-class TaskProcessor : public TaskProcessorBase {
-public:
-    explicit TaskProcessor(TaskManager* manager) : mManager(manager) {}
-    virtual ~TaskProcessor() {}
-
-    void add(const sp<Task<T> >& task) {
-        if (!addImpl(task)) {
-            // fall back to immediate execution
-            process(task);
-        }
-    }
-
-    virtual void onProcess(const sp<Task<T> >& task) = 0;
-
-private:
-    bool addImpl(const sp<Task<T> >& task);
-
-    virtual void process(const sp<TaskBase>& task) override {
-        sp<Task<T> > realTask = static_cast<Task<T>*>(task.get());
-        // This is the right way to do it but sp<> doesn't play nice
-        // sp<Task<T> > realTask = static_cast<sp<Task<T> > >(task);
-        onProcess(realTask);
-    }
-
-    TaskManager* mManager;
-};
-
-template <typename T>
-bool TaskProcessor<T>::addImpl(const sp<Task<T> >& task) {
-    if (mManager) {
-        sp<TaskProcessor<T> > self(this);
-        return mManager->addTask(task, self);
-    }
-    return false;
-}
-
-};  // namespace uirenderer
-};  // namespace android
-
-#endif  // ANDROID_HWUI_TASK_PROCESSOR_H
diff --git a/libs/hwui/thread/WorkQueue.h b/libs/hwui/thread/WorkQueue.h
index 7a6e638..42f8503 100644
--- a/libs/hwui/thread/WorkQueue.h
+++ b/libs/hwui/thread/WorkQueue.h
@@ -26,7 +26,6 @@
 #include <functional>
 #include <future>
 #include <mutex>
-#include <variant>
 #include <vector>
 
 namespace android::uirenderer {
diff --git a/location/java/android/location/GnssCapabilities.java b/location/java/android/location/GnssCapabilities.java
new file mode 100644
index 0000000..6a35920
--- /dev/null
+++ b/location/java/android/location/GnssCapabilities.java
@@ -0,0 +1,153 @@
+/*
+ * 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 android.location;
+
+import android.annotation.IntDef;
+import android.annotation.SystemApi;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * A container of supported GNSS chipset capabilities.
+ *
+ * @hide
+ */
+@SystemApi
+public final class GnssCapabilities {
+    /** The GNSS chipset supports low power mode. */
+    public static final int LOW_POWER_MODE                                              = 0;
+
+    /** The GNSS chipset supports blacklisting satellites. */
+    public static final int SATELLITE_BLACKLIST                                         = 1;
+
+    /** The GNSS chipset supports geofencing. */
+    public static final int GEOFENCING                                                  = 2;
+
+    /** The GNSS chipset supports measurements.*/
+    public static final int MEASUREMENTS                                                = 3;
+
+    /** The GNSS chipset supports navigation messages. */
+    public static final int NAV_MESSAGES                                                = 4;
+
+    /** The GNSS chipset supports measurement corrections. */
+    public static final int MEASUREMENT_CORRECTIONS                                     = 5;
+
+    /** The GNSS chipset supports line-of-sight satellite identification measurement corrections. */
+    public static final int MEASUREMENT_CORRECTIONS_LOS_SATS                            = 6;
+
+    /** The GNSS chipset supports per satellite excess-path-length measurement corrections. */
+    public static final int MEASUREMENT_CORRECTIONS_EXCESS_PATH_LENGTH                  = 7;
+
+    /** The GNSS chipset supports reflecting planes measurement corrections. */
+    public static final int MEASUREMENT_CORRECTIONS_REFLECTING_PLANE                    = 8;
+
+    private static final int MIN_CAPABILITY = 0;
+    private static final int MAX_CAPABILITY = MEASUREMENT_CORRECTIONS_REFLECTING_PLANE;
+
+    /**
+     * GNSS capability.
+     * @hide
+     */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef({
+            LOW_POWER_MODE,
+            SATELLITE_BLACKLIST,
+            GEOFENCING,
+            MEASUREMENTS,
+            NAV_MESSAGES,
+            MEASUREMENT_CORRECTIONS,
+            MEASUREMENT_CORRECTIONS_LOS_SATS,
+            MEASUREMENT_CORRECTIONS_EXCESS_PATH_LENGTH,
+            MEASUREMENT_CORRECTIONS_REFLECTING_PLANE
+    })
+    public @interface Capability {}
+
+    /**
+     * @hide
+     */
+    public static final long INVALID_CAPABILITIES = -1;
+
+    /** A bitmask of supported GNSS capabilities. */
+    private final long mGnssCapabilities;
+
+    static GnssCapabilities of(long gnssCapabilities) {
+        return new GnssCapabilities(gnssCapabilities);
+    }
+
+    private GnssCapabilities(long gnssCapabilities) {
+        mGnssCapabilities = gnssCapabilities;
+    }
+
+    /**
+     * Returns {@code true} if the {@code capability} is supported by the GNSS implementation.
+     */
+    public boolean hasCapability(@Capability int capability) {
+        return isValidCapability(capability) && (mGnssCapabilities & (1 << capability)) != 0;
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder sb = new StringBuilder("GnssCapabilities: (");
+        int capability = 0;
+        boolean addSeparator = false;
+        long gnssCapabilities = mGnssCapabilities;
+        while (gnssCapabilities != 0) {
+            if ((gnssCapabilities & 1) != 0) {
+                if (addSeparator) {
+                    sb.append(' ');
+                } else {
+                    addSeparator = true;
+                }
+                sb.append(toStringCapability(capability));
+            }
+            gnssCapabilities >>= 1;
+            ++capability;
+        }
+        sb.append(")");
+        return sb.toString();
+    }
+
+    private boolean isValidCapability(@Capability int capability) {
+        return capability >= MIN_CAPABILITY && capability <= MAX_CAPABILITY;
+    }
+
+    private static String toStringCapability(@Capability int capability) {
+        switch (capability) {
+            case LOW_POWER_MODE:
+                return "LOW_POWER_MODE";
+            case SATELLITE_BLACKLIST:
+                return "SATELLITE_BLACKLIST";
+            case GEOFENCING:
+                return "GEOFENCING";
+            case MEASUREMENTS:
+                return "MEASUREMENTS";
+            case NAV_MESSAGES:
+                return "NAV_MESSAGES";
+            case MEASUREMENT_CORRECTIONS:
+                return "MEASUREMENT_CORRECTIONS";
+            case MEASUREMENT_CORRECTIONS_LOS_SATS:
+                return "MEASUREMENT_CORRECTIONS_LOS_SATS";
+            case MEASUREMENT_CORRECTIONS_EXCESS_PATH_LENGTH:
+                return "MEASUREMENT_CORRECTIONS_EXCESS_PATH_LENGTH";
+            case MEASUREMENT_CORRECTIONS_REFLECTING_PLANE:
+                return "MEASUREMENT_CORRECTIONS_REFLECTING_PLANE";
+            default:
+                return "Unknown(" + capability + ")";
+        }
+    }
+}
diff --git a/location/java/android/location/GnssMeasurementCallbackTransport.java b/location/java/android/location/GnssMeasurementCallbackTransport.java
index 1188b13b..8cb8c0b 100644
--- a/location/java/android/location/GnssMeasurementCallbackTransport.java
+++ b/location/java/android/location/GnssMeasurementCallbackTransport.java
@@ -63,7 +63,7 @@
                 measurementCorrections, getContext().getPackageName());
     }
 
-    protected int getGnssCapabilities() throws RemoteException {
+    protected long getGnssCapabilities() throws RemoteException {
         return mLocationManager.getGnssCapabilities(getContext().getPackageName());
     }
 
diff --git a/location/java/android/location/GnssStatus.java b/location/java/android/location/GnssStatus.java
index 60c7748..ce464b7 100644
--- a/location/java/android/location/GnssStatus.java
+++ b/location/java/android/location/GnssStatus.java
@@ -42,6 +42,8 @@
     public static final int CONSTELLATION_BEIDOU = 5;
     /** Constellation type constant for Galileo. */
     public static final int CONSTELLATION_GALILEO = 6;
+    /** Constellation type constant for IRNSS. */
+    public static final int CONSTELLATION_IRNSS = 7;
 
     /** @hide */
     public static final int GNSS_SV_FLAGS_NONE = 0;
@@ -94,7 +96,7 @@
      */
     @Retention(RetentionPolicy.SOURCE)
     @IntDef({CONSTELLATION_UNKNOWN, CONSTELLATION_GPS, CONSTELLATION_SBAS, CONSTELLATION_GLONASS,
-            CONSTELLATION_QZSS, CONSTELLATION_BEIDOU, CONSTELLATION_GALILEO})
+            CONSTELLATION_QZSS, CONSTELLATION_BEIDOU, CONSTELLATION_GALILEO, CONSTELLATION_IRNSS})
     public @interface ConstellationType {}
 
     final int[] mSvidWithFlags;
diff --git a/location/java/android/location/ILocationManager.aidl b/location/java/android/location/ILocationManager.aidl
index c371c5f..93dc6fa 100644
--- a/location/java/android/location/ILocationManager.aidl
+++ b/location/java/android/location/ILocationManager.aidl
@@ -29,6 +29,7 @@
 import android.location.ILocationListener;
 import android.location.Location;
 import android.location.LocationRequest;
+import android.location.LocationTime;
 import android.os.Bundle;
 
 import com.android.internal.location.ProviderProperties;
@@ -66,7 +67,7 @@
     boolean addGnssMeasurementsListener(in IGnssMeasurementsListener listener, in String packageName);
     void injectGnssMeasurementCorrections(in GnssMeasurementCorrections corrections,
             in String packageName);
-    int getGnssCapabilities(in String packageName);
+    long getGnssCapabilities(in String packageName);
     void removeGnssMeasurementsListener(in IGnssMeasurementsListener listener);
 
     boolean addGnssNavigationMessageListener(
@@ -104,6 +105,7 @@
     void setTestProviderLocation(String provider, in Location loc, String opPackageName);
     void setTestProviderEnabled(String provider, boolean enabled, String opPackageName);
     List<LocationRequest> getTestProviderCurrentRequests(String provider, String opPackageName);
+    LocationTime getGnssTimeMillis();
 
     // --- deprecated ---
     void setTestProviderStatus(String provider, int status, in Bundle extras, long updateTime,
diff --git a/location/java/android/location/LocationManager.java b/location/java/android/location/LocationManager.java
index dd179f3..edf304c 100644
--- a/location/java/android/location/LocationManager.java
+++ b/location/java/android/location/LocationManager.java
@@ -167,11 +167,21 @@
 
     /**
      * Broadcast intent action when the set of enabled location providers changes. To check the
-     * status of a provider, use {@link #isProviderEnabled(String)}.
+     * status of a provider, use {@link #isProviderEnabled(String)}. From Android Q and above, will
+     * include a string intent extra, {@link #EXTRA_PROVIDER_NAME}, with the name of the provider
+     * whose state has changed.
+     *
+     * @see #EXTRA_PROVIDER_NAME
      */
     public static final String PROVIDERS_CHANGED_ACTION = "android.location.PROVIDERS_CHANGED";
 
     /**
+     * Intent extra included with {@link #PROVIDERS_CHANGED_ACTION} broadcasts, containing the name
+     * of the location provider that has changed, to be used with location provider APIs.
+     */
+    public static final String EXTRA_PROVIDER_NAME = "android.location.extra.PROVIDER_NAME";
+
+    /**
      * Broadcast intent action when the device location mode changes. To check the location mode,
      * use {@link #isLocationEnabled()}.
      */
@@ -1976,15 +1986,19 @@
     }
 
     /**
-     * Returns the integer capability flags of the GNSS chipset as defined in {@code
-     * IGnssCallback.hal}
+     * Returns the supported capabilities of the GNSS chipset or {@code null} if there is an error
+     * in obtaining the capabilities.
      *
      * @hide
      */
     @SystemApi
-    public int getGnssCapabilities() {
+    public @Nullable GnssCapabilities getGnssCapabilities() {
         try {
-            return mGnssMeasurementCallbackTransport.getGnssCapabilities();
+            long gnssCapabilities = mGnssMeasurementCallbackTransport.getGnssCapabilities();
+            if (gnssCapabilities == GnssCapabilities.INVALID_CAPABILITIES) {
+                return null;
+            }
+            return GnssCapabilities.of(gnssCapabilities);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
diff --git a/media/java/android/media/session/SessionLink.aidl b/location/java/android/location/LocationTime.aidl
similarity index 76%
rename from media/java/android/media/session/SessionLink.aidl
rename to location/java/android/location/LocationTime.aidl
index c3be23e..f626363 100644
--- a/media/java/android/media/session/SessionLink.aidl
+++ b/location/java/android/location/LocationTime.aidl
@@ -1,11 +1,11 @@
 /*
- * Copyright 2019 The Android Open Source Project
+ * 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
+ *     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,
@@ -14,6 +14,6 @@
  * limitations under the License.
  */
 
-package android.media.session;
+package android.location;
 
-parcelable SessionLink;
+parcelable LocationTime;
diff --git a/location/java/android/location/LocationTime.java b/location/java/android/location/LocationTime.java
new file mode 100644
index 0000000..e5535d1
--- /dev/null
+++ b/location/java/android/location/LocationTime.java
@@ -0,0 +1,73 @@
+/*
+ * 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 android.location;
+
+import android.annotation.NonNull;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * Data class for passing location derived time.
+ * @hide
+ */
+public final class LocationTime implements Parcelable {
+
+    private final long mTime;
+    private final long mElapsedRealtimeNanos;
+
+    public LocationTime(long time, long elapsedRealtimeNanos) {
+        mTime = time;
+        mElapsedRealtimeNanos = elapsedRealtimeNanos;
+    }
+
+    /**
+     * The current time, according to the Gnss location provider. */
+    public long getTime() {
+        return mTime;
+    }
+
+    /**
+     * The elapsed nanos since boot {@link #getTime} was computed at.
+     */
+    public long getElapsedRealtimeNanos() {
+        return mElapsedRealtimeNanos;
+    }
+
+    @Override
+    public void writeToParcel(Parcel out, int flags) {
+        out.writeLong(mTime);
+        out.writeLong(mElapsedRealtimeNanos);
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    public static final @NonNull Parcelable.Creator<LocationTime> CREATOR =
+            new Parcelable.Creator<LocationTime>() {
+                public LocationTime createFromParcel(Parcel in) {
+                    long time = in.readLong();
+                    long elapsedRealtimeNanos = in.readLong();
+                    return new LocationTime(time, elapsedRealtimeNanos);
+                }
+
+                public LocationTime[] newArray(int size) {
+                    return new LocationTime[size];
+                }
+            };
+}
diff --git a/media/apex/java/android/media/CallbackDataSourceDesc.java b/media/apex/java/android/media/CallbackDataSourceDesc.java
index 9209ca9..d9db62e 100644
--- a/media/apex/java/android/media/CallbackDataSourceDesc.java
+++ b/media/apex/java/android/media/CallbackDataSourceDesc.java
@@ -17,7 +17,7 @@
 package android.media;
 
 import android.annotation.NonNull;
-import android.annotation.Nullable;
+import android.annotation.TestApi;
 
 /**
  * Structure of data source descriptor for sources using callback.
@@ -26,12 +26,16 @@
  * {@link MediaPlayer2#setNextDataSources} to set data source for playback.
  *
  * <p>Users should use {@link Builder} to create {@link CallbackDataSourceDesc}.
- *
+ * @hide
  */
+@TestApi
 public class CallbackDataSourceDesc extends DataSourceDesc {
     private DataSourceCallback mDataSourceCallback;
 
-    private CallbackDataSourceDesc() {
+    CallbackDataSourceDesc(String mediaId, long startPositionMs, long endPositionMs,
+            DataSourceCallback dataSourceCallback) {
+        super(mediaId, startPositionMs, endPositionMs);
+        mDataSourceCallback = dataSourceCallback;
     }
 
     /**
@@ -41,75 +45,4 @@
     public @NonNull DataSourceCallback getDataSourceCallback() {
         return mDataSourceCallback;
     }
-
-    /**
-     * Builder class for {@link CallbackDataSourceDesc} objects.
-     * <p> Here is an example where <code>Builder</code> is used to define the
-     * {@link CallbackDataSourceDesc} to be used by a {@link MediaPlayer2} instance:
-     *
-     * <pre class="prettyprint">
-     * CallbackDataSourceDesc newDSD = new CallbackDataSourceDesc.Builder()
-     *         .setDataSource(media2DataSource)
-     *         .setStartPosition(1000)
-     *         .setEndPosition(15000)
-     *         .build();
-     * mediaplayer2.setDataSourceDesc(newDSD);
-     * </pre>
-     */
-    public static class Builder extends BuilderBase<Builder> {
-        private DataSourceCallback mDataSourceCallback;
-
-        /**
-         * Constructs a new Builder with the defaults.
-         */
-        public Builder() {
-            super();
-        }
-
-        /**
-         * Constructs a new Builder from a given {@link CallbackDataSourceDesc} instance
-         * @param dsd the {@link CallbackDataSourceDesc} object whose data will be reused
-         * in the new Builder.
-         */
-        public Builder(@Nullable CallbackDataSourceDesc dsd) {
-            super(dsd);
-            if (dsd == null) {
-                return;  // use default
-            }
-            mDataSourceCallback = dsd.mDataSourceCallback;
-        }
-
-        /**
-         * Combines all of the fields that have been set and return a new
-         * {@link CallbackDataSourceDesc} object. <code>IllegalStateException</code> will be
-         * thrown if there is conflict between fields.
-         *
-         * @return a new {@link CallbackDataSourceDesc} object
-         */
-        public @NonNull CallbackDataSourceDesc build() {
-            if (mDataSourceCallback == null) {
-                throw new IllegalStateException(
-                        "DataSourceCallback should not be null");
-            }
-
-            CallbackDataSourceDesc dsd = new CallbackDataSourceDesc();
-            super.build(dsd);
-            dsd.mDataSourceCallback = mDataSourceCallback;
-
-            return dsd;
-        }
-
-        /**
-         * Sets the data source (DataSourceCallback) to use.
-         *
-         * @param dscb the DataSourceCallback for the media to play
-         * @return the same Builder instance.
-         * @throws NullPointerException if dscb is null.
-         */
-        public @NonNull Builder setDataSource(@NonNull DataSourceCallback dscb) {
-            Media2Utils.checkArgument(dscb != null, "data source cannot be null.");
-            mDataSourceCallback = dscb;
-            return this;
-        }
-    }
 }
diff --git a/media/apex/java/android/media/DataSourceDesc.java b/media/apex/java/android/media/DataSourceDesc.java
index e6fd120..be80c22 100644
--- a/media/apex/java/android/media/DataSourceDesc.java
+++ b/media/apex/java/android/media/DataSourceDesc.java
@@ -18,15 +18,22 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.net.Uri;
+import android.os.ParcelFileDescriptor;
+
+import java.net.CookieHandler;
+import java.net.CookieManager;
+import java.net.HttpCookie;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
 
 /**
- * Base class of data source descriptor.
+ * Data source descriptor.
  *
  * Used by {@link MediaPlayer2#setDataSource}, {@link MediaPlayer2#setNextDataSource} and
  * {@link MediaPlayer2#setNextDataSources} to set data source for playback.
- *
- * <p>Users should use subclasses' builder to change {@link DataSourceDesc}.
- *
  */
 public class DataSourceDesc {
     // intentionally less than long.MAX_VALUE
@@ -45,7 +52,10 @@
     private long mStartPositionMs = 0;
     private long mEndPositionMs = POSITION_UNKNOWN;
 
-    DataSourceDesc() {
+    DataSourceDesc(String mediaId, long startPositionMs, long endPositionMs) {
+        mMediaId = mediaId;
+        mStartPositionMs = startPositionMs;
+        mEndPositionMs = endPositionMs;
     }
 
     /**
@@ -97,17 +107,48 @@
     }
 
     /**
-     * Base class for Builders in the subclasses of {@link DataSourceDesc}.
+     * Builder for {@link DataSourceDesc}.
+     * <p>
+     * Here is an example where <code>Builder</code> is used to define the
+     * {@link DataSourceDesc} to be used by a {@link MediaPlayer2} instance:
+     *
+     * <pre class="prettyprint">
+     * DataSourceDesc newDSD = new DataSourceDesc.Builder()
+     *         .setDataSource(context, uri, headers, cookies)
+     *         .setStartPosition(1000)
+     *         .setEndPosition(15000)
+     *         .build();
+     * mediaplayer2.setDataSourceDesc(newDSD);
+     * </pre>
      */
-    protected static class BuilderBase<T extends BuilderBase> {
+    public static final class Builder {
+        private static final int SOURCE_TYPE_UNKNOWN = 0;
+        private static final int SOURCE_TYPE_URI = 1;
+        private static final int SOURCE_TYPE_FILE = 2;
+        private static final int SOURCE_TYPE_CALLBACK = 3;
+
+        private int mSourceType = SOURCE_TYPE_UNKNOWN;
         private String mMediaId;
         private long mStartPositionMs = 0;
         private long mEndPositionMs = POSITION_UNKNOWN;
 
+        // For UriDataSourceDesc
+        private Uri mUri;
+        private Map<String, String> mHeader;
+        private List<HttpCookie> mCookies;
+
+        // For FileDataSourceDesc
+        private ParcelFileDescriptor mPFD;
+        private long mOffset = 0;
+        private long mLength = FileDataSourceDesc.FD_LENGTH_UNKNOWN;
+
+        // For CallbackDataSourceDesc
+        private DataSourceCallback mDataSourceCallback;
+
         /**
          * Constructs a new BuilderBase with the defaults.
          */
-        BuilderBase() {
+        public Builder() {
         }
 
         /**
@@ -115,33 +156,61 @@
          * @param dsd the {@link DataSourceDesc} object whose data will be reused
          * in the new BuilderBase.
          */
-        BuilderBase(DataSourceDesc dsd) {
+        public Builder(@Nullable DataSourceDesc dsd) {
             if (dsd == null) {
                 return;
             }
             mMediaId = dsd.mMediaId;
             mStartPositionMs = dsd.mStartPositionMs;
             mEndPositionMs = dsd.mEndPositionMs;
+            if (dsd instanceof FileDataSourceDesc) {
+                mSourceType = SOURCE_TYPE_FILE;
+                mPFD = ((FileDataSourceDesc) dsd).getParcelFileDescriptor();
+                mOffset = ((FileDataSourceDesc) dsd).getOffset();
+                mLength = ((FileDataSourceDesc) dsd).getLength();
+            } else if (dsd instanceof UriDataSourceDesc) {
+                mSourceType = SOURCE_TYPE_URI;
+                mUri = ((UriDataSourceDesc) dsd).getUri();
+                mHeader = ((UriDataSourceDesc) dsd).getHeaders();
+                mCookies = ((UriDataSourceDesc) dsd).getCookies();
+            } else if (dsd instanceof CallbackDataSourceDesc) {
+                mSourceType = SOURCE_TYPE_CALLBACK;
+                mDataSourceCallback = ((CallbackDataSourceDesc) dsd).getDataSourceCallback();
+            } else {
+                throw new IllegalStateException("Unknown source type:" + mSourceType);
+            }
         }
 
         /**
          * Sets all fields that have been set in the {@link DataSourceDesc} object.
          * <code>IllegalStateException</code> will be thrown if there is conflict between fields.
          *
-         * @param dsd an instance of subclass of {@link DataSourceDesc} whose data will be set
-         * @return the same instance of subclass of {@link DataSourceDesc}
+         * @return {@link DataSourceDesc}
          */
-        void build(@NonNull DataSourceDesc dsd) {
-            Media2Utils.checkArgument(dsd != null,  "dsd cannot be null.");
-
+        @NonNull
+        public DataSourceDesc build() {
+            if (mSourceType == SOURCE_TYPE_UNKNOWN) {
+                throw new IllegalStateException("Source is not set.");
+            }
             if (mStartPositionMs > mEndPositionMs) {
                 throw new IllegalStateException("Illegal start/end position: "
                     + mStartPositionMs + " : " + mEndPositionMs);
             }
 
-            dsd.mMediaId = mMediaId;
-            dsd.mStartPositionMs = mStartPositionMs;
-            dsd.mEndPositionMs = mEndPositionMs;
+            DataSourceDesc desc;
+            if (mSourceType == SOURCE_TYPE_FILE) {
+                desc = new FileDataSourceDesc(
+                        mMediaId, mStartPositionMs, mEndPositionMs, mPFD, mOffset, mLength);
+            } else if (mSourceType == SOURCE_TYPE_URI) {
+                desc = new UriDataSourceDesc(
+                        mMediaId, mStartPositionMs, mEndPositionMs, mUri, mHeader, mCookies);
+            } else if (mSourceType == SOURCE_TYPE_CALLBACK) {
+                desc = new CallbackDataSourceDesc(
+                        mMediaId, mStartPositionMs, mEndPositionMs, mDataSourceCallback);
+            } else {
+                throw new IllegalStateException("Unknown source type:" + mSourceType);
+            }
+            return desc;
         }
 
         /**
@@ -150,9 +219,10 @@
          * @param mediaId the media Id of this data source
          * @return the same Builder instance.
          */
-        public @NonNull T setMediaId(@Nullable String mediaId) {
+        @NonNull
+        public Builder setMediaId(@Nullable String mediaId) {
             mMediaId = mediaId;
-            return (T) this;
+            return this;
         }
 
         /**
@@ -163,12 +233,13 @@
          * @return the same Builder instance.
          *
          */
-        public @NonNull T setStartPosition(long position) {
+        @NonNull
+        public Builder setStartPosition(long position) {
             if (position < 0) {
                 position = 0;
             }
             mStartPositionMs = position;
-            return (T) this;
+            return this;
         }
 
         /**
@@ -179,12 +250,155 @@
          * @param position the end position in milliseconds at which the playback will end
          * @return the same Builder instance.
          */
-        public @NonNull T setEndPosition(long position) {
+        @NonNull
+        public Builder setEndPosition(long position) {
             if (position < 0) {
                 position = LONG_MAX_TIME_MS;
             }
             mEndPositionMs = position;
-            return (T) this;
+            return this;
+        }
+
+        /**
+         * Sets the data source as a content Uri.
+         *
+         * @param uri the Content URI of the data you want to play
+         * @return the same Builder instance.
+         * @throws NullPointerException if context or uri is null.
+         */
+        @NonNull
+        public Builder setDataSource(@NonNull Uri uri) {
+            setSourceType(SOURCE_TYPE_URI);
+            Media2Utils.checkArgument(uri != null, "uri cannot be null");
+            mUri = uri;
+            return this;
+        }
+
+        /**
+         * Sets the data source as a content Uri.
+         *
+         * To provide cookies for the subsequent HTTP requests, you can install your own default
+         * cookie handler and use other variants of setDataSource APIs instead. Alternatively, you
+         * can use this API to pass the cookies as a list of HttpCookie. If the app has not
+         * installed a CookieHandler already, {@link MediaPlayer2} will create a CookieManager
+         * and populates its CookieStore with the provided cookies when this data source is passed
+         * to {@link MediaPlayer2}. If the app has installed its own handler already, the handler
+         * is required to be of CookieManager type such that {@link MediaPlayer2} can update the
+         * manager’s CookieStore.
+         *
+         *  <p><strong>Note</strong> that the cross domain redirection is allowed by default,
+         * but that can be changed with key/value pairs through the headers parameter with
+         * "android-allow-cross-domain-redirect" as the key and "0" or "1" as the value to
+         * disallow or allow cross domain redirection.
+         *
+         * @param uri the Content URI of the data you want to play
+         * @param headers the headers to be sent together with the request for the data
+         *                The headers must not include cookies. Instead, use the cookies param.
+         * @param cookies the cookies to be sent together with the request
+         * @return the same Builder instance.
+         * @throws NullPointerException if context or uri is null.
+         * @throws IllegalArgumentException if the cookie handler is not of CookieManager type
+         *                                  when cookies are provided.
+         */
+        @NonNull
+        public Builder setDataSource(@NonNull Uri uri, @Nullable Map<String, String> headers,
+                @Nullable List<HttpCookie> cookies) {
+            setSourceType(SOURCE_TYPE_URI);
+            Media2Utils.checkArgument(uri != null, "uri cannot be null");
+            if (cookies != null) {
+                CookieHandler cookieHandler = CookieHandler.getDefault();
+                if (cookieHandler != null && !(cookieHandler instanceof CookieManager)) {
+                    throw new IllegalArgumentException(
+                            "The cookie handler has to be of CookieManager type "
+                                    + "when cookies are provided.");
+                }
+            }
+
+            mUri = uri;
+            if (headers != null) {
+                mHeader = new HashMap<String, String>(headers);
+            }
+            if (cookies != null) {
+                mCookies = new ArrayList<HttpCookie>(cookies);
+            }
+            return this;
+        }
+
+        /**
+         * Sets the data source (ParcelFileDescriptor) to use. The ParcelFileDescriptor must be
+         * seekable (N.B. a LocalSocket is not seekable). When the {@link FileDataSourceDesc}
+         * created by this builder is passed to {@link MediaPlayer2} via
+         * {@link MediaPlayer2#setDataSource},
+         * {@link MediaPlayer2#setNextDataSource} or
+         * {@link MediaPlayer2#setNextDataSources}, MediaPlayer2 will
+         * close the ParcelFileDescriptor.
+         *
+         * @param pfd the ParcelFileDescriptor for the file to play
+         * @return the same Builder instance.
+         * @throws NullPointerException if pfd is null.
+         */
+        @NonNull
+        public Builder setDataSource(@NonNull ParcelFileDescriptor pfd) {
+            setSourceType(SOURCE_TYPE_FILE);
+            Media2Utils.checkArgument(pfd != null, "pfd cannot be null.");
+            mPFD = pfd;
+            return this;
+        }
+
+        /**
+         * Sets the data source (ParcelFileDescriptor) to use. The ParcelFileDescriptor must be
+         * seekable (N.B. a LocalSocket is not seekable). When the {@link FileDataSourceDesc}
+         * created by this builder is passed to {@link MediaPlayer2} via
+         * {@link MediaPlayer2#setDataSource},
+         * {@link MediaPlayer2#setNextDataSource} or
+         * {@link MediaPlayer2#setNextDataSources}, MediaPlayer2 will
+         * close the ParcelFileDescriptor.
+         *
+         * Any negative number for offset is treated as 0.
+         * Any negative number for length is treated as maximum length of the data source.
+         *
+         * @param pfd the ParcelFileDescriptor for the file to play
+         * @param offset the offset into the file where the data to be played starts, in bytes
+         * @param length the length in bytes of the data to be played
+         * @return the same Builder instance.
+         * @throws NullPointerException if pfd is null.
+         */
+        @NonNull
+        public Builder setDataSource(
+                @NonNull ParcelFileDescriptor pfd, long offset, long length) {
+            setSourceType(SOURCE_TYPE_FILE);
+            Media2Utils.checkArgument(pfd != null, "pfd cannot be null.");
+            if (offset < 0) {
+                offset = 0;
+            }
+            if (length < 0) {
+                length = FileDataSourceDesc.FD_LENGTH_UNKNOWN;
+            }
+            mPFD = pfd;
+            mOffset = offset;
+            mLength = length;
+            return this;
+        }
+
+        /**
+         * Sets the data source (DataSourceCallback) to use.
+         *
+         * @param dscb the DataSourceCallback for the media to play
+         * @return the same Builder instance.
+         * @throws NullPointerException if dscb is null.
+         */
+        public @NonNull Builder setDataSource(@NonNull DataSourceCallback dscb) {
+            setSourceType(SOURCE_TYPE_CALLBACK);
+            Media2Utils.checkArgument(dscb != null, "data source cannot be null.");
+            mDataSourceCallback = dscb;
+            return this;
+        }
+
+        private void setSourceType(int type) {
+            if (mSourceType != SOURCE_TYPE_UNKNOWN) {
+                throw new IllegalStateException("Source is already set. type=" + mSourceType);
+            }
+            mSourceType = type;
         }
     }
 }
diff --git a/media/apex/java/android/media/FileDataSourceDesc.java b/media/apex/java/android/media/FileDataSourceDesc.java
index 4b70367..feb67e1 100644
--- a/media/apex/java/android/media/FileDataSourceDesc.java
+++ b/media/apex/java/android/media/FileDataSourceDesc.java
@@ -17,7 +17,7 @@
 package android.media;
 
 import android.annotation.NonNull;
-import android.annotation.Nullable;
+import android.annotation.TestApi;
 import android.os.ParcelFileDescriptor;
 import android.util.Log;
 
@@ -30,8 +30,9 @@
  * {@link MediaPlayer2#setNextDataSources} to set data source for playback.
  *
  * <p>Users should use {@link Builder} to create {@link FileDataSourceDesc}.
- *
+ * @hide
  */
+@TestApi
 public class FileDataSourceDesc extends DataSourceDesc {
     private static final String TAG = "FileDataSourceDesc";
 
@@ -48,8 +49,12 @@
     private int mCount = 0;
     private boolean mClosed = false;
 
-    private FileDataSourceDesc() {
-        super();
+    FileDataSourceDesc(String mediaId, long startPositionMs, long endPositionMs,
+            ParcelFileDescriptor pfd, long offset, long length) {
+        super(mediaId, startPositionMs, endPositionMs);
+        mPFD = pfd;
+        mOffset = offset;
+        mLength = length;
     }
 
     /**
@@ -128,133 +133,4 @@
     public long getLength() {
         return mLength;
     }
-
-    /**
-     * Builder class for {@link FileDataSourceDesc} objects.
-     * <p> Here is an example where <code>Builder</code> is used to define the
-     * {@link FileDataSourceDesc} to be used by a {@link MediaPlayer2} instance:
-     *
-     * <pre class="prettyprint">
-     * FileDataSourceDesc newDSD = new FileDataSourceDesc.Builder()
-     *         .setDataSource(pfd, 0, srcLength)
-     *         .setStartPosition(1000)
-     *         .setEndPosition(15000)
-     *         .build();
-     * mediaplayer2.setDataSourceDesc(newDSD);
-     * </pre>
-     */
-    public static class Builder extends BuilderBase<Builder> {
-        private ParcelFileDescriptor mPFD;
-        private long mOffset = 0;
-        private long mLength = FD_LENGTH_UNKNOWN;
-
-        /**
-         * Constructs a new Builder with the defaults.
-         */
-        public Builder() {
-            super();
-        }
-
-        /**
-         * Constructs a new Builder from a given {@link FileDataSourceDesc} instance
-         * @param dsd the {@link FileDataSourceDesc} object whose data will be reused
-         * in the new Builder.
-         */
-        public Builder(@Nullable FileDataSourceDesc dsd) {
-            super(dsd);
-            if (dsd == null) {
-                return;  // use default
-            }
-            mPFD = dsd.mPFD;
-            mOffset = dsd.mOffset;
-            mLength = dsd.mLength;
-        }
-
-        /**
-         * Combines all of the fields that have been set and return a new
-         * {@link FileDataSourceDesc} object. <code>IllegalStateException</code> will be
-         * thrown if there is conflict between fields.
-         *
-         * @return a new {@link FileDataSourceDesc} object
-         */
-        public @NonNull FileDataSourceDesc build() {
-            if (mPFD == null) {
-                throw new IllegalStateException(
-                        "underline ParcelFileDescriptor should not be null");
-            }
-            try {
-                mPFD.getFd();
-            } catch (IllegalStateException e) {
-                throw new IllegalStateException("ParcelFileDescriptor has been closed");
-            }
-
-            FileDataSourceDesc dsd = new FileDataSourceDesc();
-            super.build(dsd);
-            dsd.mPFD = mPFD;
-            dsd.mOffset = mOffset;
-            dsd.mLength = mLength;
-
-            return dsd;
-        }
-
-        /**
-         * Sets the data source (ParcelFileDescriptor) to use. The ParcelFileDescriptor must be
-         * seekable (N.B. a LocalSocket is not seekable). When the {@link FileDataSourceDesc}
-         * created by this builder is passed to {@link MediaPlayer2} via
-         * {@link MediaPlayer2#setDataSource},
-         * {@link MediaPlayer2#setNextDataSource} or
-         * {@link MediaPlayer2#setNextDataSources}, MediaPlayer2 will
-         * close the ParcelFileDescriptor.
-         *
-         * @param pfd the ParcelFileDescriptor for the file to play
-         * @return the same Builder instance.
-         * @throws NullPointerException if pfd is null.
-         */
-        public @NonNull Builder setDataSource(@NonNull ParcelFileDescriptor pfd) {
-            Media2Utils.checkArgument(pfd != null, "pfd cannot be null.");
-            resetDataSource();
-            mPFD = pfd;
-            return this;
-        }
-
-        /**
-         * Sets the data source (ParcelFileDescriptor) to use. The ParcelFileDescriptor must be
-         * seekable (N.B. a LocalSocket is not seekable). When the {@link FileDataSourceDesc}
-         * created by this builder is passed to {@link MediaPlayer2} via
-         * {@link MediaPlayer2#setDataSource},
-         * {@link MediaPlayer2#setNextDataSource} or
-         * {@link MediaPlayer2#setNextDataSources}, MediaPlayer2 will
-         * close the ParcelFileDescriptor.
-         *
-         * Any negative number for offset is treated as 0.
-         * Any negative number for length is treated as maximum length of the data source.
-         *
-         * @param pfd the ParcelFileDescriptor for the file to play
-         * @param offset the offset into the file where the data to be played starts, in bytes
-         * @param length the length in bytes of the data to be played
-         * @return the same Builder instance.
-         * @throws NullPointerException if pfd is null.
-         */
-        public @NonNull Builder setDataSource(
-                @NonNull ParcelFileDescriptor pfd, long offset, long length) {
-            Media2Utils.checkArgument(pfd != null, "pfd cannot be null.");
-            if (offset < 0) {
-                offset = 0;
-            }
-            if (length < 0) {
-                length = FD_LENGTH_UNKNOWN;
-            }
-            resetDataSource();
-            mPFD = pfd;
-            mOffset = offset;
-            mLength = length;
-            return this;
-        }
-
-        private void resetDataSource() {
-            mPFD = null;
-            mOffset = 0;
-            mLength = FD_LENGTH_UNKNOWN;
-        }
-    }
 }
diff --git a/media/apex/java/android/media/MediaPlayer2.java b/media/apex/java/android/media/MediaPlayer2.java
index 5cd3621..68a46ed 100644
--- a/media/apex/java/android/media/MediaPlayer2.java
+++ b/media/apex/java/android/media/MediaPlayer2.java
@@ -274,8 +274,7 @@
  * successful transition. Any other value will be an error. Call {@link #getState()} to
  * determine the current state. </p>
  */
-public class MediaPlayer2 implements AutoCloseable
-                                            , AudioRouting {
+public class MediaPlayer2 implements AutoCloseable, AudioRouting {
     static {
         System.loadLibrary("media2_jni");
         native_init();
@@ -899,7 +898,7 @@
             UriDataSourceDesc uriDSD = (UriDataSourceDesc) dsd;
             handleDataSource(isCurrent,
                              srcId,
-                             uriDSD.getContext(),
+                             mContext,
                              uriDSD.getUri(),
                              uriDSD.getHeaders(),
                              uriDSD.getCookies(),
@@ -1810,12 +1809,10 @@
     public MediaTimestamp getTimestamp() {
         try {
             // TODO: get the timestamp from native side
-            return new MediaTimestamp.Builder()
-                    .setMediaTimestamp(
-                        getCurrentPosition() * 1000L,
-                        System.nanoTime(),
-                        getState() == PLAYER_STATE_PLAYING ? getPlaybackParams().getSpeed() : 0.f)
-                    .build();
+            return new MediaTimestamp(
+                    getCurrentPosition() * 1000L,
+                    System.nanoTime(),
+                    getState() == PLAYER_STATE_PLAYING ? getPlaybackParams().getSpeed() : 0.f);
         } catch (IllegalStateException e) {
             return null;
         }
@@ -2643,13 +2640,11 @@
                             return;
                         }
                         Iterator<Value> in = playerMsg.getValuesList().iterator();
-                        SubtitleData data = new SubtitleData.Builder()
-                                .setSubtitleData(
-                                    in.next().getInt32Value(),  // trackIndex
-                                    in.next().getInt64Value(),  // startTimeUs
-                                    in.next().getInt64Value(),  // durationUs
-                                    in.next().getBytesValue().toByteArray())  // data
-                                .build();
+                        SubtitleData data = new SubtitleData(
+                                in.next().getInt32Value(),  // trackIndex
+                                in.next().getInt64Value(),  // startTimeUs
+                                in.next().getInt64Value(),  // durationUs
+                                in.next().getBytesValue().toByteArray());  // data
                         sendEvent(new EventNotifier() {
                             @Override
                             public void notify(EventCallback callback) {
@@ -2673,11 +2668,9 @@
                             return;
                         }
                         Iterator<Value> in = playerMsg.getValuesList().iterator();
-                        data = new TimedMetaData.Builder()
-                                .setTimedMetaData(
-                                    in.next().getInt64Value(),  // timestampUs
-                                    in.next().getBytesValue().toByteArray())  // metaData
-                                .build();
+                        data = new TimedMetaData(
+                                in.next().getInt64Value(),  // timestampUs
+                                in.next().getBytesValue().toByteArray());  // metaData
                     } else {
                         data = null;
                     }
@@ -3463,7 +3456,7 @@
              * @param uuid of selected crypto scheme
              * @return this
              */
-            public Builder setUuid(@NonNull UUID uuid) {
+            public @NonNull Builder setUuid(@NonNull UUID uuid) {
                 this.mUUID = uuid;
                 return this;
             }
@@ -3480,7 +3473,7 @@
              * @param keySetId identifier of a persisted offline key
              * @return this
              */
-            public Builder setKeySetId(@Nullable byte[] keySetId) {
+            public @NonNull Builder setKeySetId(@Nullable byte[] keySetId) {
                 this.mKeySetId = keySetId;
                 return this;
             }
@@ -3494,7 +3487,7 @@
              * @param initData container-specific DRM initialization data
              * @return this
              */
-            public Builder setInitData(@Nullable byte[] initData) {
+            public @NonNull Builder setInitData(@Nullable byte[] initData) {
                 this.mInitData = initData;
                 return this;
             }
@@ -3505,7 +3498,7 @@
              * @param mimeType mime type to the content
              * @return this
              */
-            public Builder setMimeType(@Nullable String mimeType) {
+            public @NonNull Builder setMimeType(@Nullable String mimeType) {
                 this.mMimeType = mimeType;
                 return this;
             }
@@ -3519,7 +3512,7 @@
              * @param keyType type of the key request
              * @return this
              */
-            public Builder setKeyType(@MediaPlayer2.MediaDrmKeyType int keyType) {
+            public @NonNull Builder setKeyType(@MediaPlayer2.MediaDrmKeyType int keyType) {
                 this.mKeyType = keyType;
                 return this;
             }
@@ -3531,7 +3524,8 @@
              * @param optionalParameters optional parameters to be included in a key request
              * @return this
              */
-            public Builder setOptionalParameters(@Nullable Map<String, String> optionalParameters) {
+            public @NonNull Builder setOptionalParameters(
+                    @Nullable Map<String, String> optionalParameters) {
                 this.mOptionalParameters = optionalParameters;
                 return this;
             }
@@ -3540,7 +3534,7 @@
              * @return an immutable {@link MediaPlayer2.DrmPreparationInfo} representing the
              *         settings of this builder
              */
-            public MediaPlayer2.DrmPreparationInfo build() {
+            public @NonNull MediaPlayer2.DrmPreparationInfo build() {
                 return new MediaPlayer2.DrmPreparationInfo(mUUID, mKeySetId, mInitData, mMimeType,
                         mKeyType, mOptionalParameters);
             }
@@ -3597,7 +3591,8 @@
          * @return a {@link DrmPreparationInfo} object to initialize DRM playback, or null to skip
          *         DRM initialization
          */
-        public DrmPreparationInfo onDrmInfo(MediaPlayer2 mp, DataSourceDesc dsd, DrmInfo drmInfo) {
+        public @Nullable DrmPreparationInfo onDrmInfo(@NonNull MediaPlayer2 mp,
+                @NonNull DataSourceDesc dsd, @NonNull DrmInfo drmInfo) {
             return null;
         }
 
@@ -3630,11 +3625,13 @@
          * @param request a {@link MediaDrm.KeyRequest} prepared using the
          *        {@link DrmPreparationInfo} returned from
          *        {@link #onDrmInfo(MediaPlayer2, DataSourceDesc, DrmInfo)}
-         * @return the response to {@code request} (from license server)
+         * @return the response to {@code request} (from license server); returning {@code null} or
+         *         throwing an {@link RuntimeException} from this callback would trigger an
+         *         {@link EventCallback#onError}.
          */
-        public byte[] onDrmKeyRequest(@NonNull MediaPlayer2 mp, @NonNull DataSourceDesc dsd,
-                @NonNull MediaDrm.KeyRequest request) {
-            return null;
+        public @NonNull byte[] onDrmKeyRequest(@NonNull MediaPlayer2 mp,
+                @NonNull DataSourceDesc dsd, @NonNull MediaDrm.KeyRequest request) {
+            return new byte[0];
         }
 
         /**
@@ -4144,7 +4141,7 @@
         /**
          * Returns the PSSH info of the data source for each supported DRM scheme.
          */
-        public Map<UUID, byte[]> getPssh() {
+        public @NonNull Map<UUID, byte[]> getPssh() {
             return mMapPssh;
         }
 
@@ -4153,7 +4150,7 @@
          * It effectively identifies the subset of the source's DRM schemes which
          * are supported by the device too.
          */
-        public List<UUID> getSupportedSchemes() {
+        public @NonNull List<UUID> getSupportedSchemes() {
             return Arrays.asList(mSupportedSchemes);
         }
 
@@ -4276,7 +4273,7 @@
      * Extends MediaDrm.MediaDrmException
      */
     public static final class NoDrmSchemeException extends MediaDrmException {
-        public NoDrmSchemeException(String detailMessage) {
+        public NoDrmSchemeException(@Nullable String detailMessage) {
             super(detailMessage);
         }
     }
diff --git a/media/apex/java/android/media/Session2Command.java b/media/apex/java/android/media/Session2Command.java
index 20d6391..6822ea5 100644
--- a/media/apex/java/android/media/Session2Command.java
+++ b/media/apex/java/android/media/Session2Command.java
@@ -32,6 +32,10 @@
  * If {@link #getCommandCode()} is {@link #COMMAND_CODE_CUSTOM}), it's custom command and
  * {@link #getCustomCommand()} shouldn't be {@code null}.
  * <p>
+ * Refer to the
+ * <a href="{@docRoot}reference/androidx/media2/SessionCommand2.html">AndroidX SessionCommand</a>
+ * class for the list of valid commands.
+ * <p>
  * This API is not generally intended for third party application developers.
  * Use the <a href="{@docRoot}jetpack/androidx.html">AndroidX</a>
  * <a href="{@docRoot}reference/androidx/media2/package-summary.html">Media2 Library</a>
diff --git a/media/apex/java/android/media/Session2CommandGroup.java b/media/apex/java/android/media/Session2CommandGroup.java
index 73a59d0..06ae873 100644
--- a/media/apex/java/android/media/Session2CommandGroup.java
+++ b/media/apex/java/android/media/Session2CommandGroup.java
@@ -167,22 +167,6 @@
         }
 
         /**
-         * Adds a predefined command with given {@code commandCode} to this command group.
-         *
-         * @param commandCode A command code to add.
-         *                    Shouldn't be {@link Session2Command#COMMAND_CODE_CUSTOM}.
-         */
-        @NonNull
-        public Builder addCommand(int commandCode) {
-            if (commandCode == COMMAND_CODE_CUSTOM) {
-                throw new IllegalArgumentException(
-                        "Use addCommand(Session2Command) for COMMAND_CODE_CUSTOM.");
-            }
-            mCommands.add(new Session2Command(commandCode));
-            return this;
-        }
-
-        /**
          * Removes a command from this group which matches given {@code command}.
          *
          * @param command A command to find. Shouldn't be {@code null}.
@@ -197,21 +181,6 @@
         }
 
         /**
-         * Removes a command from this group which matches given {@code commandCode}.
-         *
-         * @param commandCode A command code to find.
-         *                    Shouldn't be {@link Session2Command#COMMAND_CODE_CUSTOM}.
-         */
-        @NonNull
-        public Builder removeCommand(int commandCode) {
-            if (commandCode == COMMAND_CODE_CUSTOM) {
-                throw new IllegalArgumentException("commandCode shouldn't be COMMAND_CODE_CUSTOM");
-            }
-            mCommands.remove(new Session2Command(commandCode));
-            return this;
-        }
-
-        /**
          * Builds {@link Session2CommandGroup}.
          *
          * @return a new {@link Session2CommandGroup}.
diff --git a/media/apex/java/android/media/UriDataSourceDesc.java b/media/apex/java/android/media/UriDataSourceDesc.java
index c0b3c82..eaedf1e 100644
--- a/media/apex/java/android/media/UriDataSourceDesc.java
+++ b/media/apex/java/android/media/UriDataSourceDesc.java
@@ -18,11 +18,9 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.content.Context;
+import android.annotation.TestApi;
 import android.net.Uri;
 
-import java.net.CookieHandler;
-import java.net.CookieManager;
 import java.net.HttpCookie;
 import java.util.ArrayList;
 import java.util.HashMap;
@@ -36,15 +34,20 @@
  * {@link MediaPlayer2#setNextDataSources} to set data source for playback.
  *
  * <p>Users should use {@link Builder} to change {@link UriDataSourceDesc}.
- *
+ * @hide
  */
+@TestApi
 public class UriDataSourceDesc extends DataSourceDesc {
     private Uri mUri;
     private Map<String, String> mHeader;
     private List<HttpCookie> mCookies;
-    private Context mContext;
 
-    private UriDataSourceDesc() {
+    UriDataSourceDesc(String mediaId, long startPositionMs, long endPositionMs,
+            Uri uri, Map<String, String> header, List<HttpCookie> cookies) {
+        super(mediaId, startPositionMs, endPositionMs);
+        mUri = uri;
+        mHeader = header;
+        mCookies = cookies;
     }
 
     /**
@@ -76,155 +79,4 @@
         }
         return new ArrayList<HttpCookie>(mCookies);
     }
-
-    /**
-     * Return the Context used for resolving the Uri of this data source.
-     * @return the Context used for resolving the Uri of this data source
-     */
-    public @NonNull Context getContext() {
-        return mContext;
-    }
-
-    /**
-     * Builder class for {@link UriDataSourceDesc} objects.
-     * <p> Here is an example where <code>Builder</code> is used to define the
-     * {@link UriDataSourceDesc} to be used by a {@link MediaPlayer2} instance:
-     *
-     * <pre class="prettyprint">
-     * UriDataSourceDesc newDSD = new UriDataSourceDesc.Builder()
-     *         .setDataSource(context, uri, headers, cookies)
-     *         .setStartPosition(1000)
-     *         .setEndPosition(15000)
-     *         .build();
-     * mediaplayer2.setDataSourceDesc(newDSD);
-     * </pre>
-     */
-    public static class Builder extends BuilderBase<Builder> {
-        private Uri mUri;
-        private Map<String, String> mHeader;
-        private List<HttpCookie> mCookies;
-        private Context mContext;
-
-        /**
-         * Constructs a new Builder with the defaults.
-         */
-        public Builder() {
-            super();
-        }
-
-        /**
-         * Constructs a new Builder from a given {@link UriDataSourceDesc} instance
-         * @param dsd the {@link UriDataSourceDesc} object whose data will be reused
-         * in the new Builder.
-         */
-        public Builder(@Nullable UriDataSourceDesc dsd) {
-            super(dsd);
-            if (dsd == null) {
-                return;  // use default
-            }
-            mUri = dsd.mUri;
-            mHeader = dsd.mHeader;
-            mCookies = dsd.mCookies;
-            mContext = dsd.mContext;
-        }
-
-        /**
-         * Combines all of the fields that have been set and return a new
-         * {@link UriDataSourceDesc} object. <code>IllegalStateException</code> will be
-         * thrown if there is conflict between fields.
-         *
-         * @return a new {@link UriDataSourceDesc} object
-         */
-        public @NonNull UriDataSourceDesc build() {
-            if (mUri == null || mContext == null) {
-                throw new IllegalStateException(
-                        "Uri and Context should not be null");
-            }
-
-            UriDataSourceDesc dsd = new UriDataSourceDesc();
-            super.build(dsd);
-            dsd.mUri = mUri;
-            dsd.mHeader = mHeader;
-            dsd.mCookies = mCookies;
-            dsd.mContext = mContext;
-
-            return dsd;
-        }
-
-        /**
-         * Sets the data source as a content Uri.
-         *
-         * @param context the Context to use when resolving the Uri
-         * @param uri the Content URI of the data you want to play
-         * @return the same Builder instance.
-         * @throws NullPointerException if context or uri is null.
-         */
-        public @NonNull Builder setDataSource(@NonNull Context context, @NonNull Uri uri) {
-            Media2Utils.checkArgument(context != null, "context cannot be null");
-            Media2Utils.checkArgument(uri != null, "uri cannot be null");
-            resetDataSource();
-            mUri = uri;
-            mContext = context;
-            return this;
-        }
-
-        /**
-         * Sets the data source as a content Uri.
-         *
-         * To provide cookies for the subsequent HTTP requests, you can install your own default
-         * cookie handler and use other variants of setDataSource APIs instead. Alternatively, you
-         * can use this API to pass the cookies as a list of HttpCookie. If the app has not
-         * installed a CookieHandler already, {@link MediaPlayer2} will create a CookieManager
-         * and populates its CookieStore with the provided cookies when this data source is passed
-         * to {@link MediaPlayer2}. If the app has installed its own handler already, the handler
-         * is required to be of CookieManager type such that {@link MediaPlayer2} can update the
-         * manager’s CookieStore.
-         *
-         *  <p><strong>Note</strong> that the cross domain redirection is allowed by default,
-         * but that can be changed with key/value pairs through the headers parameter with
-         * "android-allow-cross-domain-redirect" as the key and "0" or "1" as the value to
-         * disallow or allow cross domain redirection.
-         *
-         * @param context the Context to use when resolving the Uri
-         * @param uri the Content URI of the data you want to play
-         * @param headers the headers to be sent together with the request for the data
-         *                The headers must not include cookies. Instead, use the cookies param.
-         * @param cookies the cookies to be sent together with the request
-         * @return the same Builder instance.
-         * @throws NullPointerException if context or uri is null.
-         * @throws IllegalArgumentException if the cookie handler is not of CookieManager type
-         *                                  when cookies are provided.
-         */
-        public @NonNull Builder setDataSource(@NonNull Context context, @NonNull Uri uri,
-                @Nullable Map<String, String> headers, @Nullable List<HttpCookie> cookies) {
-            Media2Utils.checkArgument(context != null, "context cannot be null");
-            Media2Utils.checkArgument(uri != null, "uri cannot be null");
-            if (cookies != null) {
-                CookieHandler cookieHandler = CookieHandler.getDefault();
-                if (cookieHandler != null && !(cookieHandler instanceof CookieManager)) {
-                    throw new IllegalArgumentException(
-                            "The cookie handler has to be of CookieManager type "
-                            + "when cookies are provided.");
-                }
-            }
-
-            resetDataSource();
-            mUri = uri;
-            if (headers != null) {
-                mHeader = new HashMap<String, String>(headers);
-            }
-            if (cookies != null) {
-                mCookies = new ArrayList<HttpCookie>(cookies);
-            }
-            mContext = context;
-            return this;
-        }
-
-        private void resetDataSource() {
-            mUri = null;
-            mHeader = null;
-            mCookies = null;
-            mContext = null;
-        }
-    }
 }
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index 6a595d2..c926529 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -44,6 +44,7 @@
 import android.media.session.MediaSession;
 import android.media.session.MediaSessionLegacyHelper;
 import android.media.session.MediaSessionManager;
+import android.net.Uri;
 import android.os.Binder;
 import android.os.Build;
 import android.os.Handler;
@@ -1820,6 +1821,21 @@
             "android.media.action.MICROPHONE_MUTE_CHANGED";
 
     /**
+     * Broadcast Action: speakerphone state changed.
+     *
+     * You <em>cannot</em> receive this through components declared
+     * in manifests, only by explicitly registering for it with
+     * {@link Context#registerReceiver(BroadcastReceiver, IntentFilter)
+     * Context.registerReceiver()}.
+     *
+     * <p>The intent has no extra values, use {@link #isSpeakerphoneOn} to check whether the
+     * speakerphone functionality is enabled or not.
+     */
+    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+    public static final String ACTION_SPEAKERPHONE_STATE_CHANGED =
+            "android.media.action.SPEAKERPHONE_STATE_CHANGED";
+
+    /**
      * Sets the audio mode.
      * <p>
      * The audio mode encompasses audio routing AND the behavior of
@@ -5426,6 +5442,20 @@
         sAudioAudioVolumeGroupChangedHandler.unregisterListener(callback);
     }
 
+    /**
+     * Return if an asset contains haptic channels or not.
+     * @param uri the {@link Uri} of the asset.
+     * @return true if the assert contains haptic channels.
+     * @hide
+     */
+    public static boolean hasHapticChannels(Uri uri) {
+        try {
+            return getService().hasHapticChannels(uri);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
     //---------------------------------------------------------
     // Inner classes
     //--------------------
diff --git a/media/java/android/media/AudioPlaybackCaptureConfiguration.java b/media/java/android/media/AudioPlaybackCaptureConfiguration.java
index 333cd2d..4aa0b90 100644
--- a/media/java/android/media/AudioPlaybackCaptureConfiguration.java
+++ b/media/java/android/media/AudioPlaybackCaptureConfiguration.java
@@ -17,6 +17,7 @@
 package android.media;
 
 import android.annotation.NonNull;
+import android.media.AudioAttributes.AttributeUsage;
 import android.media.audiopolicy.AudioMix;
 import android.media.audiopolicy.AudioMixingRule;
 import android.media.projection.MediaProjection;
@@ -41,12 +42,9 @@
  * <pre>
  *     MediaProjection mediaProjection;
  *     // Retrieve a audio capable projection from the MediaProjectionManager
- *     AudioAttributes mediaAttr = new AudioAttributes.Builder()
- *         .setUsage(AudioAttributes.USAGE_MEDIA)
- *         .build();
  *     AudioPlaybackCaptureConfiguration config =
  *              new AudioPlaybackCaptureConfiguration.Builder(mediaProjection)
- *         .addMatchingUsage(mediaAttr)
+ *         .addMatchingUsage(AudioAttributes.USAGE_MEDIA)
  *         .build();
  *     AudioRecord record = new AudioRecord.Builder()
  *         .setAudioPlaybackCaptureConfig(config)
@@ -68,6 +66,15 @@
     }
 
     /**
+     * @return the {@code MediaProjection} used to build this object.
+     * @see {@code Builder.Builder}
+     */
+    public @NonNull MediaProjection getMediaProjection() {
+        return mProjection;
+    }
+
+
+    /**
      * Returns a mix that routes audio back into the app while still playing it from the speakers.
      *
      * @param audioFormat The format in which to capture the audio.
@@ -78,9 +85,6 @@
                 .setRouteFlags(AudioMix.ROUTE_FLAG_LOOP_BACK | AudioMix.ROUTE_FLAG_RENDER)
                 .build();
     }
-    MediaProjection getMediaProjection() {
-        return mProjection;
-    }
 
     /** Builder for creating {@link AudioPlaybackCaptureConfiguration} instances. */
     public static final class Builder {
@@ -121,14 +125,13 @@
          * attributes.
          *
          * @throws IllegalStateException if called in conjunction with
-         *     {@link #excludeUsage(AudioAttributes)}.
+         *     {@link #excludeUsage(int)}.
          */
-        public @NonNull Builder addMatchingUsage(@NonNull AudioAttributes audioAttributes) {
-            Preconditions.checkNotNull(audioAttributes);
+        public @NonNull Builder addMatchingUsage(@AttributeUsage int usage) {
             Preconditions.checkState(
                     mUsageMatchType != MATCH_TYPE_EXCLUSIVE, ERROR_MESSAGE_MISMATCHED_RULES);
-            mAudioMixingRuleBuilder
-                    .addRule(audioAttributes, AudioMixingRule.RULE_MATCH_ATTRIBUTE_USAGE);
+            mAudioMixingRuleBuilder.addRule(new AudioAttributes.Builder().setUsage(usage).build(),
+                                            AudioMixingRule.RULE_MATCH_ATTRIBUTE_USAGE);
             mUsageMatchType = MATCH_TYPE_INCLUSIVE;
             return this;
         }
@@ -156,14 +159,15 @@
          * given attributes.
          *
          * @throws IllegalStateException if called in conjunction with
-         *     {@link #addMatchingUsage(AudioAttributes)}.
+         *     {@link #addMatchingUsage(int)}.
          */
-        public @NonNull Builder excludeUsage(@NonNull AudioAttributes audioAttributes) {
-            Preconditions.checkNotNull(audioAttributes);
+        public @NonNull Builder excludeUsage(@AttributeUsage int usage) {
             Preconditions.checkState(
                     mUsageMatchType != MATCH_TYPE_INCLUSIVE, ERROR_MESSAGE_MISMATCHED_RULES);
-            mAudioMixingRuleBuilder.excludeRule(audioAttributes,
-                    AudioMixingRule.RULE_MATCH_ATTRIBUTE_USAGE);
+            mAudioMixingRuleBuilder.excludeRule(new AudioAttributes.Builder()
+                                                    .setUsage(usage)
+                                                    .build(),
+                                                AudioMixingRule.RULE_MATCH_ATTRIBUTE_USAGE);
             mUsageMatchType = MATCH_TYPE_EXCLUSIVE;
             return this;
         }
diff --git a/media/java/android/media/AudioTrack.java b/media/java/android/media/AudioTrack.java
index 09cfa95..41e059b 100644
--- a/media/java/android/media/AudioTrack.java
+++ b/media/java/android/media/AudioTrack.java
@@ -1014,9 +1014,9 @@
      * frame indicates the number of samples per channel, e.g. 100 frames for a stereo compressed
      * stream corresponds to 200 decoded interleaved PCM samples.
      * @param delayInFrames number of frames to be ignored at the beginning of the stream. A value
-     *     of 0 indicates no padding is to be applied.
-     * @param paddingInFrames number of frames to be ignored at the end of the stream. A value of 0
      *     of 0 indicates no delay is to be applied.
+     * @param paddingInFrames number of frames to be ignored at the end of the stream. A value of 0
+     *     of 0 indicates no padding is to be applied.
      */
     public void setOffloadDelayPadding(@IntRange(from = 0) int delayInFrames,
             @IntRange(from = 0) int paddingInFrames) {
diff --git a/media/java/android/media/IAudioService.aidl b/media/java/android/media/IAudioService.aidl
index c29f355..f2366d8 100644
--- a/media/java/android/media/IAudioService.aidl
+++ b/media/java/android/media/IAudioService.aidl
@@ -37,6 +37,7 @@
 import android.media.audiopolicy.AudioVolumeGroups;
 import android.media.audiopolicy.IAudioPolicyCallback;
 import android.media.projection.IMediaProjection;
+import android.net.Uri;
 
 /**
  * {@hide}
@@ -250,6 +251,8 @@
 
     int removeUidDeviceAffinity(in IAudioPolicyCallback pcb, in int uid);
 
+    boolean hasHapticChannels(in Uri uri);
+
     // WARNING: read warning at top of file, new methods that need to be used by native
     // code via IAudioManager.h need to be added to the top section.
 }
diff --git a/media/java/android/media/MediaCodecInfo.java b/media/java/android/media/MediaCodecInfo.java
index 4bc3897..a687c14 100644
--- a/media/java/android/media/MediaCodecInfo.java
+++ b/media/java/android/media/MediaCodecInfo.java
@@ -21,6 +21,7 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.TestApi;
 import android.annotation.UnsupportedAppUsage;
 import android.os.Build;
 import android.util.Log;
@@ -31,6 +32,7 @@
 
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Collections;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
@@ -1332,7 +1334,7 @@
         private Range<Rational> mBlockAspectRatioRange;
         private Range<Long> mBlocksPerSecondRange;
         private Map<Size, Range<Long>> mMeasuredFrameRates;
-        private Vector<PerformancePoint> mPerformancePoints;
+        private List<PerformancePoint> mPerformancePoints;
         private Range<Integer> mFrameRateRange;
 
         private int mBlockWidth;
@@ -1620,45 +1622,136 @@
          * rate.
          */
         public static final class PerformancePoint {
+            private Size mBlockSize; // codec block size in macroblocks
+            private int mWidth; // width in macroblocks
+            private int mHeight; // height in macroblocks
+            private int mMaxFrameRate; // max frames per second
+            private long mMaxMacroBlockRate; // max macro block rate
+
             /**
-             * (Maximum) number of macroblocks in the frame.
+             * Maximum number of macroblocks in the frame.
              *
              * Video frames are conceptually divided into 16-by-16 pixel blocks called macroblocks.
              * Most coding standards operate on these 16-by-16 pixel blocks; thus, codec performance
              * is characterized using such blocks.
+             *
+             * @hide
              */
-            public final int macroBlocks;
+            @TestApi
+            public int getMaxMacroBlocks() {
+                return saturateLongToInt(mWidth * (long)mHeight);
+            }
 
             /**
-             * (Maximum) frame rate in frames per second.
+             * Maximum frame rate in frames per second.
+             *
+             * @hide
              */
-            public final int frameRate;
+            @TestApi
+            public int getMaxFrameRate() {
+                return mMaxFrameRate;
+            }
 
             /**
-             * (Maximum) number of macroblocks processed per second.
+             * Maximum number of macroblocks processed per second.
+             *
+             * @hide
              */
-            public final long macroBlockRate;
+            @TestApi
+            public long getMaxMacroBlockRate() {
+                return mMaxMacroBlockRate;
+            }
 
-            /* package private */
-            PerformancePoint(int width_, int height_, int frameRate_, int maxFrameRate_) {
-                macroBlocks = saturateLongToInt(
-                        ((Math.max(1, (long)width_) + 15) / 16)
-                                * ((Math.max(1, (long)height_) + 15) / 16));
-                frameRate = Math.max(1, frameRate_);
-                macroBlockRate = Math.max(maxFrameRate_, frameRate) * macroBlocks;
+            /** Convert to a debug string */
+            public String toString() {
+                int blockWidth = 16 * mBlockSize.getWidth();
+                int blockHeight = 16 * mBlockSize.getHeight();
+                int origRate = (int)Utils.divUp(mMaxMacroBlockRate, getMaxMacroBlocks());
+                String info = (mWidth * 16) + "x" + (mHeight * 16) + "@" + origRate;
+                if (origRate < mMaxFrameRate) {
+                    info += ", max " + mMaxFrameRate + "fps";
+                }
+                if (blockWidth > 16 || blockHeight > 16) {
+                    info += ", " + blockWidth + "x" + blockHeight + " blocks";
+                }
+                return "PerformancePoint(" + info + ")";
+            }
+
+            /**
+             * Create a detailed performance point with custom max frame rate and macroblock size.
+             *
+             * @param width  frame width in pixels
+             * @param height frame height in pixels
+             * @param frameRate frames per second for frame width and height
+             * @param maxFrameRate maximum frames per second for any frame size
+             * @param blockSize block size for codec implementation. Must be powers of two in both
+             *        width and height.
+             *
+             * @throws IllegalArgumentException if the blockSize dimensions are not powers of two.
+             *
+             * @hide
+             */
+            @TestApi
+            public PerformancePoint(
+                    int width, int height, int frameRate, int maxFrameRate,
+                    @NonNull Size blockSize) {
+                checkPowerOfTwo(blockSize.getWidth(), "block width");
+                checkPowerOfTwo(blockSize.getHeight(), "block height");
+
+                mBlockSize = new Size(Utils.divUp(blockSize.getWidth(), 16),
+                                      Utils.divUp(blockSize.getHeight(), 16));
+                // these are guaranteed not to overflow as we decimate by 16
+                mWidth = (int)(Utils.divUp(Math.max(1L, width),
+                                           Math.max(blockSize.getWidth(), 16))
+                               * mBlockSize.getWidth());
+                mHeight = (int)(Utils.divUp(Math.max(1L, height),
+                                            Math.max(blockSize.getHeight(), 16))
+                                * mBlockSize.getHeight());
+                mMaxFrameRate = Math.max(1, Math.max(frameRate, maxFrameRate));
+                mMaxMacroBlockRate = Math.max(1, frameRate) * getMaxMacroBlocks();
+                Log.i("PP", "Created " + this);
+            }
+
+            /**
+             * Convert a performance point to a larger blocksize.
+             *
+             * @param pp performance point
+             * @param blockSize block size for codec implementation
+             *
+             * @hide
+             */
+            @TestApi
+            public PerformancePoint(@NonNull PerformancePoint pp, @NonNull Size newBlockSize) {
+                this(
+                        pp.mWidth * 16, pp.mHeight * 16,
+                        // guaranteed not to overflow as these were multiplied at construction
+                        (int)Utils.divUp(pp.mMaxMacroBlockRate, pp.getMaxMacroBlocks()),
+                        pp.mMaxFrameRate,
+                        new Size(Math.max(newBlockSize.getWidth(), pp.mBlockSize.getWidth() * 16),
+                                 Math.max(newBlockSize.getHeight(), pp.mBlockSize.getHeight() * 16))
+                );
+                /*
+                // these are guaranteed not to overflow as size * blockSize is decimated by 16
+                width = align(pp.width * pp.blockSize.getWidth(), blockSize.getWidth());
+                height = align(pp.height * pp.blockSize.getHeight(), blockSize.getHeight());
+                frameRate = pp.frameRate;
+                macroBlockRate = align(pp.macroBlockRate, blockSize.getWidth * blockSize.getHeight());
+                */
+                Log.i("PP", " from " + pp + " and " + newBlockSize);
             }
 
             /**
              * Create a performance point for a given frame size and frame rate.
              *
-             * @param width_ width of the frame in pixels
-             * @param height_ height of the frame in pixels
-             * @param frameRate_ frame rate in frames per second
+             * @param width width of the frame in pixels
+             * @param height height of the frame in pixels
+             * @param frameRate frame rate in frames per second
              */
-            public PerformancePoint(int width_, int height_, int frameRate_) {
-                this(width_, height_, frameRate_, frameRate_ /* maxFrameRate */);
+            public PerformancePoint(int width, int height, int frameRate) {
+                this(width, height, frameRate, frameRate /* maxFrameRate */, new Size(16, 16));
             }
 
+            /** Saturates a long value to int */
             private int saturateLongToInt(long value) {
                 if (value < Integer.MIN_VALUE) {
                     return Integer.MIN_VALUE;
@@ -1669,6 +1762,19 @@
                 }
             }
 
+            /* This method may overflow */
+            private int align(int value, int alignment) {
+                return Utils.divUp(value, alignment) * alignment;
+            }
+
+            /** Checks that value is a power of two. */
+            private void checkPowerOfTwo2(int value, @NonNull String description) {
+                if (value == 0 || (value & (value - 1)) != 0) {
+                    throw new IllegalArgumentException(
+                            description + " (" + value + ") must be a power of 2");
+                }
+            }
+
             /**
              * Checks whether the performance point covers a media format.
              *
@@ -1680,7 +1786,7 @@
                 PerformancePoint other = new PerformancePoint(
                         format.getInteger(MediaFormat.KEY_WIDTH, 0),
                         format.getInteger(MediaFormat.KEY_HEIGHT, 0),
-                        // safely convert ceil(double) to int through float case and Math.round
+                        // safely convert ceil(double) to int through float cast and Math.round
                         Math.round((float)(
                                 Math.ceil(format.getNumber(MediaFormat.KEY_FRAME_RATE, 0)
                                         .doubleValue()))));
@@ -1690,7 +1796,7 @@
             /**
              * Checks whether the performance point covers another performance point. Use this
              * method to determine if a performance point advertised by a codec covers the
-             * performance point required. This method can also be used for lose ordering as this
+             * performance point required. This method can also be used for loose ordering as this
              * method is transitive.
              *
              * @param other other performance point considered
@@ -1698,91 +1804,139 @@
              * @return {@code true} if the performance point covers the other.
              */
             public boolean covers(@NonNull PerformancePoint other) {
-                return (macroBlocks >= other.macroBlocks
-                        && frameRate >= other.frameRate
-                        && macroBlockRate >= other.macroBlockRate);
+                // convert performance points to common block size
+                Size commonSize = getCommonBlockSize(other);
+                PerformancePoint aligned = new PerformancePoint(this, commonSize);
+                PerformancePoint otherAligned = new PerformancePoint(other, commonSize);
+
+                return (aligned.getMaxMacroBlocks() >= otherAligned.getMaxMacroBlocks()
+                        && aligned.mMaxFrameRate >= otherAligned.mMaxFrameRate
+                        && aligned.mMaxMacroBlockRate >= otherAligned.mMaxMacroBlockRate);
             }
 
+            private @NonNull Size getCommonBlockSize(@NonNull PerformancePoint other) {
+                return new Size(
+                        Math.max(mBlockSize.getWidth(), other.mBlockSize.getWidth()) * 16,
+                        Math.max(mBlockSize.getHeight(), other.mBlockSize.getHeight()) * 16);
+            }
 
             @Override
             public boolean equals(Object o) {
                 if (o instanceof PerformancePoint) {
+                    // convert performance points to common block size
                     PerformancePoint other = (PerformancePoint)o;
-                    return (macroBlocks == other.macroBlocks
-                            && frameRate == other.frameRate
-                            && macroBlockRate == other.macroBlockRate);
+                    Size commonSize = getCommonBlockSize(other);
+                    PerformancePoint aligned = new PerformancePoint(this, commonSize);
+                    PerformancePoint otherAligned = new PerformancePoint(other, commonSize);
+
+                    return (aligned.getMaxMacroBlocks() == otherAligned.getMaxMacroBlocks()
+                            && aligned.mMaxFrameRate == otherAligned.mMaxFrameRate
+                            && aligned.mMaxMacroBlockRate == otherAligned.mMaxMacroBlockRate);
                 }
                 return false;
             }
 
             /** 480p 24fps */
+            @NonNull
             public static final PerformancePoint SD_24 = new PerformancePoint(720, 480, 24);
             /** 576p 25fps */
+            @NonNull
             public static final PerformancePoint SD_25 = new PerformancePoint(720, 576, 25);
             /** 480p 30fps */
+            @NonNull
             public static final PerformancePoint SD_30 = new PerformancePoint(720, 480, 30);
             /** 480p 48fps */
+            @NonNull
             public static final PerformancePoint SD_48 = new PerformancePoint(720, 480, 48);
             /** 576p 50fps */
+            @NonNull
             public static final PerformancePoint SD_50 = new PerformancePoint(720, 576, 50);
             /** 480p 60fps */
+            @NonNull
             public static final PerformancePoint SD_60 = new PerformancePoint(720, 480, 60);
 
             /** 720p 24fps */
+            @NonNull
             public static final PerformancePoint HD_24 = new PerformancePoint(1280, 720, 24);
             /** 720p 25fps */
+            @NonNull
             public static final PerformancePoint HD_25 = new PerformancePoint(1280, 720, 25);
             /** 720p 30fps */
+            @NonNull
             public static final PerformancePoint HD_30 = new PerformancePoint(1280, 720, 30);
             /** 720p 50fps */
+            @NonNull
             public static final PerformancePoint HD_50 = new PerformancePoint(1280, 720, 50);
             /** 720p 60fps */
+            @NonNull
             public static final PerformancePoint HD_60 = new PerformancePoint(1280, 720, 60);
             /** 720p 100fps */
+            @NonNull
             public static final PerformancePoint HD_100 = new PerformancePoint(1280, 720, 100);
             /** 720p 120fps */
+            @NonNull
             public static final PerformancePoint HD_120 = new PerformancePoint(1280, 720, 120);
             /** 720p 200fps */
+            @NonNull
             public static final PerformancePoint HD_200 = new PerformancePoint(1280, 720, 200);
             /** 720p 240fps */
+            @NonNull
             public static final PerformancePoint HD_240 = new PerformancePoint(1280, 720, 240);
 
             /** 1080p 24fps */
+            @NonNull
             public static final PerformancePoint FHD_24 = new PerformancePoint(1920, 1080, 24);
             /** 1080p 25fps */
+            @NonNull
             public static final PerformancePoint FHD_25 = new PerformancePoint(1920, 1080, 25);
             /** 1080p 30fps */
+            @NonNull
             public static final PerformancePoint FHD_30 = new PerformancePoint(1920, 1080, 30);
             /** 1080p 50fps */
+            @NonNull
             public static final PerformancePoint FHD_50 = new PerformancePoint(1920, 1080, 50);
             /** 1080p 60fps */
+            @NonNull
             public static final PerformancePoint FHD_60 = new PerformancePoint(1920, 1080, 60);
             /** 1080p 100fps */
+            @NonNull
             public static final PerformancePoint FHD_100 = new PerformancePoint(1920, 1080, 100);
             /** 1080p 120fps */
+            @NonNull
             public static final PerformancePoint FHD_120 = new PerformancePoint(1920, 1080, 120);
             /** 1080p 200fps */
+            @NonNull
             public static final PerformancePoint FHD_200 = new PerformancePoint(1920, 1080, 200);
             /** 1080p 240fps */
+            @NonNull
             public static final PerformancePoint FHD_240 = new PerformancePoint(1920, 1080, 240);
 
             /** 2160p 24fps */
+            @NonNull
             public static final PerformancePoint UHD_24 = new PerformancePoint(3840, 2160, 24);
             /** 2160p 25fps */
+            @NonNull
             public static final PerformancePoint UHD_25 = new PerformancePoint(3840, 2160, 25);
             /** 2160p 30fps */
+            @NonNull
             public static final PerformancePoint UHD_30 = new PerformancePoint(3840, 2160, 30);
             /** 2160p 50fps */
+            @NonNull
             public static final PerformancePoint UHD_50 = new PerformancePoint(3840, 2160, 50);
             /** 2160p 60fps */
+            @NonNull
             public static final PerformancePoint UHD_60 = new PerformancePoint(3840, 2160, 60);
             /** 2160p 100fps */
+            @NonNull
             public static final PerformancePoint UHD_100 = new PerformancePoint(3840, 2160, 100);
             /** 2160p 120fps */
+            @NonNull
             public static final PerformancePoint UHD_120 = new PerformancePoint(3840, 2160, 120);
             /** 2160p 200fps */
+            @NonNull
             public static final PerformancePoint UHD_200 = new PerformancePoint(3840, 2160, 200);
             /** 2160p 240fps */
+            @NonNull
             public static final PerformancePoint UHD_240 = new PerformancePoint(3840, 2160, 240);
         }
 
@@ -1803,10 +1957,7 @@
          */
         @Nullable
         public List<PerformancePoint> getSupportedPerformancePoints() {
-            if (mPerformancePoints == null) {
-                return null;
-            }
-            return new ArrayList<PerformancePoint>(mPerformancePoints);
+            return mPerformancePoints;
         }
 
         /**
@@ -1945,7 +2096,7 @@
             mSmallerDimensionUpperLimit = SIZE_RANGE.getUpper();
         }
 
-        private @Nullable Vector<PerformancePoint> getPerformancePoints(Map<String, Object> map) {
+        private @Nullable List<PerformancePoint> getPerformancePoints(Map<String, Object> map) {
             Vector<PerformancePoint> ret = new Vector<>();
             final String prefix = "performance-point-";
             Set<String> keys = map.keySet();
@@ -1959,7 +2110,7 @@
                     // This means that component knowingly did not publish performance points.
                     // This is different from when the component forgot to publish performance
                     // points.
-                    return ret;
+                    return Collections.unmodifiableList(ret);
                 }
                 String[] temp = key.split("-");
                 if (temp.length != 4) {
@@ -1974,23 +2125,32 @@
                 if (range == null || range.getLower() < 0 || range.getUpper() < 0) {
                     continue;
                 }
-                ret.add(new PerformancePoint(
+                PerformancePoint given = new PerformancePoint(
                         size.getWidth(), size.getHeight(), range.getLower().intValue(),
-                        range.getUpper().intValue()));
+                        range.getUpper().intValue(), new Size(mBlockWidth, mBlockHeight));
+                PerformancePoint rotated = new PerformancePoint(
+                        size.getHeight(), size.getWidth(), range.getLower().intValue(),
+                        range.getUpper().intValue(), new Size(mBlockWidth, mBlockHeight));
+                ret.add(given);
+                if (!given.covers(rotated)) {
+                    ret.add(rotated);
+                }
             }
+
             // check if the component specified no performance point indication
             if (ret.size() == 0) {
                 return null;
             }
 
             // sort reversed by area first, then by frame rate
-            ret.sort((a, b) -> -((a.macroBlocks != b.macroBlocks) ?
-                                        (a.macroBlocks < b.macroBlocks ? -1 : 1) :
-                                (a.macroBlockRate != b.macroBlockRate) ?
-                                        (a.macroBlockRate < b.macroBlockRate ? -1 : 1) :
-                                (a.frameRate != b.frameRate) ?
-                                        (a.frameRate < b.frameRate ? -1 : 1) : 0));
-            return ret;
+            ret.sort((a, b) ->
+                     -((a.getMaxMacroBlocks() != b.getMaxMacroBlocks()) ?
+                               (a.getMaxMacroBlocks() < b.getMaxMacroBlocks() ? -1 : 1) :
+                       (a.getMaxMacroBlockRate() != b.getMaxMacroBlockRate()) ?
+                               (a.getMaxMacroBlockRate() < b.getMaxMacroBlockRate() ? -1 : 1) :
+                       (a.getMaxFrameRate() != b.getMaxFrameRate()) ?
+                               (a.getMaxFrameRate() < b.getMaxFrameRate() ? -1 : 1) : 0));
+            return Collections.unmodifiableList(ret);
         }
 
         private Map<Size, Range<Long>> getMeasuredFrameRates(Map<String, Object> map) {
@@ -3223,14 +3383,83 @@
         // These constants were originally in-line with OMX values, but this
         // correspondence is no longer maintained.
 
+        // Profiles and levels for AVC Codec, corresponding to the definitions in
+        // "SERIES H: AUDIOVISUAL AND MULTIMEDIA SYSTEMS,
+        // Infrastructure of audiovisual services – Coding of moving video
+        // Advanced video coding for generic audiovisual services"
+        // found at
+        // https://www.itu.int/rec/T-REC-H.264-201704-I
+
+        /**
+         * AVC Baseline profile.
+         * See definition in
+         * <a href="https://www.itu.int/rec/T-REC-H.264-201704-I">H.264 recommendation</a>,
+         * Annex A.
+         */
         public static final int AVCProfileBaseline = 0x01;
+
+        /**
+         * AVC Main profile.
+         * See definition in
+         * <a href="https://www.itu.int/rec/T-REC-H.264-201704-I">H.264 recommendation</a>,
+         * Annex A.
+         */
         public static final int AVCProfileMain     = 0x02;
+
+        /**
+         * AVC Extended profile.
+         * See definition in
+         * <a href="https://www.itu.int/rec/T-REC-H.264-201704-I">H.264 recommendation</a>,
+         * Annex A.
+         */
         public static final int AVCProfileExtended = 0x04;
+
+        /**
+         * AVC High profile.
+         * See definition in
+         * <a href="https://www.itu.int/rec/T-REC-H.264-201704-I">H.264 recommendation</a>,
+         * Annex A.
+         */
         public static final int AVCProfileHigh     = 0x08;
+
+        /**
+         * AVC High 10 profile.
+         * See definition in
+         * <a href="https://www.itu.int/rec/T-REC-H.264-201704-I">H.264 recommendation</a>,
+         * Annex A.
+         */
         public static final int AVCProfileHigh10   = 0x10;
+
+        /**
+         * AVC High 4:2:2 profile.
+         * See definition in
+         * <a href="https://www.itu.int/rec/T-REC-H.264-201704-I">H.264 recommendation</a>,
+         * Annex A.
+         */
         public static final int AVCProfileHigh422  = 0x20;
+
+        /**
+         * AVC High 4:4:4 profile.
+         * See definition in
+         * <a href="https://www.itu.int/rec/T-REC-H.264-201704-I">H.264 recommendation</a>,
+         * Annex A.
+         */
         public static final int AVCProfileHigh444  = 0x40;
+
+        /**
+         * AVC Constrained Baseline profile.
+         * See definition in
+         * <a href="https://www.itu.int/rec/T-REC-H.264-201704-I">H.264 recommendation</a>,
+         * Annex A.
+         */
         public static final int AVCProfileConstrainedBaseline = 0x10000;
+
+        /**
+         * AVC Constrained High profile.
+         * See definition in
+         * <a href="https://www.itu.int/rec/T-REC-H.264-201704-I">H.264 recommendation</a>,
+         * Annex A.
+         */
         public static final int AVCProfileConstrainedHigh     = 0x80000;
 
         public static final int AVCLevel1       = 0x01;
@@ -3335,14 +3564,29 @@
 
         public static final int VP8ProfileMain = 0x01;
 
+        /** VP9 Profile 0 4:2:0 8-bit */
         public static final int VP9Profile0 = 0x01;
+
+        /** VP9 Profile 1 4:2:2 8-bit */
         public static final int VP9Profile1 = 0x02;
+
+        /** VP9 Profile 2 4:2:0 10-bit */
         public static final int VP9Profile2 = 0x04;
+
+        /** VP9 Profile 3 4:2:2 10-bit */
         public static final int VP9Profile3 = 0x08;
+
         // HDR profiles also support passing HDR metadata
+        /** VP9 Profile 2 4:2:0 10-bit HDR */
         public static final int VP9Profile2HDR = 0x1000;
+
+        /** VP9 Profile 3 4:2:2 10-bit HDR */
         public static final int VP9Profile3HDR = 0x2000;
+
+        /** VP9 Profile 2 4:2:0 10-bit HDR10Plus */
         public static final int VP9Profile2HDR10Plus = 0x4000;
+
+        /** VP9 Profile 3 4:2:2 10-bit HDR10Plus */
         public static final int VP9Profile3HDR10Plus = 0x8000;
 
         public static final int VP9Level1  = 0x1;
@@ -3420,9 +3664,34 @@
         public static final int DolbyVisionLevelUhd48   = 0x80;
         public static final int DolbyVisionLevelUhd60   = 0x100;
 
-        public static final int AV1Profile0     = 0x1;
-        public static final int AV1Profile1     = 0x2;
-        public static final int AV1Profile2     = 0x4;
+        // Profiles and levels for AV1 Codec, corresponding to the definitions in
+        // "AV1 Bitstream & Decoding Process Specification", Annex A
+        // found at https://aomedia.org/av1-bitstream-and-decoding-process-specification/
+
+        /**
+         * AV1 Main profile 4:2:0 8-bit
+         *
+         * See definition in
+         * <a href="https://aomedia.org/av1-bitstream-and-decoding-process-specification/">AV1 Specification</a>
+         * Annex A.
+         */
+        public static final int AV1ProfileMain8   = 0x1;
+
+        /**
+         * AV1 Main profile 4:2:0 10-bit
+         *
+         * See definition in
+         * <a href="https://aomedia.org/av1-bitstream-and-decoding-process-specification/">AV1 Specification</a>
+         * Annex A.
+         */
+        public static final int AV1ProfileMain10  = 0x2;
+
+
+        /** AV1 Main profile 4:2:0 10-bit with HDR10. */
+        public static final int AV1ProfileMain10HDR10 = 0x1000;
+
+        /** AV1 Main profile 4:2:0 10-bit with HDR10Plus. */
+        public static final int AV1ProfileMain10HDR10Plus = 0x2000;
 
         public static final int AV1Level2       = 0x1;
         public static final int AV1Level21      = 0x2;
diff --git a/media/java/android/media/MediaFormat.java b/media/java/android/media/MediaFormat.java
index 12e02e7..a22c8d0 100644
--- a/media/java/android/media/MediaFormat.java
+++ b/media/java/android/media/MediaFormat.java
@@ -413,7 +413,18 @@
     */
     public static final String KEY_INTRA_REFRESH_PERIOD = "intra-refresh-period";
 
-   /**
+    /**
+     * An optional key describing whether encoders prepend headers to sync frames (e.g.
+     * SPS and PPS to IDR frames for H.264). This is an optional parameter that applies only
+     * to video encoders. A video encoder may not support this feature; check the output
+     * format to verify that this feature was enabled.
+     *
+     * The value is an integer, with 1 indicating to prepend headers to every sync frames,
+     * or 0 otherwise. The default value is 0.
+     */
+    public static final String KEY_PREPEND_HEADER_TO_SYNC_FRAMES = "prepend-sps-pps-to-idr-frames";
+
+    /**
      * A key describing the temporal layering schema.  This is an optional parameter
      * that applies only to video encoders.  Use {@link MediaCodec#getOutputFormat}
      * after {@link MediaCodec#configure configure} to query if the encoder supports
@@ -863,6 +874,12 @@
      */
     public static final String KEY_IS_FORCED_SUBTITLE = "is-forced-subtitle";
 
+    /**
+     * A key describing the number of haptic channels in an audio format.
+     * The associated value is an integer.
+     */
+    public static final String KEY_HAPTIC_CHANNEL_COUNT = "haptic-channel-count";
+
     /** @hide */
     public static final String KEY_IS_TIMED_TEXT = "is-timed-text";
 
@@ -1036,6 +1053,15 @@
      */
     public static final String KEY_CA_PRIVATE_DATA = "ca-private-data";
 
+    /**
+     * A key describing the maximum number of B frames between I or P frames,
+     * to be used by a video encoder.
+     * The associated value is an integer. The default value is 0, which means
+     * that no B frames are allowed. Note that non-zero value does not guarantee
+     * B frames; it's up to the encoder to decide.
+     */
+    public static final String KEY_MAX_BFRAMES = "max-bframes";
+
     /* package private */ MediaFormat(@NonNull Map<String, Object> map) {
         mMap = map;
     }
diff --git a/media/java/android/media/MediaHTTPConnection.java b/media/java/android/media/MediaHTTPConnection.java
index d724762..3838a999 100644
--- a/media/java/android/media/MediaHTTPConnection.java
+++ b/media/java/android/media/MediaHTTPConnection.java
@@ -37,6 +37,7 @@
 import java.net.UnknownServiceException;
 import java.util.HashMap;
 import java.util.Map;
+import java.util.concurrent.atomic.AtomicReference;
 
 /** @hide */
 public class MediaHTTPConnection extends IMediaHTTPConnection.Stub {
@@ -46,27 +47,23 @@
     // connection timeout - 30 sec
     private static final int CONNECT_TIMEOUT_MS = 30 * 1000;
 
-    @UnsupportedAppUsage
-    private long mCurrentOffset = -1;
-    @UnsupportedAppUsage
-    private URL mURL = null;
-    @UnsupportedAppUsage
-    private Map<String, String> mHeaders = null;
-    @UnsupportedAppUsage
-    private HttpURLConnection mConnection = null;
-    @UnsupportedAppUsage
-    private long mTotalSize = -1;
-    private InputStream mInputStream = null;
-
-    @UnsupportedAppUsage
-    private boolean mAllowCrossDomainRedirect = true;
-    @UnsupportedAppUsage
-    private boolean mAllowCrossProtocolRedirect = true;
-
     // from com.squareup.okhttp.internal.http
     private final static int HTTP_TEMP_REDIRECT = 307;
     private final static int MAX_REDIRECTS = 20;
 
+    class ConnectionState {
+        public HttpURLConnection mConnection = null;
+        public InputStream mInputStream = null;
+        public long mCurrentOffset = -1;
+        public Map<String, String> mHeaders = null;
+        public URL mURL = null;
+        public long mTotalSize = -1;
+        public boolean mAllowCrossDomainRedirect = true;
+        public boolean mAllowCrossProtocolRedirect = true;
+    }
+    private final AtomicReference<ConnectionState> mConnectionStateHolder =
+            new AtomicReference<ConnectionState>();
+
     @UnsupportedAppUsage
     public MediaHTTPConnection() {
         CookieHandler cookieHandler = CookieHandler.getDefault();
@@ -84,13 +81,23 @@
             Log.d(TAG, "connect: uri=" + uri + ", headers=" + headers);
         }
 
+        ConnectionState connectionState = mConnectionStateHolder.get();
+        synchronized (this) {
+            if (connectionState == null) {
+                connectionState = new ConnectionState();
+                mConnectionStateHolder.set(connectionState);
+            }
+        }
+
         try {
             disconnect();
-            mAllowCrossDomainRedirect = true;
-            mURL = new URL(uri);
-            mHeaders = convertHeaderStringToMap(headers);
+            connectionState.mAllowCrossDomainRedirect = true;
+            connectionState.mURL = new URL(uri);
+            connectionState.mHeaders = convertHeaderStringToMap(headers, connectionState);
         } catch (MalformedURLException e) {
             return null;
+        } finally {
+            mConnectionStateHolder.set(connectionState);
         }
 
         return native_getIMemory();
@@ -106,18 +113,21 @@
     }
 
     /* returns true iff header is internal */
-    private boolean filterOutInternalHeaders(String key, String val) {
+    private boolean filterOutInternalHeaders(
+            String key, String val, ConnectionState connectionState) {
         if ("android-allow-cross-domain-redirect".equalsIgnoreCase(key)) {
-            mAllowCrossDomainRedirect = parseBoolean(val);
+            connectionState.mAllowCrossDomainRedirect = parseBoolean(val);
             // cross-protocol redirects are also controlled by this flag
-            mAllowCrossProtocolRedirect = mAllowCrossDomainRedirect;
+            connectionState.mAllowCrossProtocolRedirect =
+                    connectionState.mAllowCrossDomainRedirect;
         } else {
             return false;
         }
         return true;
     }
 
-    private Map<String, String> convertHeaderStringToMap(String headers) {
+    private Map<String, String> convertHeaderStringToMap(String headers,
+            ConnectionState connectionState) {
         HashMap<String, String> map = new HashMap<String, String>();
 
         String[] pairs = headers.split("\r\n");
@@ -127,7 +137,7 @@
                 String key = pair.substring(0, colonPos);
                 String val = pair.substring(colonPos + 1);
 
-                if (!filterOutInternalHeaders(key, val)) {
+                if (!filterOutInternalHeaders(key, val, connectionState)) {
                     map.put(key, val);
                 }
             }
@@ -139,25 +149,28 @@
     @Override
     @UnsupportedAppUsage
     public void disconnect() {
-        teardownConnection();
-        mHeaders = null;
-        mURL = null;
+        ConnectionState connectionState = mConnectionStateHolder.getAndSet(null);
+        if (connectionState != null) {
+            teardownConnection(connectionState);
+            connectionState.mHeaders = null;
+            connectionState.mURL = null;
+        }
     }
 
-    private void teardownConnection() {
-        if (mConnection != null) {
-            if (mInputStream != null) {
+    private void teardownConnection(ConnectionState connectionState) {
+        if (connectionState.mConnection != null) {
+            if (connectionState.mInputStream != null) {
                 try {
-                    mInputStream.close();
+                    connectionState.mInputStream.close();
                 } catch (IOException e) {
                 }
-                mInputStream = null;
+                connectionState.mInputStream = null;
             }
 
-            mConnection.disconnect();
-            mConnection = null;
+            connectionState.mConnection.disconnect();
+            connectionState.mConnection = null;
 
-            mCurrentOffset = -1;
+            connectionState.mCurrentOffset = -1;
         }
     }
 
@@ -184,42 +197,44 @@
         return false;
     }
 
-    private void seekTo(long offset) throws IOException {
-        teardownConnection();
+    private void seekTo(long offset, ConnectionState connectionState) throws IOException {
+        teardownConnection(connectionState);
 
         try {
             int response;
             int redirectCount = 0;
 
-            URL url = mURL;
+            URL url = connectionState.mURL;
 
             // do not use any proxy for localhost (127.0.0.1)
             boolean noProxy = isLocalHost(url);
 
             while (true) {
                 if (noProxy) {
-                    mConnection = (HttpURLConnection)url.openConnection(Proxy.NO_PROXY);
+                    connectionState.mConnection =
+                            (HttpURLConnection) url.openConnection(Proxy.NO_PROXY);
                 } else {
-                    mConnection = (HttpURLConnection)url.openConnection();
+                    connectionState.mConnection = (HttpURLConnection) url.openConnection();
                 }
-                mConnection.setConnectTimeout(CONNECT_TIMEOUT_MS);
+                connectionState.mConnection.setConnectTimeout(CONNECT_TIMEOUT_MS);
 
                 // handle redirects ourselves if we do not allow cross-domain redirect
-                mConnection.setInstanceFollowRedirects(mAllowCrossDomainRedirect);
+                connectionState.mConnection.setInstanceFollowRedirects(
+                        connectionState.mAllowCrossDomainRedirect);
 
-                if (mHeaders != null) {
-                    for (Map.Entry<String, String> entry : mHeaders.entrySet()) {
-                        mConnection.setRequestProperty(
+                if (connectionState.mHeaders != null) {
+                    for (Map.Entry<String, String> entry : connectionState.mHeaders.entrySet()) {
+                        connectionState.mConnection.setRequestProperty(
                                 entry.getKey(), entry.getValue());
                     }
                 }
 
                 if (offset > 0) {
-                    mConnection.setRequestProperty(
+                    connectionState.mConnection.setRequestProperty(
                             "Range", "bytes=" + offset + "-");
                 }
 
-                response = mConnection.getResponseCode();
+                response = connectionState.mConnection.getResponseCode();
                 if (response != HttpURLConnection.HTTP_MULT_CHOICE &&
                         response != HttpURLConnection.HTTP_MOVED_PERM &&
                         response != HttpURLConnection.HTTP_MOVED_TEMP &&
@@ -233,7 +248,7 @@
                     throw new NoRouteToHostException("Too many redirects: " + redirectCount);
                 }
 
-                String method = mConnection.getRequestMethod();
+                String method = connectionState.mConnection.getRequestMethod();
                 if (response == HTTP_TEMP_REDIRECT &&
                         !method.equals("GET") && !method.equals("HEAD")) {
                     // "If the 307 status code is received in response to a
@@ -241,34 +256,35 @@
                     // automatically redirect the request"
                     throw new NoRouteToHostException("Invalid redirect");
                 }
-                String location = mConnection.getHeaderField("Location");
+                String location = connectionState.mConnection.getHeaderField("Location");
                 if (location == null) {
                     throw new NoRouteToHostException("Invalid redirect");
                 }
-                url = new URL(mURL /* TRICKY: don't use url! */, location);
+                url = new URL(connectionState.mURL /* TRICKY: don't use url! */, location);
                 if (!url.getProtocol().equals("https") &&
                         !url.getProtocol().equals("http")) {
                     throw new NoRouteToHostException("Unsupported protocol redirect");
                 }
-                boolean sameProtocol = mURL.getProtocol().equals(url.getProtocol());
-                if (!mAllowCrossProtocolRedirect && !sameProtocol) {
+                boolean sameProtocol =
+                        connectionState.mURL.getProtocol().equals(url.getProtocol());
+                if (!connectionState.mAllowCrossProtocolRedirect && !sameProtocol) {
                     throw new NoRouteToHostException("Cross-protocol redirects are disallowed");
                 }
-                boolean sameHost = mURL.getHost().equals(url.getHost());
-                if (!mAllowCrossDomainRedirect && !sameHost) {
+                boolean sameHost = connectionState.mURL.getHost().equals(url.getHost());
+                if (!connectionState.mAllowCrossDomainRedirect && !sameHost) {
                     throw new NoRouteToHostException("Cross-domain redirects are disallowed");
                 }
 
                 if (response != HTTP_TEMP_REDIRECT) {
                     // update effective URL, unless it is a Temporary Redirect
-                    mURL = url;
+                    connectionState.mURL = url;
                 }
             }
 
-            if (mAllowCrossDomainRedirect) {
+            if (connectionState.mAllowCrossDomainRedirect) {
                 // remember the current, potentially redirected URL if redirects
                 // were handled by HttpURLConnection
-                mURL = mConnection.getURL();
+                connectionState.mURL = connectionState.mConnection.getURL();
             }
 
             if (response == HttpURLConnection.HTTP_PARTIAL) {
@@ -276,10 +292,9 @@
                 // because what we want is not just the length of the range
                 // returned but the size of the full content if available.
 
-                String contentRange =
-                    mConnection.getHeaderField("Content-Range");
+                String contentRange = connectionState.mConnection.getHeaderField("Content-Range");
 
-                mTotalSize = -1;
+                connectionState.mTotalSize = -1;
                 if (contentRange != null) {
                     // format is "bytes xxx-yyy/zzz
                     // where "zzz" is the total number of bytes of the
@@ -291,7 +306,7 @@
                             contentRange.substring(lastSlashPos + 1);
 
                         try {
-                            mTotalSize = Long.parseLong(total);
+                            connectionState.mTotalSize = Long.parseLong(total);
                         } catch (NumberFormatException e) {
                         }
                     }
@@ -299,7 +314,7 @@
             } else if (response != HttpURLConnection.HTTP_OK) {
                 throw new IOException();
             } else {
-                mTotalSize = mConnection.getContentLength();
+                connectionState.mTotalSize = connectionState.mConnection.getContentLength();
             }
 
             if (offset > 0 && response != HttpURLConnection.HTTP_PARTIAL) {
@@ -308,14 +323,14 @@
                 throw new ProtocolException();
             }
 
-            mInputStream =
-                new BufferedInputStream(mConnection.getInputStream());
+            connectionState.mInputStream =
+                new BufferedInputStream(connectionState.mConnection.getInputStream());
 
-            mCurrentOffset = offset;
+            connectionState.mCurrentOffset = offset;
         } catch (IOException e) {
-            mTotalSize = -1;
-            teardownConnection();
-            mCurrentOffset = -1;
+            connectionState.mTotalSize = -1;
+            teardownConnection(connectionState);
+            connectionState.mCurrentOffset = -1;
 
             throw e;
         }
@@ -324,10 +339,14 @@
     @Override
     @UnsupportedAppUsage
     public int readAt(long offset, int size) {
-        return native_readAt(offset, size);
+        ConnectionState connectionState = mConnectionStateHolder.get();
+        if (connectionState != null) {
+            return native_readAt(offset, size, connectionState);
+        }
+        return -1;
     }
 
-    private int readAt(long offset, byte[] data, int size) {
+    private int readAt(long offset, byte[] data, int size, ConnectionState connectionState) {
         StrictMode.ThreadPolicy policy =
             new StrictMode.ThreadPolicy.Builder().permitAll().build();
 
@@ -335,12 +354,12 @@
 
         try {
             synchronized(this) {
-                if (offset != mCurrentOffset) {
-                    seekTo(offset);
+                if (offset != connectionState.mCurrentOffset) {
+                    seekTo(offset, connectionState);
                 }
             }
 
-            int n = mInputStream.read(data, 0, size);
+            int n = connectionState.mInputStream.read(data, 0, size);
 
             if (n == -1) {
                 // InputStream signals EOS using a -1 result, our semantics
@@ -348,7 +367,7 @@
                 n = 0;
             }
 
-            mCurrentOffset += n;
+            connectionState.mCurrentOffset += n;
 
             if (VERBOSE) {
                 Log.d(TAG, "readAt " + offset + " / " + size + " => " + n);
@@ -380,35 +399,47 @@
 
     @Override
     public synchronized long getSize() {
-        if (mConnection == null) {
-            try {
-                seekTo(0);
-            } catch (IOException e) {
-                return -1;
+        ConnectionState connectionState = mConnectionStateHolder.get();
+        if (connectionState != null) {
+            if (connectionState.mConnection == null) {
+                try {
+                    seekTo(0, connectionState);
+                } catch (IOException e) {
+                    return -1;
+                }
             }
+            return connectionState.mTotalSize;
         }
 
-        return mTotalSize;
+        return -1;
     }
 
     @Override
     @UnsupportedAppUsage
     public synchronized String getMIMEType() {
-        if (mConnection == null) {
-            try {
-                seekTo(0);
-            } catch (IOException e) {
-                return "application/octet-stream";
+        ConnectionState connectionState = mConnectionStateHolder.get();
+        if (connectionState != null) {
+            if (connectionState.mConnection == null) {
+                try {
+                    seekTo(0, connectionState);
+                } catch (IOException e) {
+                    return "application/octet-stream";
+                }
             }
+            return connectionState.mConnection.getContentType();
         }
 
-        return mConnection.getContentType();
+        return null;
     }
 
     @Override
     @UnsupportedAppUsage
     public String getUri() {
-        return mURL.toString();
+        ConnectionState connectionState = mConnectionStateHolder.get();
+        if (connectionState != null) {
+            return connectionState.mURL.toString();
+        }
+        return null;
     }
 
     @Override
@@ -421,7 +452,7 @@
     private native final void native_finalize();
 
     private native final IBinder native_getIMemory();
-    private native final int native_readAt(long offset, int size);
+    private native int native_readAt(long offset, int size, ConnectionState connectionState);
 
     static {
         System.loadLibrary("media_jni");
diff --git a/media/java/android/media/MediaTimestamp.java b/media/java/android/media/MediaTimestamp.java
index da3362a..0777ba3 100644
--- a/media/java/android/media/MediaTimestamp.java
+++ b/media/java/android/media/MediaTimestamp.java
@@ -16,8 +16,7 @@
 
 package android.media;
 
-import android.annotation.NonNull;
-import android.annotation.SystemApi;
+import android.annotation.FloatRange;
 
 /**
  * An immutable object that represents the linear correlation between the media time
@@ -76,6 +75,7 @@
      * greater than 1.0 if media clock is faster than the system clock;
      * less than 1.0 if media clock is slower than the system clock.
      */
+    @FloatRange(from = 0.0f, to = Float.MAX_VALUE)
     public float getMediaClockRate() {
         return clockRate;
     }
@@ -87,11 +87,19 @@
     /** @hide - accessor shorthand */
     public final float clockRate;
 
-    /** @hide */
-    MediaTimestamp(long mediaUs, long systemNs, float rate) {
-        mediaTimeUs = mediaUs;
-        nanoTime = systemNs;
-        clockRate = rate;
+    /**
+     * Constructor.
+     *
+     * @param mediaTimeUs the media time of the anchor in microseconds
+     * @param nanoTimeNs the {@link java.lang.System#nanoTime system time} corresponding to the
+     *                  media time in nanoseconds.
+     * @param clockRate the rate of the media clock in relation to the system time.
+     */
+    public MediaTimestamp(long mediaTimeUs, long nanoTimeNs,
+            @FloatRange(from = 0.0f, to = Float.MAX_VALUE) float clockRate) {
+        this.mediaTimeUs = mediaTimeUs;
+        this.nanoTime = nanoTimeNs;
+        this.clockRate = clockRate;
     }
 
     /** @hide */
@@ -120,71 +128,4 @@
                 + " clockRate=" + clockRate
                 + "}";
     }
-
-    /**
-     * Builder class for {@link MediaTimestamp} objects.
-     * <p> Here is an example where <code>Builder</code> is used to define the
-     * {@link MediaTimestamp}:
-     *
-     * <pre class="prettyprint">
-     * MediaTimestamp mts = new MediaTimestamp.Builder()
-     *         .setMediaTimestamp(mediaTime, systemTime, rate)
-     *         .build();
-     * </pre>
-     * @hide
-     */
-    @SystemApi
-    public static final class Builder {
-        long mMediaTimeUs;
-        long mNanoTime;
-        float mClockRate = 1.0f;
-
-        /**
-         * Constructs a new Builder with the defaults.
-         */
-        public Builder() {
-        }
-
-        /**
-         * Constructs a new Builder from a given {@link MediaTimestamp} instance
-         * @param mts the {@link MediaTimestamp} object whose data will be reused
-         * in the new Builder.
-         */
-        public Builder(@NonNull MediaTimestamp mts) {
-            if (mts == null) {
-                throw new IllegalArgumentException("null MediaTimestamp is not allowed");
-            }
-            mMediaTimeUs = mts.mediaTimeUs;
-            mNanoTime = mts.nanoTime;
-            mClockRate = mts.clockRate;
-        }
-
-        /**
-         * Combines all of the fields that have been set and return a new
-         * {@link MediaTimestamp} object.
-         *
-         * @return a new {@link MediaTimestamp} object
-         */
-        public @NonNull MediaTimestamp build() {
-            return new MediaTimestamp(mMediaTimeUs, mNanoTime, mClockRate);
-        }
-
-        /**
-         * Sets the info of media timestamp.
-         *
-         * @param mediaTimeUs the media time of the anchor in microseconds
-         * @param nanoTime the {@link java.lang.System#nanoTime system time} corresponding to
-         *     the media time in nanoseconds.
-         * @param clockRate the rate of the media clock in relation to the system time.
-         * @return the same Builder instance.
-         */
-        public @NonNull Builder setMediaTimestamp(
-                long mediaTimeUs, long nanoTime, float clockRate) {
-            mMediaTimeUs = mediaTimeUs;
-            mNanoTime = nanoTime;
-            mClockRate = clockRate;
-
-            return this;
-        }
-    }
 }
diff --git a/media/java/android/media/RingtoneManager.java b/media/java/android/media/RingtoneManager.java
index 9a60923..e0e657b 100644
--- a/media/java/android/media/RingtoneManager.java
+++ b/media/java/android/media/RingtoneManager.java
@@ -1098,6 +1098,28 @@
     }
 
     /**
+     * Returns if the {@link Ringtone} at the given position in the
+     * {@link Cursor} contains haptic channels.
+     *
+     * @param position The position (in the {@link Cursor}) of the ringtone.
+     * @return true if the ringtone contains haptic channels.
+     */
+    public boolean hasHapticChannels(int position) {
+        return hasHapticChannels(getRingtoneUri(position));
+    }
+
+    /**
+     * Returns if the {@link Ringtone} from a given sound URI contains
+     * haptic channels or not.
+     *
+     * @param ringtoneUri The {@link Uri} of a sound or ringtone.
+     * @return true if the ringtone contains haptic channels.
+     */
+    public static boolean hasHapticChannels(@NonNull Uri ringtoneUri) {
+        return AudioManager.hasHapticChannels(ringtoneUri);
+    }
+
+    /**
      * Creates a {@link android.media.MediaScannerConnection} to scan a ringtone file and add its
      * information to the internal database.
      *
diff --git a/media/java/android/media/SubtitleData.java b/media/java/android/media/SubtitleData.java
index 2c6c61f..2ef6982 100644
--- a/media/java/android/media/SubtitleData.java
+++ b/media/java/android/media/SubtitleData.java
@@ -17,11 +17,8 @@
 package android.media;
 
 import android.annotation.NonNull;
-import android.annotation.SystemApi;
 import android.os.Parcel;
 
-import java.util.Arrays;
-
 /**
  * Class encapsulating subtitle data, as received through the
  * {@link MediaPlayer.OnSubtitleDataListener} interface.
@@ -82,12 +79,23 @@
         }
     }
 
-    /** @hide */
+    /**
+     * Constructor.
+     *
+     * @param trackIndex the index of the media player track which contains this subtitle data.
+     * @param startTimeUs the start time in microsecond for the subtitle data
+     * @param durationUs the duration in microsecond for the subtitle data
+     * @param data the data array for the subtitle data. It should not be null.
+     *            No data copying is made.
+     */
     public SubtitleData(int trackIndex, long startTimeUs, long durationUs, @NonNull byte[] data) {
+        if (data == null) {
+            throw new IllegalArgumentException("null data is not allowed");
+        }
         mTrackIndex = trackIndex;
         mStartTimeUs = startTimeUs;
         mDurationUs = durationUs;
-        mData = (data != null ? data : new byte[0]);
+        mData = data;
     }
 
     /**
@@ -141,80 +149,4 @@
 
         return true;
     }
-
-    /**
-     * Builder class for {@link SubtitleData} objects.
-     * <p> Here is an example where <code>Builder</code> is used to define the
-     * {@link SubtitleData}:
-     *
-     * <pre class="prettyprint">
-     * SubtitleData sd = new SubtitleData.Builder()
-     *         .setSubtitleData(trackIndex, startTime, duration, data)
-     *         .build();
-     * </pre>
-     * @hide
-     */
-    @SystemApi
-    public static final class Builder {
-        private int mTrackIndex;
-        private long mStartTimeUs;
-        private long mDurationUs;
-        private byte[] mData = new byte[0];
-
-        /**
-         * Constructs a new Builder with the defaults.
-         */
-        public Builder() {
-        }
-
-        /**
-         * Constructs a new Builder from a given {@link SubtitleData} instance
-         * @param sd the {@link SubtitleData} object whose data will be reused
-         * in the new Builder. It should not be null. The data array is copied.
-         */
-        public Builder(@NonNull SubtitleData sd) {
-            if (sd == null) {
-                throw new IllegalArgumentException("null SubtitleData is not allowed");
-            }
-            mTrackIndex = sd.mTrackIndex;
-            mStartTimeUs = sd.mStartTimeUs;
-            mDurationUs = sd.mDurationUs;
-            if (sd.mData != null) {
-                mData = Arrays.copyOf(sd.mData, sd.mData.length);
-            }
-        }
-
-        /**
-         * Combines all of the fields that have been set and return a new
-         * {@link SubtitleData} object. <code>IllegalStateException</code> will be
-         * thrown if there is conflict between fields.
-         *
-         * @return a new {@link SubtitleData} object
-         */
-        public @NonNull SubtitleData build() {
-            return new SubtitleData(mTrackIndex, mStartTimeUs, mDurationUs, mData);
-        }
-
-        /**
-         * Sets the info of subtitle data.
-         *
-         * @param trackIndex the index of the media player track which contains this subtitle data.
-         * @param startTimeUs the start time in microsecond for the subtile data
-         * @param durationUs the duration in microsecond for the subtile data
-         * @param data the data array for the subtile data. It should not be null.
-         *     No data copying is made.
-         * @return the same Builder instance.
-         */
-        public @NonNull Builder setSubtitleData(
-                int trackIndex, long startTimeUs, long durationUs, @NonNull byte[] data) {
-            if (data == null) {
-                throw new IllegalArgumentException("null data is not allowed");
-            }
-            mTrackIndex = trackIndex;
-            mStartTimeUs = startTimeUs;
-            mDurationUs = durationUs;
-            mData = data;
-            return this;
-        }
-    }
 }
diff --git a/media/java/android/media/TimedMetaData.java b/media/java/android/media/TimedMetaData.java
index 990760c..b99b30c 100644
--- a/media/java/android/media/TimedMetaData.java
+++ b/media/java/android/media/TimedMetaData.java
@@ -17,11 +17,8 @@
 package android.media;
 
 import android.annotation.NonNull;
-import android.annotation.SystemApi;
 import android.os.Parcel;
 
-import java.util.Arrays;
-
 /**
  * Class that embodies one timed metadata access unit, including
  *
@@ -52,7 +49,11 @@
     }
 
     /**
-     * @hide
+     * Constructor.
+     *
+     * @param timestampUs the timestamp in microsecond for the timed metadata
+     * @param metaData the metadata array for the timed metadata. No data copying is made.
+     *     It should not be null.
      */
     public TimedMetaData(long timestampUs, @NonNull byte[] metaData) {
         if (metaData == null) {
@@ -90,71 +91,4 @@
 
         return true;
     }
-
-    /**
-     * Builder class for {@link TimedMetaData} objects.
-     * <p> Here is an example where <code>Builder</code> is used to define the
-     * {@link TimedMetaData}:
-     *
-     * <pre class="prettyprint">
-     * TimedMetaData tmd = new TimedMetaData.Builder()
-     *         .setTimedMetaData(timestamp, metaData)
-     *         .build();
-     * </pre>
-     * @hide
-     */
-    @SystemApi
-    public static final class Builder {
-        private long mTimestampUs;
-        private byte[] mMetaData = new byte[0];
-
-        /**
-         * Constructs a new Builder with the defaults.
-         */
-        public Builder() {
-        }
-
-        /**
-         * Constructs a new Builder from a given {@link TimedMetaData} instance
-         * @param tmd the {@link TimedMetaData} object whose data will be reused
-         * in the new Builder. It should not be null. The metadata array is copied.
-         */
-        public Builder(@NonNull TimedMetaData tmd) {
-            if (tmd == null) {
-                throw new IllegalArgumentException("null TimedMetaData is not allowed");
-            }
-            mTimestampUs = tmd.mTimestampUs;
-            if (tmd.mMetaData != null) {
-                mMetaData = Arrays.copyOf(tmd.mMetaData, tmd.mMetaData.length);
-            }
-        }
-
-        /**
-         * Combines all of the fields that have been set and return a new
-         * {@link TimedMetaData} object. <code>IllegalStateException</code> will be
-         * thrown if there is conflict between fields.
-         *
-         * @return a new {@link TimedMetaData} object
-         */
-        public @NonNull TimedMetaData build() {
-            return new TimedMetaData(mTimestampUs, mMetaData);
-        }
-
-        /**
-         * Sets the info of timed metadata.
-         *
-         * @param timestamp the timestamp in microsecond for the timed metadata
-         * @param metaData the metadata array for the timed metadata. No data copying is made.
-         *     It should not be null.
-         * @return the same Builder instance.
-         */
-        public @NonNull Builder setTimedMetaData(long timestamp, @NonNull byte[] metaData) {
-            if (metaData == null) {
-                throw new IllegalArgumentException("null metaData is not allowed");
-            }
-            mTimestampUs = timestamp;
-            mMetaData = metaData;
-            return this;
-        }
-    }
 }
diff --git a/media/java/android/media/audiopolicy/AudioMixingRule.java b/media/java/android/media/audiopolicy/AudioMixingRule.java
index 6c48cdb..d41f416 100644
--- a/media/java/android/media/audiopolicy/AudioMixingRule.java
+++ b/media/java/android/media/audiopolicy/AudioMixingRule.java
@@ -409,6 +409,10 @@
                 final int match_rule = rule & ~RULE_EXCLUSION_MASK;
                 while (crIterator.hasNext()) {
                     final AudioMixMatchCriterion criterion = crIterator.next();
+
+                    if ((criterion.mRule & ~RULE_EXCLUSION_MASK) != match_rule) {
+                        continue; // The two rules are not of the same type
+                    }
                     switch (match_rule) {
                         case RULE_MATCH_ATTRIBUTE_USAGE:
                             // "usage"-based rule
diff --git a/media/java/android/media/session/ISessionManager.aidl b/media/java/android/media/session/ISessionManager.aidl
index cfcc294..02348476 100644
--- a/media/java/android/media/session/ISessionManager.aidl
+++ b/media/java/android/media/session/ISessionManager.aidl
@@ -22,10 +22,10 @@
 import android.media.session.ICallback;
 import android.media.session.IOnMediaKeyListener;
 import android.media.session.IOnVolumeKeyLongPressListener;
+import android.media.session.ISession;
 import android.media.session.ISession2TokensListener;
 import android.media.session.MediaSession;
 import android.media.session.SessionCallbackLink;
-import android.media.session.SessionLink;
 import android.os.Bundle;
 import android.view.KeyEvent;
 
@@ -34,7 +34,7 @@
  * @hide
  */
 interface ISessionManager {
-    SessionLink createSession(String packageName, in SessionCallbackLink sessionCb, String tag,
+    ISession createSession(String packageName, in SessionCallbackLink sessionCb, String tag,
             in Bundle sessionInfo, int userId);
     void notifySession2Created(in Session2Token sessionToken);
     List<MediaSession.Token> getSessions(in ComponentName compName, int userId);
diff --git a/media/java/android/media/session/MediaSession.java b/media/java/android/media/session/MediaSession.java
index 4fc436c..cbc6c9d 100644
--- a/media/java/android/media/session/MediaSession.java
+++ b/media/java/android/media/session/MediaSession.java
@@ -36,6 +36,7 @@
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.os.Process;
+import android.os.RemoteException;
 import android.os.ResultReceiver;
 import android.service.media.MediaBrowserService;
 import android.text.TextUtils;
@@ -163,11 +164,11 @@
                 .getSystemService(Context.MEDIA_SESSION_SERVICE);
         try {
             SessionCallbackLink cbLink = new SessionCallbackLink(context);
-            SessionLink sessionLink = manager.createSession(cbLink, tag, sessionInfo);
-            mImpl = new MediaSessionEngine(context, sessionLink, cbLink);
+            ISession binder = manager.createSession(cbLink, tag, sessionInfo);
+            mImpl = new MediaSessionEngine(context, binder, cbLink);
             mMaxBitmapSize = context.getResources().getDimensionPixelSize(
                     com.android.internal.R.dimen.config_mediaMetadataBitmapMaxSize);
-        } catch (RuntimeException e) {
+        } catch (RemoteException e) {
             throw new RuntimeException("Remote error creating session.", e);
         }
     }
diff --git a/media/java/android/media/session/MediaSessionEngine.java b/media/java/android/media/session/MediaSessionEngine.java
index 266bf32..7c5243a 100644
--- a/media/java/android/media/session/MediaSessionEngine.java
+++ b/media/java/android/media/session/MediaSessionEngine.java
@@ -25,6 +25,7 @@
 import android.media.AudioAttributes;
 import android.media.MediaDescription;
 import android.media.MediaMetadata;
+import android.media.MediaParceledListSlice;
 import android.media.Rating;
 import android.media.VolumeProvider;
 import android.media.session.MediaSessionManager.RemoteUserInfo;
@@ -34,6 +35,7 @@
 import android.os.Looper;
 import android.os.Message;
 import android.os.Parcel;
+import android.os.RemoteException;
 import android.os.ResultReceiver;
 import android.service.media.MediaBrowserService;
 import android.text.TextUtils;
@@ -55,7 +57,7 @@
 
     private final MediaSession.Token mSessionToken;
     private final MediaController mController;
-    private final SessionLink mSessionLink;
+    private final ISession mBinder;
 
     private CallbackMessageHandler mCallbackHandler;
     private VolumeProvider mVolumeProvider;
@@ -70,14 +72,14 @@
      * finished with the session.
      *
      * @param context The context to use to create the session.
-     * @param sessionLink A session link for the binder of MediaSessionRecord
+     * @param binder A session binder
      */
-    public MediaSessionEngine(@NonNull Context context, @NonNull SessionLink sessionLink,
-            @NonNull SessionCallbackLink cbLink) {
-        mSessionLink = sessionLink;
+    public MediaSessionEngine(@NonNull Context context, @NonNull ISession binder,
+            @NonNull SessionCallbackLink cbLink) throws RemoteException {
+        mBinder = binder;
 
         cbLink.setSessionEngine(this);
-        mSessionToken = new MediaSession.Token(mSessionLink.getController());
+        mSessionToken = new MediaSession.Token(mBinder.getController());
         mController = new MediaController(context, mSessionToken);
     }
 
@@ -134,8 +136,8 @@
      */
     public void setSessionActivity(@Nullable PendingIntent pi) {
         try {
-            mSessionLink.setLaunchPendingIntent(pi);
-        } catch (RuntimeException e) {
+            mBinder.setLaunchPendingIntent(pi);
+        } catch (RemoteException e) {
             Log.wtf(TAG, "Failure in setLaunchPendingIntent.", e);
         }
     }
@@ -150,8 +152,8 @@
      */
     public void setMediaButtonReceiver(@Nullable PendingIntent mbr) {
         try {
-            mSessionLink.setMediaButtonReceiver(mbr);
-        } catch (RuntimeException e) {
+            mBinder.setMediaButtonReceiver(mbr);
+        } catch (RemoteException e) {
             Log.wtf(TAG, "Failure in setMediaButtonReceiver.", e);
         }
     }
@@ -163,8 +165,8 @@
      */
     public void setFlags(int flags) {
         try {
-            mSessionLink.setFlags(flags);
-        } catch (RuntimeException e) {
+            mBinder.setFlags(flags);
+        } catch (RemoteException e) {
             Log.wtf(TAG, "Failure in setFlags.", e);
         }
     }
@@ -185,8 +187,8 @@
             throw new IllegalArgumentException("Attributes cannot be null for local playback.");
         }
         try {
-            mSessionLink.setPlaybackToLocal(attributes);
-        } catch (RuntimeException e) {
+            mBinder.setPlaybackToLocal(attributes);
+        } catch (RemoteException e) {
             Log.wtf(TAG, "Failure in setPlaybackToLocal.", e);
         }
     }
@@ -217,10 +219,10 @@
         });
 
         try {
-            mSessionLink.setPlaybackToRemote(volumeProvider.getVolumeControl(),
+            mBinder.setPlaybackToRemote(volumeProvider.getVolumeControl(),
                     volumeProvider.getMaxVolume());
-            mSessionLink.setCurrentVolume(volumeProvider.getCurrentVolume());
-        } catch (RuntimeException e) {
+            mBinder.setCurrentVolume(volumeProvider.getCurrentVolume());
+        } catch (RemoteException e) {
             Log.wtf(TAG, "Failure in setPlaybackToRemote.", e);
         }
     }
@@ -238,9 +240,9 @@
             return;
         }
         try {
-            mSessionLink.setActive(active);
+            mBinder.setActive(active);
             mActive = active;
-        } catch (RuntimeException e) {
+        } catch (RemoteException e) {
             Log.wtf(TAG, "Failure in setActive.", e);
         }
     }
@@ -267,8 +269,8 @@
             throw new IllegalArgumentException("event cannot be null or empty");
         }
         try {
-            mSessionLink.sendEvent(event, extras);
-        } catch (RuntimeException e) {
+            mBinder.sendEvent(event, extras);
+        } catch (RemoteException e) {
             Log.wtf(TAG, "Error sending event", e);
         }
     }
@@ -280,8 +282,8 @@
      */
     public void close() {
         try {
-            mSessionLink.destroySession();
-        } catch (RuntimeException e) {
+            mBinder.destroySession();
+        } catch (RemoteException e) {
             Log.wtf(TAG, "Error releasing session: ", e);
         }
     }
@@ -316,8 +318,8 @@
     public void setPlaybackState(@Nullable PlaybackState state) {
         mPlaybackState = state;
         try {
-            mSessionLink.setPlaybackState(state);
-        } catch (RuntimeException e) {
+            mBinder.setPlaybackState(state);
+        } catch (RemoteException e) {
             Log.wtf(TAG, "Dead object in setPlaybackState.", e);
         }
     }
@@ -344,8 +346,8 @@
         String metadataDescription = "size=" + fields + ", description=" + description;
 
         try {
-            mSessionLink.setMetadata(metadata, duration, metadataDescription);
-        } catch (RuntimeException e) {
+            mBinder.setMetadata(metadata, duration, metadataDescription);
+        } catch (RemoteException e) {
             Log.wtf(TAG, "Dead object in setPlaybackState.", e);
         }
     }
@@ -363,8 +365,8 @@
      */
     public void setQueue(@Nullable List<MediaSession.QueueItem> queue) {
         try {
-            mSessionLink.setQueue(queue);
-        } catch (RuntimeException e) {
+            mBinder.setQueue(queue == null ? null : new MediaParceledListSlice(queue));
+        } catch (RemoteException e) {
             Log.wtf("Dead object in setQueue.", e);
         }
     }
@@ -378,8 +380,8 @@
      */
     public void setQueueTitle(@Nullable CharSequence title) {
         try {
-            mSessionLink.setQueueTitle(title);
-        } catch (RuntimeException e) {
+            mBinder.setQueueTitle(title);
+        } catch (RemoteException e) {
             Log.wtf("Dead object in setQueueTitle.", e);
         }
     }
@@ -399,8 +401,8 @@
      */
     public void setRatingType(int type) {
         try {
-            mSessionLink.setRatingType(type);
-        } catch (RuntimeException e) {
+            mBinder.setRatingType(type);
+        } catch (RemoteException e) {
             Log.e(TAG, "Error in setRatingType.", e);
         }
     }
@@ -414,8 +416,8 @@
      */
     public void setExtras(@Nullable Bundle extras) {
         try {
-            mSessionLink.setExtras(extras);
-        } catch (RuntimeException e) {
+            mBinder.setExtras(extras);
+        } catch (RemoteException e) {
             Log.wtf("Dead object in setExtras.", e);
         }
     }
@@ -464,8 +466,8 @@
             }
         }
         try {
-            mSessionLink.setCurrentVolume(provider.getCurrentVolume());
-        } catch (RuntimeException e) {
+            mBinder.setCurrentVolume(provider.getCurrentVolume());
+        } catch (RemoteException e) {
             Log.e(TAG, "Error in notifyVolumeChanged", e);
         }
     }
diff --git a/media/java/android/media/session/MediaSessionManager.java b/media/java/android/media/session/MediaSessionManager.java
index f530442..7ca5c93 100644
--- a/media/java/android/media/session/MediaSessionManager.java
+++ b/media/java/android/media/session/MediaSessionManager.java
@@ -107,7 +107,7 @@
      * @hide
      */
     @NonNull
-    public SessionLink createSession(@NonNull SessionCallbackLink cbStub, @NonNull String tag,
+    public ISession createSession(@NonNull SessionCallbackLink cbStub, @NonNull String tag,
             @Nullable Bundle sessionInfo) {
         try {
             return mService.createSession(mContext.getPackageName(), cbStub, tag, sessionInfo,
diff --git a/media/java/android/media/session/SessionLink.java b/media/java/android/media/session/SessionLink.java
deleted file mode 100644
index a47c262..0000000
--- a/media/java/android/media/session/SessionLink.java
+++ /dev/null
@@ -1,450 +0,0 @@
-/*
- * Copyright 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 android.media.session;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.app.PendingIntent;
-import android.media.AudioAttributes;
-import android.media.MediaMetadata;
-import android.media.MediaParceledListSlice;
-import android.media.session.MediaSession.QueueItem;
-import android.os.Bundle;
-import android.os.IBinder;
-import android.os.Parcel;
-import android.os.Parcelable;
-import android.os.RemoteException;
-
-import java.util.List;
-
-/**
- * Handles incoming commands from {@link MediaSession}.
- * @hide
- */
-public final class SessionLink implements Parcelable {
-    public static final @android.annotation.NonNull Parcelable.Creator<SessionLink> CREATOR =
-            new Parcelable.Creator<SessionLink>() {
-                @Override
-                public SessionLink createFromParcel(Parcel in) {
-                    return new SessionLink(in.readStrongBinder());
-                }
-
-                @Override
-                public SessionLink[] newArray(int size) {
-                    return new SessionLink[size];
-                }
-            };
-
-    final SessionStub mSessionStub;
-    final ISession mISession;
-
-    /**
-     * Constructor for stub (Callee)
-     */
-    public SessionLink(@NonNull SessionStub sessionStub) {
-        mSessionStub = sessionStub;
-        mISession = new StubProxy();
-    }
-
-    /**
-     * Constructor for interface (Caller)
-     */
-    public SessionLink(IBinder binder) {
-        mSessionStub = null;
-        mISession = ISession.Stub.asInterface(binder);
-    }
-
-    /**
-     * Tell system that the session sends an event to all the connected controllers.
-     *
-     * @param event the name of the event
-     * @param extras the extras included with the event
-     */
-    void sendEvent(@NonNull String event, @Nullable Bundle extras) {
-        try {
-            mISession.sendEvent(event, extras);
-        } catch (RemoteException e) {
-            throw new RuntimeException(e);
-        }
-    }
-
-    /**
-     * Gets the controller binder from the system.
-     */
-    @NonNull
-    ISessionController getController() {
-        try {
-            return mISession.getController();
-        } catch (RemoteException e) {
-            throw new RuntimeException(e);
-        }
-    }
-
-    /**
-     * Tell system that the session sets the flags.
-     *
-     * @param flags the new session flags
-     */
-    void setFlags(int flags) {
-        try {
-            mISession.setFlags(flags);
-        } catch (RemoteException e) {
-            throw new RuntimeException(e);
-        }
-    }
-
-    /**
-     * Tell system that the session is (in)active.
-     *
-     * @param active the new activeness state
-     */
-    void setActive(boolean active) {
-        try {
-            mISession.setActive(active);
-        } catch (RemoteException e) {
-            throw new RuntimeException(e);
-        }
-    }
-
-    /**
-     * Tell system that the session sets the media button receiver.
-     *
-     * @param mbr the pending intent for media button receiver
-     */
-    void setMediaButtonReceiver(@Nullable PendingIntent mbr) {
-        try {
-            mISession.setMediaButtonReceiver(mbr);
-        } catch (RemoteException e) {
-            throw new RuntimeException(e);
-        }
-    }
-
-    /**
-     * Tell system that the session sets the pending intent for launching UI.
-     *
-     * @param pi the pending intent for launching UI
-     */
-    void setLaunchPendingIntent(@Nullable PendingIntent pi) {
-        try {
-            mISession.setLaunchPendingIntent(pi);
-        } catch (RemoteException e) {
-            throw new RuntimeException(e);
-        }
-    }
-
-    /**
-     * Tell system that the session is destroyed.
-     */
-    void destroySession() {
-        try {
-            mISession.destroySession();
-        } catch (RemoteException e) {
-            throw new RuntimeException(e);
-        }
-    }
-
-    /**
-     * Tell system that the session sets the new metadata.
-     *
-     * @param metadata the new metadata
-     * @param duration the duration of the media in milliseconds
-     * @param metadataDescription the description of the metadata
-     */
-    void setMetadata(@Nullable MediaMetadata metadata, long duration,
-            @Nullable String metadataDescription) {
-        try {
-            mISession.setMetadata(metadata, duration, metadataDescription);
-        } catch (RemoteException e) {
-            throw new RuntimeException(e);
-        }
-    }
-
-    /**
-     * Tell system that the session sets the new playback state.
-     *
-     * @param state the new playback state
-     */
-    void setPlaybackState(@Nullable PlaybackState state) {
-        try {
-            mISession.setPlaybackState(state);
-        } catch (RemoteException e) {
-            throw new RuntimeException(e);
-        }
-    }
-
-    /**
-     * Tell system that the session sets the new queue.
-     *
-     * @param queue the new queue
-     */
-    void setQueue(@Nullable List<QueueItem> queue) {
-        try {
-            mISession.setQueue(queue == null ? null : new MediaParceledListSlice(queue));
-        } catch (RemoteException e) {
-            throw new RuntimeException(e);
-        }
-    }
-
-    /**
-     * Tell system that the session sets the new queue title.
-     *
-     * @param title the new queue title
-     */
-    void setQueueTitle(@Nullable CharSequence title) {
-        try {
-            mISession.setQueueTitle(title);
-        } catch (RemoteException e) {
-            throw new RuntimeException(e);
-        }
-    }
-
-    /**
-     * Tell system that the session sets the new extras.
-     *
-     * @param extras the new extras
-     */
-    void setExtras(@Nullable Bundle extras) {
-        try {
-            mISession.setExtras(extras);
-        } catch (RemoteException e) {
-            throw new RuntimeException(e);
-        }
-    }
-
-    /**
-     * Tell system that the session sets the new rating type of the current media.
-     *
-     * @param type the rating type.
-     */
-    void setRatingType(int type) {
-        try {
-            mISession.setRatingType(type);
-        } catch (RemoteException e) {
-            throw new RuntimeException(e);
-        }
-    }
-
-    /**
-     * Tell system that the session represents a local playback.
-     *
-     * @param attributes the audio attributes of the local playback.
-     */
-    void setPlaybackToLocal(@NonNull AudioAttributes attributes) {
-        try {
-            mISession.setPlaybackToLocal(attributes);
-        } catch (RemoteException e) {
-            throw new RuntimeException(e);
-        }
-    }
-
-    /**
-     * Tell system that the session represents a remote playback.
-     *
-     * @param control the volume control type
-     * @param max the max volume
-     */
-    void setPlaybackToRemote(int control, int max) {
-        try {
-            mISession.setPlaybackToRemote(control, max);
-        } catch (RemoteException e) {
-            throw new RuntimeException(e);
-        }
-    }
-
-    /**
-     * Tell system that the session sets the new current volume.
-     *
-     * @param currentVolume the new current volume
-     */
-    void setCurrentVolume(int currentVolume) {
-        try {
-            mISession.setCurrentVolume(currentVolume);
-        } catch (RemoteException e) {
-            throw new RuntimeException(e);
-        }
-    }
-
-    /** Gets the binder */
-    @NonNull
-    public IBinder getBinder() {
-        return mISession.asBinder();
-    }
-
-    @Override
-    public int describeContents() {
-        return 0;
-    }
-
-    @Override
-    public void writeToParcel(Parcel dest, int flags) {
-        dest.writeStrongBinder(mISession.asBinder());
-    }
-
-    /**
-     * Class for Stub implementation
-     */
-    public abstract static class SessionStub {
-        /** Stub method for ISession.sendEvent */
-        public void sendEvent(@NonNull String event, @Nullable Bundle data) {
-        }
-
-        /** Stub method for ISession.getController */
-        @NonNull
-        public ISessionController getController() {
-            return null;
-        }
-
-        /** Stub method for ISession.setFlags */
-        public void setFlags(int flags) {
-        }
-
-        /** Stub method for ISession.setActive */
-        public void setActive(boolean active) {
-        }
-
-        /** Stub method for ISession.setMediaButtonReceiver */
-        public void setMediaButtonReceiver(@Nullable PendingIntent mbr) {
-        }
-
-        /** Stub method for ISession.setLaunchPendingIntent */
-        public void setLaunchPendingIntent(@Nullable PendingIntent pi) {
-        }
-
-        /** Stub method for ISession.destroySession */
-        public void destroySession() {
-        }
-
-        /** Stub method for ISession.setMetadata */
-        public void setMetadata(@Nullable MediaMetadata metadata, long duration,
-                @Nullable String metadataDescription) {
-        }
-
-        /** Stub method for ISession.setPlaybackState */
-        public void setPlaybackState(@Nullable PlaybackState state) {
-        }
-
-        /** Stub method for ISession.setQueue */
-        public void setQueue(@Nullable List<QueueItem> queue) {
-        }
-
-        /** Stub method for ISession.setQueueTitle */
-        public void setQueueTitle(@Nullable CharSequence title) {
-        }
-
-        /** Stub method for ISession.setExtras */
-        public void setExtras(@Nullable Bundle extras) {
-        }
-
-        /** Stub method for ISession.setRatingType */
-        public void setRatingType(int type) {
-        }
-
-        /** Stub method for ISession.setPlaybackToLocal */
-        public void setPlaybackToLocal(@NonNull AudioAttributes attributes) {
-        }
-
-        /** Stub method for ISession.setPlaybackToRemote */
-        public void setPlaybackToRemote(int control, int max) {
-        }
-
-        /** Stub method for ISession.setCurrentVolume */
-        public void setCurrentVolume(int currentVolume) {
-        }
-    }
-
-    private class StubProxy extends ISession.Stub {
-        @Override
-        public void sendEvent(String event, Bundle data) {
-            mSessionStub.sendEvent(event, data);
-        }
-
-        @Override
-        public ISessionController getController() {
-            return mSessionStub.getController();
-        }
-
-        @Override
-        public void setFlags(int flags) {
-            mSessionStub.setFlags(flags);
-        }
-
-        @Override
-        public void setActive(boolean active) {
-            mSessionStub.setActive(active);
-        }
-
-        @Override
-        public void setMediaButtonReceiver(PendingIntent mbr) {
-            mSessionStub.setMediaButtonReceiver(mbr);
-        }
-
-        @Override
-        public void setLaunchPendingIntent(PendingIntent pi) {
-            mSessionStub.setLaunchPendingIntent(pi);
-        }
-
-        @Override
-        public void destroySession() {
-            mSessionStub.destroySession();
-        }
-
-        @Override
-        public void setMetadata(MediaMetadata metadata, long duration, String metadataDescription) {
-            mSessionStub.setMetadata(metadata, duration, metadataDescription);
-        }
-
-        @Override
-        public void setPlaybackState(PlaybackState state) {
-            mSessionStub.setPlaybackState(state);
-        }
-
-        @Override
-        public void setQueue(MediaParceledListSlice queue) {
-            mSessionStub.setQueue(queue == null ? null : queue.getList());
-        }
-
-        @Override
-        public void setQueueTitle(CharSequence title) {
-            mSessionStub.setQueueTitle(title);
-        }
-
-        @Override
-        public void setExtras(Bundle extras) {
-            mSessionStub.setExtras(extras);
-        }
-
-        @Override
-        public void setRatingType(int type) {
-            mSessionStub.setRatingType(type);
-        }
-
-        @Override
-        public void setPlaybackToLocal(AudioAttributes attributes) {
-            mSessionStub.setPlaybackToLocal(attributes);
-        }
-
-        @Override
-        public void setPlaybackToRemote(int control, int max) {
-            mSessionStub.setPlaybackToRemote(control, max);
-        }
-
-        @Override
-        public void setCurrentVolume(int currentVolume) {
-            mSessionStub.setCurrentVolume(currentVolume);
-        }
-    }
-}
diff --git a/media/java/android/mtp/MtpDatabase.java b/media/java/android/mtp/MtpDatabase.java
index 474b671..dc2d177 100755
--- a/media/java/android/mtp/MtpDatabase.java
+++ b/media/java/android/mtp/MtpDatabase.java
@@ -54,6 +54,7 @@
 import java.util.HashMap;
 import java.util.List;
 import java.util.Locale;
+import java.util.Objects;
 import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.stream.IntStream;
 
@@ -248,7 +249,7 @@
     public MtpDatabase(Context context, String volumeName,
             String[] subDirectories) {
         native_setup();
-        mContext = context;
+        mContext = Objects.requireNonNull(context);
         mMediaProvider = context.getContentResolver()
                 .acquireContentProviderClient(MediaStore.AUTHORITY);
         mVolumeName = volumeName;
@@ -294,6 +295,10 @@
         }
     }
 
+    public Context getContext() {
+        return mContext;
+    }
+
     @Override
     public void close() {
         mManager.close();
diff --git a/media/java/android/mtp/MtpServer.java b/media/java/android/mtp/MtpServer.java
index a555d37..f0ab9a3 100644
--- a/media/java/android/mtp/MtpServer.java
+++ b/media/java/android/mtp/MtpServer.java
@@ -18,7 +18,12 @@
 
 import com.android.internal.util.Preconditions;
 
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.util.ByteStringUtils;
+
 import java.io.FileDescriptor;
+import java.util.Random;
 
 /**
  * Java wrapper for MTP/PTP support as USB responder.
@@ -29,6 +34,12 @@
     private long mNativeContext; // accessed by native methods
     private final MtpDatabase mDatabase;
     private final Runnable mOnTerminate;
+    private final Context mContext;
+
+// It requires "exactly 32 characters, including any leading 0s" in MTP spec
+// (5.1.1.14 Serial Number)
+    private static final int sID_LEN_BYTES = 16;
+    private static final int sID_LEN_STR = (sID_LEN_BYTES * 2);
 
     static {
         System.loadLibrary("media_jni");
@@ -41,10 +52,41 @@
             Runnable onTerminate,
             String deviceInfoManufacturer,
             String deviceInfoModel,
-            String deviceInfoDeviceVersion,
-            String deviceInfoSerialNumber) {
+            String deviceInfoDeviceVersion) {
         mDatabase = Preconditions.checkNotNull(database);
         mOnTerminate = Preconditions.checkNotNull(onTerminate);
+        mContext = mDatabase.getContext();
+
+        final String strID_PREFS_NAME = "mtp-cfg";
+        final String strID_PREFS_KEY = "mtp-id";
+        String strRandomId = null;
+        String deviceInfoSerialNumber;
+
+        SharedPreferences sharedPref =
+                mContext.getSharedPreferences(strID_PREFS_NAME, Context.MODE_PRIVATE);
+        if (sharedPref.contains(strID_PREFS_KEY)) {
+            strRandomId = sharedPref.getString(strID_PREFS_KEY, null);
+
+            // Check for format consistence (regenerate upon corruption)
+            if (strRandomId.length() != sID_LEN_STR) {
+                strRandomId = null;
+            } else {
+                // Only accept hex digit
+                for (int ii = 0; ii < strRandomId.length(); ii++)
+                    if (Character.digit(strRandomId.charAt(ii), 16) == -1) {
+                        strRandomId = null;
+                        break;
+                    }
+            }
+        }
+
+        if (strRandomId == null) {
+            strRandomId = getRandId();
+            sharedPref.edit().putString(strID_PREFS_KEY, strRandomId).apply();
+        }
+
+        deviceInfoSerialNumber = strRandomId;
+
         native_setup(
                 database,
                 controlFd,
@@ -56,6 +98,14 @@
         database.setServer(this);
     }
 
+    private String getRandId() {
+        Random randomVal = new Random();
+        byte[] randomBytes = new byte[sID_LEN_BYTES];
+
+        randomVal.nextBytes(randomBytes);
+        return ByteStringUtils.toHexString(randomBytes);
+    }
+
     public void start() {
         Thread thread = new Thread(this, "MtpServer");
         thread.start();
diff --git a/media/jni/android_media_MediaHTTPConnection.cpp b/media/jni/android_media_MediaHTTPConnection.cpp
index 365e045..d28c15c 100644
--- a/media/jni/android_media_MediaHTTPConnection.cpp
+++ b/media/jni/android_media_MediaHTTPConnection.cpp
@@ -109,7 +109,8 @@
     gFields.context = env->GetFieldID(clazz.get(), "mNativeContext", "J");
     CHECK(gFields.context != NULL);
 
-    gFields.readAtMethodID = env->GetMethodID(clazz.get(), "readAt", "(J[BI)I");
+    gFields.readAtMethodID = env->GetMethodID(
+            clazz.get(), "readAt", "(J[BILandroid/media/MediaHTTPConnection$ConnectionState;)I");
 }
 
 static void android_media_MediaHTTPConnection_native_setup(
@@ -132,7 +133,7 @@
 }
 
 static jint android_media_MediaHTTPConnection_native_readAt(
-        JNIEnv *env, jobject thiz, jlong offset, jint size) {
+        JNIEnv *env, jobject thiz, jlong offset, jint size, jobject connectionState) {
     sp<JMediaHTTPConnection> conn = getObject(env, thiz);
     if (size > JMediaHTTPConnection::kBufferSize) {
         size = JMediaHTTPConnection::kBufferSize;
@@ -141,7 +142,7 @@
     jbyteArray byteArrayObj = conn->getByteArrayObj();
 
     jint n = env->CallIntMethod(
-            thiz, gFields.readAtMethodID, offset, byteArrayObj, size);
+            thiz, gFields.readAtMethodID, offset, byteArrayObj, size, connectionState);
 
     if (n > 0) {
         env->GetByteArrayRegion(
@@ -158,7 +159,7 @@
     { "native_getIMemory", "()Landroid/os/IBinder;",
       (void *)android_media_MediaHTTPConnection_native_getIMemory },
 
-    { "native_readAt", "(JI)I",
+    { "native_readAt", "(JILandroid/media/MediaHTTPConnection$ConnectionState;)I",
       (void *)android_media_MediaHTTPConnection_native_readAt },
 
     { "native_init", "()V",
diff --git a/media/mca/effect/java/android/media/effect/SingleFilterEffect.java b/media/mca/effect/java/android/media/effect/SingleFilterEffect.java
index 47900df..dfbf5d2 100644
--- a/media/mca/effect/java/android/media/effect/SingleFilterEffect.java
+++ b/media/mca/effect/java/android/media/effect/SingleFilterEffect.java
@@ -17,6 +17,7 @@
 
 package android.media.effect;
 
+import android.annotation.UnsupportedAppUsage;
 import android.filterfw.core.Filter;
 import android.filterfw.core.FilterFactory;
 import android.filterfw.core.FilterFunction;
@@ -44,6 +45,7 @@
      * @param outputName The name of the output image port.
      * @param finalParameters Key-value pairs of final input port assignments.
      */
+    @UnsupportedAppUsage
     public SingleFilterEffect(EffectContext context,
                               String name,
                               Class filterClass,
diff --git a/media/mca/filterfw/java/android/filterfw/GraphEnvironment.java b/media/mca/filterfw/java/android/filterfw/GraphEnvironment.java
index 7c90b27..52615bf 100644
--- a/media/mca/filterfw/java/android/filterfw/GraphEnvironment.java
+++ b/media/mca/filterfw/java/android/filterfw/GraphEnvironment.java
@@ -119,6 +119,7 @@
      *
      * @param references An alternating argument list of keys (Strings) and values.
      */
+    @UnsupportedAppUsage
     public void addReferences(Object... references) {
         getGraphReader().addReferencesByKeysAndValues(references);
     }
diff --git a/packages/CaptivePortalLogin/src/com/android/captiveportallogin/CaptivePortalLoginActivity.java b/packages/CaptivePortalLogin/src/com/android/captiveportallogin/CaptivePortalLoginActivity.java
index a288d010..bda5743 100644
--- a/packages/CaptivePortalLogin/src/com/android/captiveportallogin/CaptivePortalLoginActivity.java
+++ b/packages/CaptivePortalLogin/src/com/android/captiveportallogin/CaptivePortalLoginActivity.java
@@ -52,6 +52,7 @@
 import android.webkit.CookieManager;
 import android.webkit.SslErrorHandler;
 import android.webkit.WebChromeClient;
+import android.webkit.WebResourceRequest;
 import android.webkit.WebSettings;
 import android.webkit.WebView;
 import android.webkit.WebViewClient;
@@ -409,8 +410,7 @@
                     TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 1,
                     getResources().getDisplayMetrics());
         private int mPagesLoaded;
-        // the host of the page that this webview is currently loading. Can be null when undefined.
-        private String mHostname;
+        private String mMainFrameUrl;
 
         // If we haven't finished cleaning up the history, don't allow going back.
         public boolean allowBack() {
@@ -436,7 +436,6 @@
             }
             final URL url = makeURL(urlString);
             Log.d(TAG, "onPageStarted: " + sanitizeURL(url));
-            mHostname = host(url);
             // For internally generated pages, leave URL bar listing prior URL as this is the URL
             // the page refers to.
             if (!urlString.startsWith(INTERNAL_ASSETS)) {
@@ -480,17 +479,28 @@
             return Integer.toString((int)dp) + "px";
         }
 
+        // Check if webview is trying to load the main frame and record its url.
+        @Override
+        public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) {
+            if (request.isForMainFrame()) {
+                mMainFrameUrl = request.getUrl().toString();
+            }
+            return false;
+        }
+
         // A web page consisting of a large broken lock icon to indicate SSL failure.
 
         @Override
         public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) {
-            final URL url = makeURL(error.getUrl());
-            final String host = host(url);
+            final URL errorUrl = makeURL(error.getUrl());
+            final URL mainFrameUrl = makeURL(mMainFrameUrl);
             Log.d(TAG, String.format("SSL error: %s, url: %s, certificate: %s",
-                    sslErrorName(error), sanitizeURL(url), error.getCertificate()));
-            if (url == null || !Objects.equals(host, mHostname)) {
-                // Ignore ssl errors for resources coming from a different hostname than the page
-                // that we are currently loading, and only cancel the request.
+                    sslErrorName(error), sanitizeURL(errorUrl), error.getCertificate()));
+            if (errorUrl == null
+                    // Ignore SSL errors from resources by comparing the main frame url with SSL
+                    // error url.
+                    || !errorUrl.equals(mainFrameUrl)) {
+                Log.d(TAG, "onReceivedSslError: mMainFrameUrl = " + mMainFrameUrl);
                 handler.cancel();
                 return;
             }
diff --git a/packages/CarSystemUI/Android.bp b/packages/CarSystemUI/Android.bp
index 9064ebe..589623b 100644
--- a/packages/CarSystemUI/Android.bp
+++ b/packages/CarSystemUI/Android.bp
@@ -32,7 +32,6 @@
         "SystemUISharedLib",
         "SettingsLib",
         "android.car.userlib",
-        "androidx.car_car",
         "androidx.legacy_legacy-support-v4",
         "androidx.recyclerview_recyclerview",
         "androidx.preference_preference",
@@ -46,7 +45,6 @@
         "androidx.slice_slice-builders",
         "androidx.arch.core_core-runtime",
         "androidx.lifecycle_lifecycle-extensions",
-        "car-theme-lib-bp",
         "SystemUI-tags",
         "SystemUI-proto",
     ],
@@ -58,8 +56,8 @@
 
     manifest: "AndroidManifest.xml",
 
-    owner: "google",
     platform_apis: true,
+    product_specific: true,
     certificate: "platform",
     privileged: true,
 
@@ -82,4 +80,6 @@
     ],
 
     plugins: ["dagger2-compiler-2.19"],
+
+    required: ["privapp_whitelist_com.android.systemui"],
 }
diff --git a/packages/CarSystemUI/res-keyguard/drawable/keyguard_button_background.xml b/packages/CarSystemUI/res-keyguard/drawable/keyguard_button_background.xml
index b428931..8b2779d 100644
--- a/packages/CarSystemUI/res-keyguard/drawable/keyguard_button_background.xml
+++ b/packages/CarSystemUI/res-keyguard/drawable/keyguard_button_background.xml
@@ -18,13 +18,13 @@
 <selector xmlns:android="http://schemas.android.com/apk/res/android">
     <item android:state_pressed="true">
         <shape android:shape="rectangle">
-            <corners android:radius="@dimen/car_button_radius"/>
+            <corners android:radius="@*android:dimen/car_button_radius"/>
             <solid android:color="#131315"/>
         </shape>
     </item>
     <item>
         <shape android:shape="rectangle">
-            <corners android:radius="@dimen/car_button_radius"/>
+            <corners android:radius="@*android:dimen/car_button_radius"/>
             <solid android:color="@color/button_background"/>
         </shape>
     </item>
diff --git a/packages/CarSystemUI/res-keyguard/layout-land/keyguard_pattern_view.xml b/packages/CarSystemUI/res-keyguard/layout-land/keyguard_pattern_view.xml
index b115a1f..a465254 100644
--- a/packages/CarSystemUI/res-keyguard/layout-land/keyguard_pattern_view.xml
+++ b/packages/CarSystemUI/res-keyguard/layout-land/keyguard_pattern_view.xml
@@ -28,7 +28,7 @@
     android:orientation="horizontal"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
-    android:paddingHorizontal="@dimen/car_margin">
+    android:paddingHorizontal="@*android:dimen/car_margin">
 
     <FrameLayout
         android:layout_height="match_parent"
@@ -53,10 +53,10 @@
         <TextView
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
-            android:layout_margin="@dimen/car_padding_2"
+            android:layout_margin="@*android:dimen/car_padding_2"
             android:gravity="center"
             android:textColor="@android:color/white"
-            android:textSize="@dimen/car_body1_size"
+            android:textSize="@*android:dimen/car_body1_size"
             android:text="@string/keyguard_enter_your_pattern" />
 
         <include layout="@layout/keyguard_message_area" />
diff --git a/packages/CarSystemUI/res-keyguard/layout-land/keyguard_pin_view.xml b/packages/CarSystemUI/res-keyguard/layout-land/keyguard_pin_view.xml
index ed88c62..5746102 100644
--- a/packages/CarSystemUI/res-keyguard/layout-land/keyguard_pin_view.xml
+++ b/packages/CarSystemUI/res-keyguard/layout-land/keyguard_pin_view.xml
@@ -29,7 +29,7 @@
     android:layout_width="match_parent"
     android:layout_height="match_parent"
     android:orientation="horizontal"
-    android:paddingHorizontal="@dimen/car_margin">
+    android:paddingHorizontal="@*android:dimen/car_margin">
 
     <FrameLayout
         android:layout_width="0dp"
@@ -72,10 +72,10 @@
         <TextView
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
-            android:layout_margin="@dimen/car_padding_2"
+            android:layout_margin="@*android:dimen/car_padding_2"
             android:gravity="center"
             android:textColor="@android:color/white"
-            android:textSize="@dimen/car_body1_size"
+            android:textSize="@*android:dimen/car_body1_size"
             android:text="@string/keyguard_enter_your_pin" />
 
         <include layout="@layout/keyguard_message_area" />
diff --git a/packages/CarSystemUI/res-keyguard/layout/keyguard_message_area.xml b/packages/CarSystemUI/res-keyguard/layout/keyguard_message_area.xml
index c230414..09cf472 100644
--- a/packages/CarSystemUI/res-keyguard/layout/keyguard_message_area.xml
+++ b/packages/CarSystemUI/res-keyguard/layout/keyguard_message_area.xml
@@ -27,5 +27,5 @@
     android:singleLine="true"
     android:ellipsize="marquee"
     android:focusable="true"
-    android:layout_marginBottom="@dimen/car_padding_4"
-    android:textSize="@dimen/car_body2_size" />
+    android:layout_marginBottom="@*android:dimen/car_padding_4"
+    android:textSize="@*android:dimen/car_body2_size" />
diff --git a/packages/CarSystemUI/res-keyguard/layout/keyguard_password_view.xml b/packages/CarSystemUI/res-keyguard/layout/keyguard_password_view.xml
index e701fdb..7004fb6 100644
--- a/packages/CarSystemUI/res-keyguard/layout/keyguard_password_view.xml
+++ b/packages/CarSystemUI/res-keyguard/layout/keyguard_password_view.xml
@@ -51,7 +51,7 @@
             android:singleLine="true"
             android:textStyle="normal"
             android:inputType="textPassword"
-            android:textSize="@dimen/car_body1_size"
+            android:textSize="@*android:dimen/car_body1_size"
             android:textColor="?attr/wallpaperTextColor"
             android:textAppearance="?android:attr/textAppearanceMedium"
             android:imeOptions="flagForceAscii|actionDone"
@@ -61,10 +61,10 @@
         <TextView
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
-            android:layout_margin="@dimen/car_padding_2"
+            android:layout_margin="@*android:dimen/car_padding_2"
             android:gravity="center"
             android:textColor="@android:color/white"
-            android:textSize="@dimen/car_body1_size"
+            android:textSize="@*android:dimen/car_body1_size"
             android:text="@string/keyguard_enter_your_password" />
 
         <Button
diff --git a/packages/CarSystemUI/res-keyguard/layout/keyguard_pattern_view.xml b/packages/CarSystemUI/res-keyguard/layout/keyguard_pattern_view.xml
index 00333a8..bb69d44 100644
--- a/packages/CarSystemUI/res-keyguard/layout/keyguard_pattern_view.xml
+++ b/packages/CarSystemUI/res-keyguard/layout/keyguard_pattern_view.xml
@@ -46,10 +46,10 @@
             <TextView
                 android:layout_width="match_parent"
                 android:layout_height="wrap_content"
-                android:layout_margin="@dimen/car_padding_2"
+                android:layout_margin="@*android:dimen/car_padding_2"
                 android:gravity="center"
                 android:textColor="@android:color/white"
-                android:textSize="@dimen/car_body1_size"
+                android:textSize="@*android:dimen/car_body1_size"
                 android:text="@string/keyguard_enter_your_pattern" />
 
             <include layout="@layout/keyguard_message_area" />
diff --git a/packages/CarSystemUI/res-keyguard/layout/keyguard_pin_view.xml b/packages/CarSystemUI/res-keyguard/layout/keyguard_pin_view.xml
index 1662251..815e67d 100644
--- a/packages/CarSystemUI/res-keyguard/layout/keyguard_pin_view.xml
+++ b/packages/CarSystemUI/res-keyguard/layout/keyguard_pin_view.xml
@@ -59,10 +59,10 @@
             <TextView
                 android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
-                android:layout_margin="@dimen/car_padding_2"
+                android:layout_margin="@*android:dimen/car_padding_2"
                 android:gravity="center"
                 android:textColor="@android:color/white"
-                android:textSize="@dimen/car_body1_size"
+                android:textSize="@*android:dimen/car_body1_size"
                 android:text="@string/keyguard_enter_your_pin" />
 
             <include layout="@layout/keyguard_message_area" />
diff --git a/packages/CarSystemUI/res-keyguard/values-land/dimens.xml b/packages/CarSystemUI/res-keyguard/values-land/dimens.xml
index 805a134..c39e0e4 100644
--- a/packages/CarSystemUI/res-keyguard/values-land/dimens.xml
+++ b/packages/CarSystemUI/res-keyguard/values-land/dimens.xml
@@ -15,6 +15,6 @@
   limitations under the License.
 -->
 <resources>
-    <dimen name="num_pad_key_margin_horizontal">@dimen/car_padding_5</dimen>
-    <dimen name="num_pad_key_margin_bottom">@dimen/car_padding_4</dimen>
+    <dimen name="num_pad_key_margin_horizontal">@*android:dimen/car_padding_5</dimen>
+    <dimen name="num_pad_key_margin_bottom">@*android:dimen/car_padding_4</dimen>
 </resources>
diff --git a/packages/CarSystemUI/res-keyguard/values/colors.xml b/packages/CarSystemUI/res-keyguard/values/colors.xml
index e6edbea3..ba9f060 100644
--- a/packages/CarSystemUI/res-keyguard/values/colors.xml
+++ b/packages/CarSystemUI/res-keyguard/values/colors.xml
@@ -16,6 +16,6 @@
 -->
 
 <resources>
-    <color name="button_background">@color/car_dark_blue_grey_600</color>
-    <color name="button_text">@color/car_action1_light</color>
+    <color name="button_background">@*android:color/car_dark_blue_grey_600</color>
+    <color name="button_text">@android:color/white</color>
 </resources>
\ No newline at end of file
diff --git a/packages/CarSystemUI/res-keyguard/values/dimens.xml b/packages/CarSystemUI/res-keyguard/values/dimens.xml
index 9424dc3..8dfe171 100644
--- a/packages/CarSystemUI/res-keyguard/values/dimens.xml
+++ b/packages/CarSystemUI/res-keyguard/values/dimens.xml
@@ -19,8 +19,8 @@
     <dimen name="num_pad_margin_right">144dp</dimen>
     <dimen name="num_pad_key_width">80dp</dimen>
     <dimen name="num_pad_key_height">80dp</dimen>
-    <dimen name="num_pad_key_margin_horizontal">@dimen/car_padding_6</dimen>
-    <dimen name="num_pad_key_margin_bottom">@dimen/car_padding_5</dimen>
+    <dimen name="num_pad_key_margin_horizontal">@*android:dimen/car_padding_5</dimen>
+    <dimen name="num_pad_key_margin_bottom">@*android:dimen/car_padding_5</dimen>
     <dimen name="pin_entry_height">@dimen/num_pad_key_height</dimen>
     <dimen name="divider_height">1dp</dimen>
     <dimen name="key_enter_margin_top">128dp</dimen>
diff --git a/packages/CarSystemUI/res-keyguard/values/styles.xml b/packages/CarSystemUI/res-keyguard/values/styles.xml
index b39e6e6..ecea30a 100644
--- a/packages/CarSystemUI/res-keyguard/values/styles.xml
+++ b/packages/CarSystemUI/res-keyguard/values/styles.xml
@@ -40,7 +40,7 @@
         <item name="android:layout_marginEnd">@dimen/num_pad_key_margin_horizontal</item>
     </style>
 
-    <style name="KeyguardButton" parent="Widget.Car.Button">
+    <style name="KeyguardButton" parent="@android:style/Widget.DeviceDefault.Button">
         <item name="android:background">@drawable/keyguard_button_background</item>
         <item name="android:textColor">@color/button_text</item>
         <item name="android:textAllCaps">false</item>
@@ -48,6 +48,6 @@
 
     <style name="Widget.TextView.NumPadKey" parent="@android:style/Widget.TextView">
         <!-- Only replaces the text size. -->
-        <item name="android:textSize">@dimen/car_body1_size</item>
+        <item name="android:textSize">@*android:dimen/car_body1_size</item>
     </style>
 </resources>
diff --git a/packages/CarSystemUI/res/drawable/car_ic_add_white.xml b/packages/CarSystemUI/res/drawable/car_ic_add_white.xml
index d681860..9d5ca26 100644
--- a/packages/CarSystemUI/res/drawable/car_ic_add_white.xml
+++ b/packages/CarSystemUI/res/drawable/car_ic_add_white.xml
@@ -13,8 +13,8 @@
      limitations under the License.
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:width="@dimen/car_touch_target_size"
-    android:height="@dimen/car_touch_target_size"
+    android:width="@*android:dimen/car_touch_target_size"
+    android:height="@*android:dimen/car_touch_target_size"
     android:viewportWidth="24.0"
     android:viewportHeight="24.0">
   <path
diff --git a/packages/CarSystemUI/res/drawable/car_rounded_bg_bottom.xml b/packages/CarSystemUI/res/drawable/car_rounded_bg_bottom.xml
index eb501e5..07227fb 100644
--- a/packages/CarSystemUI/res/drawable/car_rounded_bg_bottom.xml
+++ b/packages/CarSystemUI/res/drawable/car_rounded_bg_bottom.xml
@@ -19,9 +19,9 @@
        android:shape="rectangle">
     <solid android:color="?android:attr/colorBackgroundFloating" />
     <corners
-        android:bottomLeftRadius="@dimen/car_radius_3"
+        android:bottomLeftRadius="@*android:dimen/car_radius_3"
         android:topLeftRadius="0dp"
-        android:bottomRightRadius="@dimen/car_radius_3"
+        android:bottomRightRadius="@*android:dimen/car_radius_3"
         android:topRightRadius="0dp"
         />
 </shape>
diff --git a/packages/CarSystemUI/res/drawable/car_seekbar_thumb.xml b/packages/CarSystemUI/res/drawable/car_seekbar_thumb.xml
index 1a9b8a5..2649a00 100644
--- a/packages/CarSystemUI/res/drawable/car_seekbar_thumb.xml
+++ b/packages/CarSystemUI/res/drawable/car_seekbar_thumb.xml
@@ -19,19 +19,19 @@
     <item>
         <shape android:shape="oval">
             <padding
-                android:bottom="@dimen/car_padding_1"
-                android:left="@dimen/car_padding_1"
-                android:right="@dimen/car_padding_1"
-                android:top="@dimen/car_padding_1"/>
+                android:bottom="@*android:dimen/car_padding_1"
+                android:left="@*android:dimen/car_padding_1"
+                android:right="@*android:dimen/car_padding_1"
+                android:top="@*android:dimen/car_padding_1"/>
             <solid android:color="@android:color/black"/>
         </shape>
     </item>
     <item>
         <shape android:shape="oval">
-            <solid android:color="@color/car_accent"/>
+            <solid android:color="@*android:color/car_accent"/>
             <size
-                android:width="@dimen/car_seekbar_thumb_size"
-                android:height="@dimen/car_seekbar_thumb_size"/>
+                android:width="@*android:dimen/car_seekbar_thumb_size"
+                android:height="@*android:dimen/car_seekbar_thumb_size"/>
         </shape>
     </item>
 </layer-list>
diff --git a/packages/CarSystemUI/res/layout/car_fullscreen_user_switcher.xml b/packages/CarSystemUI/res/layout/car_fullscreen_user_switcher.xml
index e8c5134cd..395eac1 100644
--- a/packages/CarSystemUI/res/layout/car_fullscreen_user_switcher.xml
+++ b/packages/CarSystemUI/res/layout/car_fullscreen_user_switcher.xml
@@ -14,12 +14,12 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
-        xmlns:app="http://schemas.android.com/apk/res-auto"
-        android:fitsSystemWindows="true"
-        android:layout_width="match_parent"
-        android:layout_height="match_parent"
-        android:visibility="gone">
+<FrameLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:fitsSystemWindows="true"
+    android:visibility="gone">
 
     <LinearLayout
         android:id="@+id/container"
@@ -27,20 +27,21 @@
         android:layout_height="match_parent"
         android:orientation="vertical">
 
-        <include layout="@layout/car_status_bar_header"
-            android:theme="@android:style/Theme"
-            android:layout_alignParentTop="true"/>
+        <include
+            layout="@layout/car_status_bar_header"
+            android:layout_alignParentTop="true"
+            android:theme="@android:style/Theme"/>
 
-        <com.android.systemui.statusbar.car.UserGridRecyclerView
-            android:id="@+id/user_grid"
+        <FrameLayout
             android:layout_width="match_parent"
-            android:layout_height="match_parent"
-            android:layout_marginTop="@dimen/car_user_switcher_margin_top"
-            android:theme="@style/PagedListTheme"
-            app:verticallyCenterListContent="true"
-            app:showPagedListViewDivider="false"
-            app:gutter="both"
-            app:itemSpacing="@dimen/car_user_switcher_vertical_spacing_between_users"/>
+            android:layout_height="match_parent">
+            <com.android.systemui.statusbar.car.UserGridRecyclerView
+                android:id="@+id/user_grid"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:layout_gravity="center_vertical"
+                android:layout_marginTop="@dimen/car_user_switcher_margin_top"/>
+        </FrameLayout>
 
     </LinearLayout>
 </FrameLayout>
diff --git a/packages/CarSystemUI/res/layout/car_navigation_bar.xml b/packages/CarSystemUI/res/layout/car_navigation_bar.xml
index 93d2b67..34fd703 100644
--- a/packages/CarSystemUI/res/layout/car_navigation_bar.xml
+++ b/packages/CarSystemUI/res/layout/car_navigation_bar.xml
@@ -137,8 +137,8 @@
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
         android:layout_weight="1"
-        android:paddingStart="@dimen/car_keyline_1"
-        android:paddingEnd="@dimen/car_keyline_1"
+        android:paddingStart="@*android:dimen/car_keyline_1"
+        android:paddingEnd="@*android:dimen/car_keyline_1"
         android:gravity="center"
         android:visibility="gone">
     </LinearLayout>
diff --git a/packages/CarSystemUI/res/layout/car_navigation_bar_unprovisioned.xml b/packages/CarSystemUI/res/layout/car_navigation_bar_unprovisioned.xml
index 4fa877f..28eba6c 100644
--- a/packages/CarSystemUI/res/layout/car_navigation_bar_unprovisioned.xml
+++ b/packages/CarSystemUI/res/layout/car_navigation_bar_unprovisioned.xml
@@ -28,12 +28,12 @@
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
         android:layout_weight="1"
-        android:paddingStart="@dimen/car_padding_5"
-        android:paddingEnd="@dimen/car_padding_5">
+        android:paddingStart="@*android:dimen/car_padding_5"
+        android:paddingEnd="@*android:dimen/car_padding_5">
 
         <com.android.systemui.statusbar.car.CarNavigationButton
             android:id="@+id/home"
-            android:layout_width="@dimen/car_touch_target_size"
+            android:layout_width="@*android:dimen/car_touch_target_size"
             android:layout_height="match_parent"
             android:background="?android:attr/selectableItemBackground"
             android:src="@drawable/car_ic_overview"
diff --git a/packages/CarSystemUI/res/layout/car_qs_panel.xml b/packages/CarSystemUI/res/layout/car_qs_panel.xml
index d923e0f..9c598d7 100644
--- a/packages/CarSystemUI/res/layout/car_qs_panel.xml
+++ b/packages/CarSystemUI/res/layout/car_qs_panel.xml
@@ -28,7 +28,6 @@
 
     <RelativeLayout
         xmlns:android="http://schemas.android.com/apk/res/android"
-        xmlns:app="http://schemas.android.com/apk/res-auto"
         android:id="@+id/user_switcher_container"
         android:clipChildren="false"
         android:layout_width="match_parent"
@@ -37,11 +36,7 @@
         <com.android.systemui.statusbar.car.UserGridRecyclerView
             android:id="@+id/user_grid"
             android:layout_width="match_parent"
-            android:layout_height="match_parent"
-            android:theme="@style/PagedListTheme"
-            app:showPagedListViewDivider="false"
-            app:gutter="both"
-            app:itemSpacing="@dimen/car_user_switcher_vertical_spacing_between_users"/>
+            android:layout_height="match_parent"/>
 
     </RelativeLayout>
 
diff --git a/packages/CarSystemUI/res/layout/car_top_navigation_bar.xml b/packages/CarSystemUI/res/layout/car_top_navigation_bar.xml
index 2fe740d..925ccb4 100644
--- a/packages/CarSystemUI/res/layout/car_top_navigation_bar.xml
+++ b/packages/CarSystemUI/res/layout/car_top_navigation_bar.xml
@@ -49,11 +49,11 @@
                 android:id="@+id/lefttext"
                 android:layout_width="wrap_content"
                 android:layout_height="match_parent"
-                android:paddingStart="@dimen/car_padding_4"
+                android:paddingStart="@*android:dimen/car_padding_4"
                 android:paddingEnd="16dp"
                 android:gravity="center_vertical|start"
                 android:minEms="4"
-                android:textAppearance="@style/TextAppearance.Car.Status"
+                android:textAppearance="@style/TextAppearance.CarStatus"
                 systemui:hvacAreaId="49"
                 systemui:hvacMaxText="@string/hvac_max_text"
                 systemui:hvacMaxValue="@dimen/hvac_max_value"
@@ -96,7 +96,7 @@
             android:layout_centerHorizontal="true"
             android:layout_centerVertical="true"
             android:layout_toEndOf="@+id/clock_container"
-            android:paddingStart="@dimen/car_padding_1"
+            android:paddingStart="@*android:dimen/car_padding_1"
             android:gravity="center_vertical"
             android:orientation="horizontal"
         >
@@ -132,10 +132,10 @@
                 android:layout_width="wrap_content"
                 android:layout_height="match_parent"
                 android:paddingStart="16dp"
-                android:paddingEnd="@dimen/car_padding_4"
+                android:paddingEnd="@*android:dimen/car_padding_4"
                 android:gravity="center_vertical|end"
                 android:minEms="4"
-                android:textAppearance="@style/TextAppearance.Car.Status"
+                android:textAppearance="@style/TextAppearance.CarStatus"
                 systemui:hvacAreaId="68"
                 systemui:hvacMaxText="@string/hvac_max_text"
                 systemui:hvacMaxValue="@dimen/hvac_max_value"
diff --git a/packages/CarSystemUI/res/layout/car_volume_dialog.xml b/packages/CarSystemUI/res/layout/car_volume_dialog.xml
index 709797d..35551ea 100644
--- a/packages/CarSystemUI/res/layout/car_volume_dialog.xml
+++ b/packages/CarSystemUI/res/layout/car_volume_dialog.xml
@@ -14,15 +14,9 @@
   ~ See the License for the specific language governing permissions and
   ~ limitations under the License
   -->
-<androidx.car.widget.PagedListView
+<androidx.recyclerview.widget.RecyclerView
     xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:app="http://schemas.android.com/apk/res-auto"
     android:id="@+id/volume_list"
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
-    android:minWidth="@dimen/volume_dialog_panel_width"
-    android:theme="@style/PagedListViewTheme"
-    app:gutter="none"
-    app:scrollBarEnabled="false"
-    app:listDividerColor="@color/list_divider_color"
-    app:showPagedListViewDivider="true"/>
+    android:minWidth="@dimen/volume_dialog_panel_width"/>
diff --git a/packages/CarSystemUI/res/layout/car_volume_item.xml b/packages/CarSystemUI/res/layout/car_volume_item.xml
new file mode 100644
index 0000000..2275ca6
--- /dev/null
+++ b/packages/CarSystemUI/res/layout/car_volume_item.xml
@@ -0,0 +1,71 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+    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.
+-->
+
+<RelativeLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:minHeight="@dimen/car_volume_item_height">
+
+    <!-- Primary Action. -->
+    <ImageView
+        android:id="@+id/primary_icon"
+        android:layout_width="@dimen/car_primary_icon_size"
+        android:layout_centerVertical="true"
+        android:layout_marginStart="@dimen/car_volume_item_margin_horizontal"
+        android:layout_alignParentStart="true"
+        android:layout_height="@dimen/car_primary_icon_size"/>
+
+    <!-- Note: the horizontal padding and offset are set to 0 so that the track and thumb
+             aligns with the proper keylines. -->
+    <SeekBar
+        android:id="@+id/seek_bar"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_marginBottom="@dimen/car_volume_item_seekbar_margin_vertical"
+        android:layout_marginTop="@dimen/car_volume_item_seekbar_margin_vertical"
+        android:min="0"
+        android:paddingBottom="@dimen/car_volume_item_seekbar_padding_vertical"
+        android:layout_centerVertical="true"
+        android:paddingEnd="0dp"
+        android:paddingStart="0dp"
+        android:paddingTop="@dimen/car_volume_item_seekbar_padding_vertical"
+        android:splitTrack="false"
+        android:layout_toStartOf="@id/supplemental_icon_divider"
+        android:layout_marginStart="@dimen/car_volume_item_seekbar_margin_start"
+        android:layout_marginEnd="@dimen/car_volume_item_seekbar_margin_end"
+        android:thumbOffset="0dp"/>
+
+    <!-- Supplemental action. -->
+    <View
+        android:id="@+id/supplemental_icon_divider"
+        android:layout_width="@dimen/car_volume_item_divider_width"
+        android:layout_height="@dimen/car_volume_item_divider_height"
+        android:layout_marginEnd="@dimen/car_volume_item_divider_margin_end"
+        android:layout_centerVertical="true"
+        android:layout_toStartOf="@id/supplemental_icon"
+        android:background="@color/car_volume_item_divider_color"/>
+    <ImageView
+        android:id="@+id/supplemental_icon"
+        android:layout_width="@dimen/car_primary_icon_size"
+        android:layout_height="@dimen/car_primary_icon_size"
+        android:background="?android:attr/selectableItemBackground"
+        android:layout_centerVertical="true"
+        android:layout_alignParentEnd="true"
+        android:layout_marginEnd="@dimen/car_volume_item_margin_horizontal"
+        android:scaleType="fitCenter"/>
+</RelativeLayout>
diff --git a/packages/CarSystemUI/res/layout/notification_center_activity.xml b/packages/CarSystemUI/res/layout/notification_center_activity.xml
index 7c83303..383aba4 100644
--- a/packages/CarSystemUI/res/layout/notification_center_activity.xml
+++ b/packages/CarSystemUI/res/layout/notification_center_activity.xml
@@ -32,19 +32,14 @@
          android:translationZ="2dp"
         />
 
-    <androidx.car.widget.PagedListView
+    <androidx.recyclerview.widget.RecyclerView
         android:id="@+id/notifications"
         android:layout_width="0dp"
         android:layout_height="0dp"
         android:orientation="vertical"
-        android:theme="@style/PagedListTheme"
-        app:gutter="none"
-        app:itemSpacing="@dimen/item_spacing"
         app:layout_constraintTop_toTopOf="parent"
         app:layout_constraintBottom_toBottomOf="parent"
         app:layout_constraintStart_toStartOf="parent"
-        app:layout_constraintEnd_toEndOf="parent"
-        app:scrollBarEnabled="false"
-        app:showPagedListViewDivider="false"/>
+        app:layout_constraintEnd_toEndOf="parent"/>
 
 </com.android.car.notification.CarNotificationView>
diff --git a/packages/CarSystemUI/res/values/colors.xml b/packages/CarSystemUI/res/values/colors.xml
index 7b4e32b..83ec351 100644
--- a/packages/CarSystemUI/res/values/colors.xml
+++ b/packages/CarSystemUI/res/values/colors.xml
@@ -45,4 +45,6 @@
     <color name="keyguard_button_text_color">@android:color/black</color>
 
     <color name="list_divider_color">@*android:color/car_list_divider_light</color>
+    <color name="car_volume_item_divider_color">@*android:color/car_list_divider</color>
+    <color name="car_volume_item_background_color">@*android:color/car_card_dark</color>
 </resources>
diff --git a/packages/CarSystemUI/res/values/colors_car.xml b/packages/CarSystemUI/res/values/colors_car.xml
index 08e16cd..69ab3f3 100644
--- a/packages/CarSystemUI/res/values/colors_car.xml
+++ b/packages/CarSystemUI/res/values/colors_car.xml
@@ -18,12 +18,12 @@
 -->
 <resources>
     <color name="car_qs_background_primary">#263238</color> <!-- Blue Gray 900 -->
-    <color name="car_qs_footer_user_name_color">@color/car_grey_50</color>
+    <color name="car_qs_footer_user_name_color">@*android:color/car_grey_50</color>
 
     <!-- colors for user switcher -->
-    <color name="car_user_switcher_background_color">@color/car_card_dark</color>
-    <color name="car_user_switcher_name_text_color">@color/car_body1_light</color>
-    <color name="car_user_switcher_add_user_background_color">@color/car_dark_blue_grey_600</color>
-    <color name="car_user_switcher_add_user_add_sign_color">@color/car_body1_light</color>
+    <color name="car_user_switcher_background_color">@*android:color/car_card_dark</color>
+    <color name="car_user_switcher_name_text_color">@*android:color/car_body1_light</color>
+    <color name="car_user_switcher_add_user_background_color">@*android:color/car_dark_blue_grey_600</color>
+    <color name="car_user_switcher_add_user_add_sign_color">@*android:color/car_body1_light</color>
 
 </resources>
diff --git a/packages/CarSystemUI/res/values/dimens.xml b/packages/CarSystemUI/res/values/dimens.xml
index 07ecca2..8789c8a 100644
--- a/packages/CarSystemUI/res/values/dimens.xml
+++ b/packages/CarSystemUI/res/values/dimens.xml
@@ -26,7 +26,7 @@
     <!-- The amount by which to scale up the status bar icons. -->
     <item name="status_bar_icon_scale_factor" format="float" type="dimen">1.75</item>
 
-    <dimen name="car_primary_icon_size">36dp</dimen>
+    <dimen name="car_primary_icon_size">@*android:dimen/car_primary_icon_size</dimen>
 
     <!-- dimensions for the car user switcher -->
     <dimen name="car_user_switcher_name_text_size">@dimen/car_body1_size</dimen>
@@ -49,7 +49,7 @@
 
     <dimen name="volume_dialog_elevation">6dp</dimen>
 
-    <dimen name="volume_dialog_row_margin_end">@dimen/car_keyline_3</dimen>
+    <dimen name="volume_dialog_row_margin_end">@*android:dimen/car_keyline_3</dimen>
 
     <dimen name="volume_dialog_row_padding_end">0dp</dimen>
 
@@ -59,4 +59,33 @@
     <dimen name="car_keyline_1">24dp</dimen>
     <dimen name="car_keyline_2">96dp</dimen>
     <dimen name="car_keyline_3">128dp</dimen>
+
+    <dimen name="privacy_chip_icon_max_height">100dp</dimen>
+
+    <!-- Height of icons in Ongoing App Ops dialog. Both App Op icon and application icon -->
+    <dimen name="ongoing_appops_dialog_icon_height">48dp</dimen>
+    <!-- Margin between text lines in Ongoing App Ops dialog -->
+    <dimen name="ongoing_appops_dialog_text_margin">15dp</dimen>
+    <!-- Padding around Ongoing App Ops dialog content -->
+    <dimen name="ongoing_appops_dialog_content_padding">24dp</dimen>
+    <!-- Margins around the Ongoing App Ops chip. In landscape, the side margins are 0 -->
+    <dimen name="ongoing_appops_chip_margin">12dp</dimen>
+    <!-- Start and End padding for Ongoing App Ops chip -->
+    <dimen name="ongoing_appops_chip_side_padding">6dp</dimen>
+    <!-- Padding between background of Ongoing App Ops chip and content -->
+    <dimen name="ongoing_appops_chip_bg_padding">4dp</dimen>
+    <!-- Radius of Ongoing App Ops chip corners -->
+    <dimen name="ongoing_appops_chip_bg_corner_radius">12dp</dimen>
+
+    <!-- Car volume dimens. -->
+    <dimen name="car_volume_item_height">@*android:dimen/car_single_line_list_item_height</dimen>
+    <dimen name="car_volume_item_margin_horizontal">@*android:dimen/car_keyline_1</dimen>
+    <dimen name="car_volume_item_seekbar_margin_vertical">@*android:dimen/car_padding_1</dimen>
+    <dimen name="car_volume_item_seekbar_margin_start">@*android:dimen/car_keyline_3</dimen>
+    <dimen name="car_volume_item_seekbar_margin_end">@*android:dimen/car_padding_4</dimen>
+    <dimen name="car_volume_item_seekbar_padding_vertical">@*android:dimen/car_seekbar_padding</dimen>
+    <dimen name="car_volume_item_divider_height">60dp</dimen>
+    <dimen name="car_volume_item_divider_width">1dp</dimen>
+    <dimen name="car_volume_item_divider_margin_end">@*android:dimen/car_padding_4</dimen>
+    <dimen name="car_volume_item_corner_radius">@*android:dimen/car_radius_3</dimen>
 </resources>
diff --git a/packages/CarSystemUI/res/values/dimens_car.xml b/packages/CarSystemUI/res/values/dimens_car.xml
index c027f81..42a7649 100644
--- a/packages/CarSystemUI/res/values/dimens_car.xml
+++ b/packages/CarSystemUI/res/values/dimens_car.xml
@@ -17,11 +17,11 @@
 -->
 <resources>
     <!-- dimensions for the car user switcher -->
-    <dimen name="car_user_switcher_name_text_size">@dimen/car_body1_size</dimen>
-    <dimen name="car_user_switcher_image_avatar_size">@dimen/car_large_avatar_size</dimen>
-    <dimen name="car_user_switcher_vertical_spacing_between_users">@dimen/car_padding_5</dimen>
-    <dimen name="car_user_switcher_vertical_spacing_between_name_and_avatar">@dimen/car_padding_4</dimen>
-    <dimen name="car_user_switcher_margin_top">@dimen/car_padding_4</dimen>
+    <dimen name="car_user_switcher_name_text_size">@*android:dimen/car_body1_size</dimen>
+    <dimen name="car_user_switcher_image_avatar_size">@*android:dimen/car_large_avatar_size</dimen>
+    <dimen name="car_user_switcher_vertical_spacing_between_users">@*android:dimen/car_padding_5</dimen>
+    <dimen name="car_user_switcher_vertical_spacing_between_name_and_avatar">@*android:dimen/car_padding_4</dimen>
+    <dimen name="car_user_switcher_margin_top">@*android:dimen/car_padding_4</dimen>
 
     <dimen name="car_navigation_button_width">64dp</dimen>
     <dimen name="car_navigation_bar_width">760dp</dimen>
@@ -37,7 +37,7 @@
     <dimen name="car_qs_footer_icon_height">56dp</dimen>
     <dimen name="car_qs_footer_user_switch_icon_margin">5dp</dimen>
     <dimen name="car_qs_footer_user_switch_icon_width">36dp</dimen>
-    <dimen name="car_qs_footer_user_name_text_size">@dimen/car_body2_size</dimen>
+    <dimen name="car_qs_footer_user_name_text_size">@*android:dimen/car_body2_size</dimen>
 
     <dimen name="car_user_switcher_container_height">420dp</dimen>
     <!-- This must be the negative of car_user_switcher_container_height for the animation. -->
diff --git a/packages/CarSystemUI/res/values/styles.xml b/packages/CarSystemUI/res/values/styles.xml
index 0d95d30..371bebd 100644
--- a/packages/CarSystemUI/res/values/styles.xml
+++ b/packages/CarSystemUI/res/values/styles.xml
@@ -29,12 +29,12 @@
         parent="@*android:style/TextAppearance.StatusBar.Icon">
         <item name="android:textSize">42sp</item>
         <item name="android:fontFamily">sans-serif-regular</item>
-        <item name="android:textColor">@color/car_grey_50</item>
+        <item name="android:textColor">@*android:color/car_grey_50</item>
     </style>
 
-    <style name="TextAppearance.Car.Status">
-        <item name="android:textSize">@dimen/car_body2_size</item>
-        <item name="android:textColor">@color/car_grey_50</item>
+    <style name="TextAppearance.CarStatus" parent="@android:style/TextAppearance.DeviceDefault">
+        <item name="android:textSize">@*android:dimen/car_body2_size</item>
+        <item name="android:textColor">@*android:color/car_grey_50</item>
     </style>
 
     <style name="CarNavigationBarButtonTheme">
@@ -46,11 +46,4 @@
         <item name="android:layout_width">96dp</item>
         <item name="android:background">@drawable/nav_button_background</item>
     </style>
-
-    <style name="PagedListViewTheme" parent="@style/Theme.CarSupportWrapper.NoActionBar">
-        <item name="android:background">@*android:color/car_background</item>
-        <item name="listItemBackgroundColor">@*android:color/car_background</item>
-        <item name="dividerEndMargin">@dimen/car_keyline_1</item>
-        <item name="dividerStartMargin">@dimen/car_keyline_1</item>
-    </style>
 </resources>
\ No newline at end of file
diff --git a/packages/CarSystemUI/res/values/themes.xml b/packages/CarSystemUI/res/values/themes.xml
index 8d1a4d7..f82be3c 100644
--- a/packages/CarSystemUI/res/values/themes.xml
+++ b/packages/CarSystemUI/res/values/themes.xml
@@ -18,10 +18,6 @@
 -->
 
 <resources>
-    <!--This Theme contains attributes required for components from the car support lib -->
-    <style name="PagedListTheme" parent="Theme.CarSupportWrapper.NoActionBar">
-    </style>
-
     <style name="Theme.Notification" parent="Theme.DeviceDefault.NoActionBar.Notification">
     </style>
 </resources>
diff --git a/packages/CarSystemUI/src/com/android/systemui/notifications/NotificationsUI.java b/packages/CarSystemUI/src/com/android/systemui/notifications/NotificationsUI.java
index 4a2d2fb..48cb55b 100644
--- a/packages/CarSystemUI/src/com/android/systemui/notifications/NotificationsUI.java
+++ b/packages/CarSystemUI/src/com/android/systemui/notifications/NotificationsUI.java
@@ -16,11 +16,11 @@
 
 package com.android.systemui.notifications;
 
-import android.app.ActivityManager;
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
 import android.animation.ValueAnimator;
 import android.annotation.SuppressLint;
+import android.app.ActivityManager;
 import android.car.Car;
 import android.car.CarNotConnectedException;
 import android.car.drivingstate.CarUxRestrictionsManager;
@@ -113,7 +113,7 @@
                         ServiceManager.getService(Context.STATUS_BAR_SERVICE)),
                 launchResult -> {
                     if (launchResult == ActivityManager.START_TASK_TO_FRONT
-                            || launchResult == ActivityManager.START_SUCCESS){
+                            || launchResult == ActivityManager.START_SUCCESS) {
                         closeCarNotifications(DEFAULT_FLING_VELOCITY);
                     }
                 });
@@ -179,8 +179,7 @@
                     }
                 });
 
-        RecyclerView notificationList = mCarNotificationWindow
-                .findViewById(com.android.car.notification.R.id.recycler_view);
+        RecyclerView notificationList = mCarNotificationWindow.findViewById(R.id.notifications);
         // register a scroll listener so we can figure out if we are at the bottom of the
         // list of notifications
         notificationList.addOnScrollListener(new RecyclerView.OnScrollListener() {
@@ -202,7 +201,7 @@
         // There's a view installed at a higher z-order such that we can intercept the ACTION_DOWN
         // to set the initial click state.
         mCarNotificationWindow.findViewById(R.id.glass_pane).setOnTouchListener((v, event) -> {
-            if (event.getActionMasked() == MotionEvent.ACTION_UP ) {
+            if (event.getActionMasked() == MotionEvent.ACTION_UP) {
                 mNotificationListAtBottomAtTimeOfTouch = false;
             }
             if (event.getActionMasked() == MotionEvent.ACTION_DOWN) {
@@ -259,7 +258,7 @@
         public boolean onTouch(View v, MotionEvent event) {
             // reset mNotificationListAtBottomAtTimeOfTouch here since the "glass pane" will not
             // get the up event
-            if (event.getActionMasked() == MotionEvent.ACTION_UP ) {
+            if (event.getActionMasked() == MotionEvent.ACTION_UP) {
                 mNotificationListAtBottomAtTimeOfTouch = false;
             }
             boolean wasScrolledUp = mScrollUpDetector.onTouchEvent(event);
@@ -351,7 +350,7 @@
         public boolean onFling(MotionEvent event1, MotionEvent event2,
                 float velocityX, float velocityY) {
             if (Math.abs(event1.getX() - event2.getX()) > SWIPE_MAX_OFF_PATH
-                    || Math.abs(velocityY) < SWIPE_THRESHOLD_VELOCITY){
+                    || Math.abs(velocityY) < SWIPE_THRESHOLD_VELOCITY) {
                 // swipe was not vertical or was not fast enough
                 return false;
             }
@@ -435,8 +434,7 @@
         mNotificationViewController.disable();
         mIsShowing = false;
         mIsTracking = false;
-        RecyclerView notificationListView = mCarNotificationWindow.findViewById(
-                com.android.car.notification.R.id.recycler_view);
+        RecyclerView notificationListView = mCarNotificationWindow.findViewById(R.id.notifications);
         notificationListView.scrollToPosition(0);
     }
 
diff --git a/packages/CarSystemUI/src/com/android/systemui/qs/car/CarQSFragment.java b/packages/CarSystemUI/src/com/android/systemui/qs/car/CarQSFragment.java
index 41c37d3..769fc52 100644
--- a/packages/CarSystemUI/src/com/android/systemui/qs/car/CarQSFragment.java
+++ b/packages/CarSystemUI/src/com/android/systemui/qs/car/CarQSFragment.java
@@ -79,7 +79,7 @@
         mUserGridView = mUserSwitcherContainer.findViewById(R.id.user_grid);
         GridLayoutManager layoutManager = new GridLayoutManager(context,
                 context.getResources().getInteger(R.integer.user_fullscreen_switcher_num_col));
-        mUserGridView.getRecyclerView().setLayoutManager(layoutManager);
+        mUserGridView.setLayoutManager(layoutManager);
         mUserGridView.buildAdapter();
 
         mUserSwitchCallback = new UserSwitchCallback();
diff --git a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/FullscreenUserSwitcher.java b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/FullscreenUserSwitcher.java
index 23fe594..f896cf1 100644
--- a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/FullscreenUserSwitcher.java
+++ b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/FullscreenUserSwitcher.java
@@ -45,7 +45,7 @@
         mUserGridView = container.findViewById(R.id.user_grid);
         GridLayoutManager layoutManager = new GridLayoutManager(context,
                 context.getResources().getInteger(R.integer.user_fullscreen_switcher_num_col));
-        mUserGridView.getRecyclerView().setLayoutManager(layoutManager);
+        mUserGridView.setLayoutManager(layoutManager);
         mUserGridView.buildAdapter();
         mUserGridView.setUserSelectionListener(this::onUserSelected);
 
diff --git a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/UserGridRecyclerView.java b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/UserGridRecyclerView.java
index fb2b57b..827a59e 100644
--- a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/UserGridRecyclerView.java
+++ b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/UserGridRecyclerView.java
@@ -28,6 +28,7 @@
 import android.content.pm.UserInfo;
 import android.content.res.Resources;
 import android.graphics.Bitmap;
+import android.graphics.Rect;
 import android.os.AsyncTask;
 import android.util.AttributeSet;
 import android.view.LayoutInflater;
@@ -36,9 +37,9 @@
 import android.widget.ImageView;
 import android.widget.TextView;
 
-import androidx.car.widget.PagedListView;
 import androidx.core.graphics.drawable.RoundedBitmapDrawable;
 import androidx.core.graphics.drawable.RoundedBitmapDrawableFactory;
+import androidx.recyclerview.widget.GridLayoutManager;
 import androidx.recyclerview.widget.RecyclerView;
 
 import com.android.internal.util.UserIcons;
@@ -52,7 +53,7 @@
  * Displays a GridLayout with icons for the users in the system to allow switching between users.
  * One of the uses of this is for the lock screen in auto.
  */
-public class UserGridRecyclerView extends PagedListView implements
+public class UserGridRecyclerView extends RecyclerView implements
         CarUserManagerHelper.OnUsersUpdateListener {
     private UserSelectionListener mUserSelectionListener;
     private UserAdapter mAdapter;
@@ -63,6 +64,9 @@
         super(context, attrs);
         mContext = context;
         mCarUserManagerHelper = new CarUserManagerHelper(mContext);
+
+        addItemDecoration(new ItemSpacingDecoration(context.getResources().getDimensionPixelSize(
+                R.dimen.car_user_switcher_vertical_spacing_between_users)));
     }
 
     /**
@@ -253,7 +257,8 @@
         }
 
         private void showMaxUserLimitReachedDialog() {
-            AlertDialog maxUsersDialog = new Builder(mContext, R.style.Theme_Car_Dark_Dialog_Alert)
+            AlertDialog maxUsersDialog = new Builder(mContext,
+                    com.android.internal.R.style.Theme_DeviceDefault_Dialog_Alert)
                     .setTitle(R.string.user_limit_reached_title)
                     .setMessage(getResources().getQuantityString(
                             R.plurals.user_limit_reached_message,
@@ -272,7 +277,8 @@
                     .concat(System.getProperty("line.separator"))
                     .concat(mRes.getString(R.string.user_add_user_message_update));
 
-            AlertDialog addUserDialog = new Builder(mContext, R.style.Theme_Car_Dark_Dialog_Alert)
+            AlertDialog addUserDialog = new Builder(mContext,
+                    com.android.internal.R.style.Theme_DeviceDefault_Dialog_Alert)
                     .setTitle(R.string.user_add_user_title)
                     .setMessage(message)
                     .setNegativeButton(android.R.string.cancel, this)
@@ -391,4 +397,31 @@
 
         void onUserSelected(UserRecord record);
     }
+
+    /**
+     * A {@link RecyclerView.ItemDecoration} that will add spacing between each item in the
+     * RecyclerView that it is added to.
+     */
+    private static class ItemSpacingDecoration extends RecyclerView.ItemDecoration {
+        private int mItemSpacing;
+
+        private ItemSpacingDecoration(int itemSpacing) {
+            mItemSpacing = itemSpacing;
+        }
+
+        @Override
+        public void getItemOffsets(Rect outRect, View view, RecyclerView parent,
+                RecyclerView.State state) {
+            super.getItemOffsets(outRect, view, parent, state);
+            int position = parent.getChildAdapterPosition(view);
+
+            // Skip offset for last item except for GridLayoutManager.
+            if (position == state.getItemCount() - 1
+                    && !(parent.getLayoutManager() instanceof GridLayoutManager)) {
+                return;
+            }
+
+            outRect.bottom = mItemSpacing;
+        }
+    }
 }
diff --git a/packages/CarSystemUI/src/com/android/systemui/volume/CarVolumeDialogImpl.java b/packages/CarSystemUI/src/com/android/systemui/volume/CarVolumeDialogImpl.java
index 10a0ae5..512210b 100644
--- a/packages/CarSystemUI/src/com/android/systemui/volume/CarVolumeDialogImpl.java
+++ b/packages/CarSystemUI/src/com/android/systemui/volume/CarVolumeDialogImpl.java
@@ -32,9 +32,7 @@
 import android.content.ServiceConnection;
 import android.content.res.TypedArray;
 import android.content.res.XmlResourceParser;
-import android.graphics.Color;
 import android.graphics.PixelFormat;
-import android.graphics.drawable.ColorDrawable;
 import android.graphics.drawable.Drawable;
 import android.media.AudioManager;
 import android.os.Debug;
@@ -46,7 +44,6 @@
 import android.util.Log;
 import android.util.SparseArray;
 import android.util.Xml;
-import android.view.ContextThemeWrapper;
 import android.view.Gravity;
 import android.view.MotionEvent;
 import android.view.View;
@@ -56,12 +53,8 @@
 import android.widget.SeekBar;
 import android.widget.SeekBar.OnSeekBarChangeListener;
 
-import androidx.car.widget.ListItem;
-import androidx.car.widget.ListItemAdapter;
-import androidx.car.widget.ListItemAdapter.BackgroundStyle;
-import androidx.car.widget.ListItemProvider.ListProvider;
-import androidx.car.widget.PagedListView;
-import androidx.car.widget.SeekbarListItem;
+import androidx.recyclerview.widget.LinearLayoutManager;
+import androidx.recyclerview.widget.RecyclerView;
 
 import com.android.systemui.R;
 import com.android.systemui.plugins.VolumeDialog;
@@ -96,13 +89,13 @@
     private final SparseArray<VolumeItem> mVolumeItems = new SparseArray<>();
     // Available volume items in car audio manager.
     private final List<VolumeItem> mAvailableVolumeItems = new ArrayList<>();
-    // Volume items in the PagedListView.
-    private final List<ListItem> mVolumeLineItems = new ArrayList<>();
+    // Volume items in the RecyclerView.
+    private final List<CarVolumeItem> mCarVolumeLineItems = new ArrayList<>();
     private final KeyguardManager mKeyguard;
     private Window mWindow;
     private CustomDialog mDialog;
-    private PagedListView mListView;
-    private ListItemAdapter mPagedListAdapter;
+    private RecyclerView mListView;
+    private CarVolumeItemAdapter mVolumeItemsAdapter;
     private Car mCar;
     private CarAudioManager mCarAudioManager;
     private final CarAudioManager.CarVolumeCallback mVolumeChangeCallback =
@@ -126,7 +119,7 @@
                     // callback. Updating the seekbar at the same time could block the continuous
                     // seeking.
                     if (value != volumeItem.progress) {
-                        volumeItem.listItem.setProgress(value);
+                        volumeItem.carVolumeItem.setProgress(value);
                         volumeItem.progress = value;
                     }
                     if ((flags & AudioManager.FLAG_SHOW_UI) != 0) {
@@ -160,13 +153,13 @@
                     // The first one is the default item.
                     if (groupId == 0) {
                         mDefaultVolumeItem = volumeItem;
-                        setupDefaultListItem();
+                        setupDefaultCarVolumeItem();
                     }
                 }
 
                 // If list is already initiated, update its content.
-                if (mPagedListAdapter != null) {
-                    mPagedListAdapter.notifyDataSetChanged();
+                if (mVolumeItemsAdapter != null) {
+                    mVolumeItemsAdapter.notifyDataSetChanged();
                 }
                 mCarAudioManager.registerCarVolumeCallback(mVolumeChangeCallback);
             } catch (CarNotConnectedException e) {
@@ -184,15 +177,15 @@
         }
     };
 
-    private void setupDefaultListItem() {
+    private void setupDefaultCarVolumeItem() {
         mDefaultVolumeItem.defaultItem = true;
-        addSeekbarListItem(mDefaultVolumeItem, /* volumeGroupId = */0,
+        addCarVolumeListItem(mDefaultVolumeItem, /* volumeGroupId = */0,
                 R.drawable.car_ic_keyboard_arrow_down, new ExpandIconListener()
         );
     }
 
     public CarVolumeDialogImpl(Context context) {
-        mContext = new ContextThemeWrapper(context, com.android.systemui.R.style.qs_theme);
+        mContext = context;
         mKeyguard = (KeyguardManager) mContext.getSystemService(Context.KEYGUARD_SERVICE);
         mCar = Car.createCar(mContext, mServiceConnection);
     }
@@ -238,7 +231,7 @@
 
     private void initDialog() {
         loadAudioUsageItems();
-        mVolumeLineItems.clear();
+        mCarVolumeLineItems.clear();
         mDialog = new CustomDialog(mContext);
 
         mHovering = false;
@@ -246,7 +239,6 @@
         mExpanded = false;
         mWindow = mDialog.getWindow();
         mWindow.requestFeature(Window.FEATURE_NO_TITLE);
-        mWindow.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
         mWindow.clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND
                 | WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR);
         mWindow.addFlags(WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
@@ -263,10 +255,11 @@
         lp.gravity = Gravity.TOP | Gravity.CENTER_HORIZONTAL;
         lp.windowAnimations = -1;
         mWindow.setAttributes(lp);
-        mWindow.setLayout(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
+
+        mDialog.setContentView(R.layout.car_volume_dialog);
+        mWindow.setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
 
         mDialog.setCanceledOnTouchOutside(true);
-        mDialog.setContentView(R.layout.car_volume_dialog);
         mDialog.setOnShowListener(dialog -> {
             mListView.setTranslationY(-mListView.getHeight());
             mListView.setAlpha(0);
@@ -277,7 +270,7 @@
                     .setInterpolator(new SystemUIInterpolators.LogDecelerateInterpolator())
                     .start();
         });
-        mListView = (PagedListView) mWindow.findViewById(R.id.volume_list);
+        mListView = mWindow.findViewById(R.id.volume_list);
         mListView.setOnHoverListener((v, event) -> {
             int action = event.getActionMasked();
             mHovering = (action == MotionEvent.ACTION_HOVER_ENTER)
@@ -286,10 +279,9 @@
             return true;
         });
 
-        mPagedListAdapter = new ListItemAdapter(mContext, new ListProvider(mVolumeLineItems),
-                BackgroundStyle.PANEL);
-        mListView.setAdapter(mPagedListAdapter);
-        mListView.setMaxPages(PagedListView.UNLIMITED_PAGES);
+        mVolumeItemsAdapter = new CarVolumeItemAdapter(mContext, mCarVolumeLineItems);
+        mListView.setAdapter(mVolumeItemsAdapter);
+        mListView.setLayoutManager(new LinearLayoutManager(mContext));
     }
 
 
@@ -302,13 +294,13 @@
         mHandler.removeMessages(H.DISMISS);
         rescheduleTimeoutH();
         // Refresh the data set before showing.
-        mPagedListAdapter.notifyDataSetChanged();
+        mVolumeItemsAdapter.notifyDataSetChanged();
         if (mShowing) {
             return;
         }
         mShowing = true;
-        if (mVolumeLineItems.isEmpty()) {
-            setupDefaultListItem();
+        if (mCarVolumeLineItems.isEmpty()) {
+            setupDefaultCarVolumeItem();
         }
         mDialog.show();
         Events.writeEvent(mContext, Events.EVENT_SHOW_DIALOG, reason, mKeyguard.isKeyguardLocked());
@@ -421,40 +413,41 @@
         return result;
     }
 
-    private SeekbarListItem addSeekbarListItem(VolumeItem volumeItem,
-            int volumeGroupId,
+    private CarVolumeItem addCarVolumeListItem(VolumeItem volumeItem, int volumeGroupId,
             int supplementalIconId,
             @Nullable View.OnClickListener supplementalIconOnClickListener) {
-        SeekbarListItem listItem = new SeekbarListItem(mContext);
-        listItem.setMax(getMaxSeekbarValue(mCarAudioManager, volumeGroupId));
+        CarVolumeItem carVolumeItem = new CarVolumeItem();
+        carVolumeItem.setMax(getMaxSeekbarValue(mCarAudioManager, volumeGroupId));
         int color = mContext.getResources().getColor(R.color.car_volume_dialog_tint);
         int progress = getSeekbarValue(mCarAudioManager, volumeGroupId);
-        listItem.setProgress(progress);
-        listItem.setOnSeekBarChangeListener(new CarVolumeDialogImpl
-                .VolumeSeekBarChangeListener(volumeGroupId, mCarAudioManager));
+        carVolumeItem.setProgress(progress);
+        carVolumeItem.setOnSeekBarChangeListener(
+                new CarVolumeDialogImpl.VolumeSeekBarChangeListener(volumeGroupId,
+                        mCarAudioManager));
         Drawable primaryIcon = mContext.getResources().getDrawable(volumeItem.icon);
         primaryIcon.mutate().setTint(color);
-        listItem.setPrimaryActionIcon(primaryIcon);
+        carVolumeItem.setPrimaryIcon(primaryIcon);
         if (supplementalIconId != 0) {
             Drawable supplementalIcon = mContext.getResources().getDrawable(supplementalIconId);
             supplementalIcon.mutate().setTint(color);
-            listItem.setSupplementalIcon(supplementalIcon, true);
-            listItem.setSupplementalIconListener(supplementalIconOnClickListener);
+            carVolumeItem.setSupplementalIcon(supplementalIcon,
+                    /* showSupplementalIconDivider= */ true);
+            carVolumeItem.setSupplementalIconListener(supplementalIconOnClickListener);
         } else {
-            listItem.setSupplementalEmptyIcon(true);
-            listItem.setSupplementalIconListener(null);
+            carVolumeItem.setSupplementalIcon(/* drawable= */ null,
+                    /* showSupplementalIconDivider= */ false);
         }
 
-        mVolumeLineItems.add(listItem);
-        volumeItem.listItem = listItem;
+        mCarVolumeLineItems.add(carVolumeItem);
+        volumeItem.carVolumeItem = carVolumeItem;
         volumeItem.progress = progress;
-        return listItem;
+        return carVolumeItem;
     }
 
-    private VolumeItem findVolumeItem(SeekbarListItem targetItem) {
+    private VolumeItem findVolumeItem(CarVolumeItem targetItem) {
         for (int i = 0; i < mVolumeItems.size(); ++i) {
             VolumeItem volumeItem = mVolumeItems.valueAt(i);
-            if (volumeItem.listItem == targetItem) {
+            if (volumeItem.carVolumeItem == targetItem) {
                 return volumeItem;
             }
         }
@@ -463,7 +456,7 @@
 
     private void cleanupAudioManager() {
         mCarAudioManager.unregisterCarVolumeCallback(mVolumeChangeCallback);
-        mVolumeLineItems.clear();
+        mCarVolumeLineItems.clear();
         mCarAudioManager = null;
     }
 
@@ -474,8 +467,9 @@
 
         private int rank;
         private boolean defaultItem = false;
-        private @DrawableRes int icon;
-        private SeekbarListItem listItem;
+        @DrawableRes
+        private int icon;
+        private CarVolumeItem carVolumeItem;
         private int progress;
     }
 
@@ -554,9 +548,9 @@
                 // Adding the items which are not coming from the default item.
                 VolumeItem volumeItem = mAvailableVolumeItems.get(groupId);
                 if (volumeItem.defaultItem) {
-                    updateDefaultVolumeItem(volumeItem.listItem);
+                    updateDefaultVolumeItem(volumeItem.carVolumeItem);
                 } else {
-                    addSeekbarListItem(volumeItem, groupId, 0, null);
+                    addCarVolumeListItem(volumeItem, groupId, 0, null);
                 }
             }
             inAnimator = AnimatorInflater.loadAnimator(
@@ -564,14 +558,14 @@
 
         } else {
             // Only keeping the default stream if it is not expended.
-            Iterator itr = mVolumeLineItems.iterator();
+            Iterator itr = mCarVolumeLineItems.iterator();
             while (itr.hasNext()) {
-                SeekbarListItem seekbarListItem = (SeekbarListItem) itr.next();
-                VolumeItem volumeItem = findVolumeItem(seekbarListItem);
+                CarVolumeItem carVolumeItem = (CarVolumeItem) itr.next();
+                VolumeItem volumeItem = findVolumeItem(carVolumeItem);
                 if (!volumeItem.defaultItem) {
                     itr.remove();
                 } else {
-                    updateDefaultVolumeItem(seekbarListItem);
+                    updateDefaultVolumeItem(carVolumeItem);
                 }
             }
             inAnimator = AnimatorInflater.loadAnimator(
@@ -590,22 +584,22 @@
         }
         animators.setTarget(mExpandIcon);
         animators.start();
-        mPagedListAdapter.notifyDataSetChanged();
+        mVolumeItemsAdapter.notifyDataSetChanged();
     }
 
-    private void updateDefaultVolumeItem(SeekbarListItem seekbarListItem){
-        VolumeItem volumeItem = findVolumeItem(seekbarListItem);
+    private void updateDefaultVolumeItem(CarVolumeItem carVolumeItem) {
+        VolumeItem volumeItem = findVolumeItem(carVolumeItem);
 
         // When volume dialog is expanded or collapsed the default list item is never
         // reset. Whereas all other list items are removed when the dialog is collapsed and then
-        // added when the dialog is expanded using {@link CarVolumeDialogImpl#addSeekbarListItem}.
+        // added when the dialog is expanded using {@link CarVolumeDialogImpl#addCarVolumeListItem}.
         // This sets the progressbar and the tint color of icons for all items other than default
         // if they were changed. For default list item it should be done manually here.
         int color = mContext.getResources().getColor(R.color.car_volume_dialog_tint);
         Drawable primaryIcon = mContext.getResources().getDrawable(volumeItem.icon);
         primaryIcon.mutate().setTint(color);
-        volumeItem.listItem.setPrimaryActionIcon(primaryIcon);
-        volumeItem.listItem.setProgress(volumeItem.progress);
+        volumeItem.carVolumeItem.setPrimaryIcon(primaryIcon);
+        volumeItem.carVolumeItem.setProgress(volumeItem.progress);
     }
 
     private final class VolumeSeekBarChangeListener implements OnSeekBarChangeListener {
@@ -646,4 +640,4 @@
         public void onStopTrackingTouch(SeekBar seekBar) {
         }
     }
-}
\ No newline at end of file
+}
diff --git a/packages/CarSystemUI/src/com/android/systemui/volume/CarVolumeItem.java b/packages/CarSystemUI/src/com/android/systemui/volume/CarVolumeItem.java
new file mode 100644
index 0000000..9613de1
--- /dev/null
+++ b/packages/CarSystemUI/src/com/android/systemui/volume/CarVolumeItem.java
@@ -0,0 +1,135 @@
+/*
+ * 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.volume;
+
+import android.graphics.drawable.Drawable;
+import android.view.View;
+import android.widget.ImageView;
+import android.widget.SeekBar;
+
+import androidx.annotation.NonNull;
+import androidx.recyclerview.widget.RecyclerView;
+
+import com.android.systemui.R;
+
+/** Holds all related data to represent a volume group. */
+public class CarVolumeItem {
+
+    private boolean mIsDirty;
+
+    private Drawable mPrimaryIcon;
+    private Drawable mSupplementalIcon;
+    private View.OnClickListener mSupplementalIconOnClickListener;
+    private boolean mShowSupplementalIconDivider;
+
+    private int mMax;
+    private int mProgress;
+    private SeekBar.OnSeekBarChangeListener mOnSeekBarChangeListener;
+
+    public CarVolumeItem() {
+        mIsDirty = true;
+    }
+
+    /**
+     * Called when {@link CarVolumeItem} is bound to its ViewHolder.
+     */
+    void bind(CarVolumeItemViewHolder viewHolder) {
+        if (mIsDirty) {
+            viewHolder.bind(/* carVolumeItem= */ this);
+            mIsDirty = false;
+        }
+    }
+
+    /** Sets progress of seekbar. */
+    public void setProgress(int progress) {
+        mProgress = progress;
+        mIsDirty = true;
+    }
+
+    /** Sets max value of seekbar. */
+    public void setMax(int max) {
+        mMax = max;
+        mIsDirty = true;
+    }
+
+    /** Sets {@link SeekBar.OnSeekBarChangeListener}. */
+    public void setOnSeekBarChangeListener(SeekBar.OnSeekBarChangeListener listener) {
+        mOnSeekBarChangeListener = listener;
+        mIsDirty = true;
+    }
+
+    /** Sets the primary icon. */
+    public void setPrimaryIcon(Drawable drawable) {
+        mPrimaryIcon = drawable;
+        mIsDirty = true;
+    }
+
+    /** Sets the supplemental icon and the visibility of the supplemental icon divider. */
+    public void setSupplementalIcon(Drawable drawable, boolean showSupplementalIconDivider) {
+        mSupplementalIcon = drawable;
+        mShowSupplementalIconDivider = showSupplementalIconDivider;
+        mIsDirty = true;
+    }
+
+    /** Sets {@code OnClickListener} for the supplemental icon. */
+    public void setSupplementalIconListener(View.OnClickListener listener) {
+        mSupplementalIconOnClickListener = listener;
+        mIsDirty = true;
+    }
+
+    /** Defines the view holder which shows the information held by {@link CarVolumeItem}. */
+    public static class CarVolumeItemViewHolder extends RecyclerView.ViewHolder {
+
+        private SeekBar mSeekBar;
+        private ImageView mPrimaryIcon;
+        private View mSupplementalIconDivider;
+        private ImageView mSupplementalIcon;
+
+        public CarVolumeItemViewHolder(@NonNull View itemView) {
+            super(itemView);
+
+            mSeekBar = itemView.findViewById(R.id.seek_bar);
+            mPrimaryIcon = itemView.findViewById(R.id.primary_icon);
+            mSupplementalIcon = itemView.findViewById(R.id.supplemental_icon);
+            mSupplementalIconDivider = itemView.findViewById(R.id.supplemental_icon_divider);
+        }
+
+        /**
+         * Binds {@link CarVolumeItem} to the {@link CarVolumeItemViewHolder}.
+         */
+        void bind(CarVolumeItem carVolumeItem) {
+            // Progress bar
+            mSeekBar.setMax(carVolumeItem.mMax);
+            mSeekBar.setProgress(carVolumeItem.mProgress);
+            mSeekBar.setOnSeekBarChangeListener(carVolumeItem.mOnSeekBarChangeListener);
+
+            // Primary icon
+            mPrimaryIcon.setVisibility(View.VISIBLE);
+            mPrimaryIcon.setImageDrawable(carVolumeItem.mPrimaryIcon);
+
+            // Supplemental icon
+            mSupplementalIcon.setVisibility(View.VISIBLE);
+            mSupplementalIconDivider.setVisibility(
+                    carVolumeItem.mShowSupplementalIconDivider ? View.VISIBLE : View.INVISIBLE);
+            mSupplementalIcon.setImageDrawable(carVolumeItem.mSupplementalIcon);
+            mSupplementalIcon.setOnClickListener(
+                    carVolumeItem.mSupplementalIconOnClickListener);
+            mSupplementalIcon.setClickable(
+                    carVolumeItem.mSupplementalIconOnClickListener != null);
+        }
+    }
+}
diff --git a/packages/CarSystemUI/src/com/android/systemui/volume/CarVolumeItemAdapter.java b/packages/CarSystemUI/src/com/android/systemui/volume/CarVolumeItemAdapter.java
new file mode 100644
index 0000000..5c1f817
--- /dev/null
+++ b/packages/CarSystemUI/src/com/android/systemui/volume/CarVolumeItemAdapter.java
@@ -0,0 +1,59 @@
+/*
+ * 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.volume;
+
+import android.content.Context;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+
+import androidx.recyclerview.widget.RecyclerView;
+
+import com.android.systemui.R;
+
+import java.util.List;
+
+/** The {@link RecyclerView.Adapter} to show the volume items in the sysUI volume dialog. */
+public class CarVolumeItemAdapter extends
+        RecyclerView.Adapter<CarVolumeItem.CarVolumeItemViewHolder> {
+
+    private final Context mContext;
+    private final List<CarVolumeItem> mItems;
+
+    public CarVolumeItemAdapter(Context context, List<CarVolumeItem> items) {
+        mContext = context;
+        mItems = items;
+    }
+
+    @Override
+    public CarVolumeItem.CarVolumeItemViewHolder onCreateViewHolder(ViewGroup parent,
+            int viewType) {
+        LayoutInflater inflater = LayoutInflater.from(mContext);
+        View view = inflater.inflate(R.layout.car_volume_item, parent, false);
+        return new CarVolumeItem.CarVolumeItemViewHolder(view);
+    }
+
+    @Override
+    public void onBindViewHolder(CarVolumeItem.CarVolumeItemViewHolder holder, int position) {
+        mItems.get(position).bind(holder);
+    }
+
+    @Override
+    public int getItemCount() {
+        return mItems.size();
+    }
+}
diff --git a/packages/NetworkStack/Android.bp b/packages/NetworkStack/Android.bp
index 190247a..8872147 100644
--- a/packages/NetworkStack/Android.bp
+++ b/packages/NetworkStack/Android.bp
@@ -25,6 +25,7 @@
         ":services-networkstack-shared-srcs",
     ],
     static_libs: [
+        "ipmemorystore-client",
         "netd_aidl_interface-java",
         "networkstack-aidl-interfaces-java",
         "datastallprotosnano",
diff --git a/packages/NetworkStack/jarjar-rules-shared.txt b/packages/NetworkStack/jarjar-rules-shared.txt
index a8c712a..7346b1a 100644
--- a/packages/NetworkStack/jarjar-rules-shared.txt
+++ b/packages/NetworkStack/jarjar-rules-shared.txt
@@ -8,12 +8,3 @@
 rule android.net.DhcpResultsParcelable* @0
 rule android.net.DhcpResults* android.net.networkstack.DhcpResults@1
 rule android.net.LocalLog* android.net.networkstack.LocalLog@1
-
-# TODO: remove from framework dependencies, then remove here
-rule android.net.InterfaceConfigurationParcel* android.net.networkstack.InterfaceConfigurationParcel@1
-rule android.net.TetherStatsParcel* android.net.networkstack.TetherStatsParcel@1
-
-# Used by UidRange, which is used by framework classes such as NetworkCapabilities.
-rule android.net.UidRangeParcel* android.net.networkstack.UidRangeParcel@1
-# TODO: move TcpKeepalivePacketData to services.net and delete
-rule android.net.TcpKeepalivePacketDataParcelable* android.net.networkstack.TcpKeepalivePacketDataParcelable@1
\ No newline at end of file
diff --git a/packages/NetworkStack/src/android/net/NetworkStackIpMemoryStore.java b/packages/NetworkStack/src/android/net/NetworkStackIpMemoryStore.java
new file mode 100644
index 0000000..475f826
--- /dev/null
+++ b/packages/NetworkStack/src/android/net/NetworkStackIpMemoryStore.java
@@ -0,0 +1,42 @@
+/*
+ * 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 android.net;
+
+import android.annotation.NonNull;
+import android.content.Context;
+
+/**
+ * service used to communicate with the ip memory store service in network stack,
+ * which is running in the same module.
+ * @see com.android.server.connectivity.ipmemorystore.IpMemoryStoreService
+ * @hide
+ */
+public class NetworkStackIpMemoryStore extends IpMemoryStoreClient {
+    @NonNull private final IIpMemoryStore mService;
+
+    public NetworkStackIpMemoryStore(@NonNull final Context context,
+            @NonNull final IIpMemoryStore service) {
+        super(context);
+        mService = service;
+    }
+
+    @Override
+    @NonNull
+    protected IIpMemoryStore getService() {
+        return mService;
+    }
+}
diff --git a/packages/NetworkStack/src/android/net/dhcp/DhcpServingParams.java b/packages/NetworkStack/src/android/net/dhcp/DhcpServingParams.java
index 3cd2aa4..230b693 100644
--- a/packages/NetworkStack/src/android/net/dhcp/DhcpServingParams.java
+++ b/packages/NetworkStack/src/android/net/dhcp/DhcpServingParams.java
@@ -329,7 +329,7 @@
             if (mLinkMtu != MTU_UNSET && (mLinkMtu < IPV4_MIN_MTU || mLinkMtu > IPV4_MAX_MTU)) {
                 throw new InvalidParameterException("Invalid link MTU: " + mLinkMtu);
             }
-            if (!mServerAddr.isIPv4()) {
+            if (!mServerAddr.isIpv4()) {
                 throw new InvalidParameterException("serverAddr must be IPv4");
             }
             if (mServerAddr.getPrefixLength() < MIN_PREFIX_LENGTH
diff --git a/packages/NetworkStack/src/android/net/ip/IpClient.java b/packages/NetworkStack/src/android/net/ip/IpClient.java
index 7c7cdbd..61dc966 100644
--- a/packages/NetworkStack/src/android/net/ip/IpClient.java
+++ b/packages/NetworkStack/src/android/net/ip/IpClient.java
@@ -29,6 +29,7 @@
 import android.net.IpPrefix;
 import android.net.LinkAddress;
 import android.net.LinkProperties;
+import android.net.NetworkStackIpMemoryStore;
 import android.net.ProvisioningConfigurationParcelable;
 import android.net.ProxyInfo;
 import android.net.RouteInfo;
@@ -61,6 +62,7 @@
 import com.android.internal.util.StateMachine;
 import com.android.internal.util.WakeupMessage;
 import com.android.server.NetworkObserverRegistry;
+import com.android.server.NetworkStackService.NetworkStackServiceManager;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
@@ -100,6 +102,7 @@
     // One holds StateMachine logs and the other connectivity packet logs.
     private static final ConcurrentHashMap<String, SharedLog> sSmLogs = new ConcurrentHashMap<>();
     private static final ConcurrentHashMap<String, LocalLog> sPktLogs = new ConcurrentHashMap<>();
+    private final NetworkStackIpMemoryStore mIpMemoryStore;
 
     /**
      * Dump all state machine and connectivity packet logs to the specified writer.
@@ -388,13 +391,14 @@
     }
 
     public IpClient(Context context, String ifName, IIpClientCallbacks callback,
-            NetworkObserverRegistry observerRegistry) {
-        this(context, ifName, callback, observerRegistry, new Dependencies());
+            NetworkObserverRegistry observerRegistry, NetworkStackServiceManager nssManager) {
+        this(context, ifName, callback, observerRegistry, nssManager, new Dependencies());
     }
 
     @VisibleForTesting
     IpClient(Context context, String ifName, IIpClientCallbacks callback,
-            NetworkObserverRegistry observerRegistry, Dependencies deps) {
+            NetworkObserverRegistry observerRegistry, NetworkStackServiceManager nssManager,
+            Dependencies deps) {
         super(IpClient.class.getSimpleName() + "." + ifName);
         Preconditions.checkNotNull(ifName);
         Preconditions.checkNotNull(callback);
@@ -408,6 +412,8 @@
         mShutdownLatch = new CountDownLatch(1);
         mCm = mContext.getSystemService(ConnectivityManager.class);
         mObserverRegistry = observerRegistry;
+        mIpMemoryStore =
+                new NetworkStackIpMemoryStore(context, nssManager.getIpMemoryStoreService());
 
         sSmLogs.putIfAbsent(mInterfaceName, new SharedLog(MAX_LOG_RECORDS, mTag));
         mLog = sSmLogs.get(mInterfaceName);
@@ -828,7 +834,7 @@
     static boolean isProvisioned(LinkProperties lp, InitialConfiguration config) {
         // For historical reasons, we should connect even if all we have is
         // an IPv4 address and nothing else.
-        if (lp.hasIPv4Address() || lp.isProvisioned()) {
+        if (lp.hasIpv4Address() || lp.isProvisioned()) {
             return true;
         }
         if (config == null) {
@@ -872,9 +878,9 @@
             delta = PROV_CHANGE_LOST_PROVISIONING;
         }
 
-        final boolean lostIPv6 = oldLp.isIPv6Provisioned() && !newLp.isIPv6Provisioned();
-        final boolean lostIPv4Address = oldLp.hasIPv4Address() && !newLp.hasIPv4Address();
-        final boolean lostIPv6Router = oldLp.hasIPv6DefaultRoute() && !newLp.hasIPv6DefaultRoute();
+        final boolean lostIPv6 = oldLp.isIpv6Provisioned() && !newLp.isIpv6Provisioned();
+        final boolean lostIPv4Address = oldLp.hasIpv4Address() && !newLp.hasIpv4Address();
+        final boolean lostIPv6Router = oldLp.hasIpv6DefaultRoute() && !newLp.hasIpv6DefaultRoute();
 
         // If bad wifi avoidance is disabled, then ignore IPv6 loss of
         // provisioning. Otherwise, when a hotspot that loses Internet
@@ -914,7 +920,7 @@
         // If the previous link properties had a global IPv6 address and an
         // IPv6 default route then also consider the loss of that default route
         // to be a loss of provisioning. See b/27962810.
-        if (oldLp.hasGlobalIPv6Address() && (lostIPv6Router && !ignoreIPv6ProvisioningLoss)) {
+        if (oldLp.hasGlobalIpv6Address() && (lostIPv6Router && !ignoreIPv6ProvisioningLoss)) {
             delta = PROV_CHANGE_LOST_PROVISIONING;
         }
 
@@ -1150,7 +1156,7 @@
 
     private boolean applyInitialConfig(InitialConfiguration config) {
         // TODO: also support specifying a static IPv4 configuration in InitialConfiguration.
-        for (LinkAddress addr : findAll(config.ipAddresses, LinkAddress::isIPv6)) {
+        for (LinkAddress addr : findAll(config.ipAddresses, LinkAddress::isIpv6)) {
             if (!mInterfaceCtrl.addAddress(addr)) return false;
         }
 
@@ -1368,7 +1374,7 @@
         }
 
         private boolean readyToProceed() {
-            return (!mLinkProperties.hasIPv4Address() && !mLinkProperties.hasGlobalIPv6Address());
+            return (!mLinkProperties.hasIpv4Address() && !mLinkProperties.hasGlobalIpv6Address());
         }
     }
 
diff --git a/packages/NetworkStack/src/android/net/ip/IpReachabilityMonitor.java b/packages/NetworkStack/src/android/net/ip/IpReachabilityMonitor.java
index 76a0338..e73cba6 100644
--- a/packages/NetworkStack/src/android/net/ip/IpReachabilityMonitor.java
+++ b/packages/NetworkStack/src/android/net/ip/IpReachabilityMonitor.java
@@ -316,8 +316,8 @@
         }
 
         final boolean lostProvisioning =
-                (mLinkProperties.isIPv4Provisioned() && !whatIfLp.isIPv4Provisioned())
-                || (mLinkProperties.isIPv6Provisioned() && !whatIfLp.isIPv6Provisioned());
+                (mLinkProperties.isIpv4Provisioned() && !whatIfLp.isIpv4Provisioned())
+                || (mLinkProperties.isIpv6Provisioned() && !whatIfLp.isIpv6Provisioned());
 
         if (lostProvisioning) {
             final String logMsg = "FAILURE: LOST_PROVISIONING, " + event;
diff --git a/packages/NetworkStack/src/com/android/server/NetworkStackService.java b/packages/NetworkStack/src/com/android/server/NetworkStackService.java
index e7c8e85..19e9108 100644
--- a/packages/NetworkStack/src/com/android/server/NetworkStackService.java
+++ b/packages/NetworkStack/src/com/android/server/NetworkStackService.java
@@ -29,6 +29,8 @@
 import android.content.Context;
 import android.content.Intent;
 import android.net.ConnectivityManager;
+import android.net.IIpMemoryStore;
+import android.net.IIpMemoryStoreCallbacks;
 import android.net.INetd;
 import android.net.INetworkMonitor;
 import android.net.INetworkMonitorCallbacks;
@@ -49,6 +51,7 @@
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.util.IndentingPrintWriter;
 import com.android.server.connectivity.NetworkMonitor;
+import com.android.server.connectivity.ipmemorystore.IpMemoryStoreService;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
@@ -86,7 +89,19 @@
         return makeConnector(this);
     }
 
-    private static class NetworkStackConnector extends INetworkStackConnector.Stub {
+    /**
+     * An interface for internal clients of the network stack service that can return
+     * or create inline instances of the service it manages.
+     */
+    public interface NetworkStackServiceManager {
+        /**
+         * Get an instance of the IpMemoryStoreService.
+         */
+        IIpMemoryStore getIpMemoryStoreService();
+    }
+
+    private static class NetworkStackConnector extends INetworkStackConnector.Stub
+            implements NetworkStackServiceManager {
         private static final int NUM_VALIDATION_LOG_LINES = 20;
         private final Context mContext;
         private final INetd mNetd;
@@ -94,6 +109,7 @@
         private final ConnectivityManager mCm;
         @GuardedBy("mIpClients")
         private final ArrayList<WeakReference<IpClient>> mIpClients = new ArrayList<>();
+        private final IpMemoryStoreService mIpMemoryStoreService;
 
         private static final int MAX_VALIDATION_LOGS = 10;
         @GuardedBy("mValidationLogs")
@@ -116,6 +132,7 @@
                     (IBinder) context.getSystemService(Context.NETD_SERVICE));
             mObserverRegistry = new NetworkObserverRegistry();
             mCm = context.getSystemService(ConnectivityManager.class);
+            mIpMemoryStoreService = new IpMemoryStoreService(context);
 
             try {
                 mObserverRegistry.register(mNetd);
@@ -159,7 +176,7 @@
 
         @Override
         public void makeIpClient(String ifName, IIpClientCallbacks cb) throws RemoteException {
-            final IpClient ipClient = new IpClient(mContext, ifName, cb, mObserverRegistry);
+            final IpClient ipClient = new IpClient(mContext, ifName, cb, mObserverRegistry, this);
 
             synchronized (mIpClients) {
                 final Iterator<WeakReference<IpClient>> it = mIpClients.iterator();
@@ -176,6 +193,17 @@
         }
 
         @Override
+        public IIpMemoryStore getIpMemoryStoreService() {
+            return mIpMemoryStoreService;
+        }
+
+        @Override
+        public void fetchIpMemoryStore(@NonNull final IIpMemoryStoreCallbacks cb)
+                throws RemoteException {
+            cb.onIpMemoryStoreFetched(mIpMemoryStoreService);
+        }
+
+        @Override
         protected void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter fout,
                 @Nullable String[] args) {
             checkDumpPermission();
@@ -249,9 +277,9 @@
         }
 
         @Override
-        public void notifyAcceptPartialConnectivity() {
+        public void setAcceptPartialConnectivity() {
             checkNetworkStackCallingPermission();
-            mNm.notifyAcceptPartialConnectivity();
+            mNm.setAcceptPartialConnectivity();
         }
 
         @Override
diff --git a/packages/NetworkStack/src/com/android/server/connectivity/NetworkMonitor.java b/packages/NetworkStack/src/com/android/server/connectivity/NetworkMonitor.java
index b238ae4..73b203c 100644
--- a/packages/NetworkStack/src/com/android/server/connectivity/NetworkMonitor.java
+++ b/packages/NetworkStack/src/com/android/server/connectivity/NetworkMonitor.java
@@ -319,7 +319,8 @@
     private final DnsStallDetector mDnsStallDetector;
     private long mLastProbeTime;
     // Set to true if data stall is suspected and reset to false after metrics are sent to statsd.
-    private boolean mCollectDataStallMetrics = false;
+    private boolean mCollectDataStallMetrics;
+    private boolean mAcceptPartialConnectivity;
 
     public NetworkMonitor(Context context, INetworkMonitorCallbacks cb, Network network,
             SharedLog validationLog) {
@@ -386,10 +387,11 @@
     }
 
     /**
-     * ConnectivityService notifies NetworkMonitor that the user accepts partial connectivity and
-     * NetworkMonitor should ignore the https probe.
+     * ConnectivityService notifies NetworkMonitor that the user already accepted partial
+     * connectivity previously, so NetworkMonitor can validate the network even if it has partial
+     * connectivity.
      */
-    public void notifyAcceptPartialConnectivity() {
+    public void setAcceptPartialConnectivity() {
         sendMessage(EVENT_ACCEPT_PARTIAL_CONNECTIVITY);
     }
 
@@ -651,9 +653,11 @@
                 case EVENT_DNS_NOTIFICATION:
                     mDnsStallDetector.accumulateConsecutiveDnsTimeoutCount(message.arg1);
                     break;
+                // Set mAcceptPartialConnectivity to true and if network start evaluating or
+                // re-evaluating and get the result of partial connectivity, ProbingState will
+                // disable HTTPS probe and transition to EvaluatingPrivateDnsState.
                 case EVENT_ACCEPT_PARTIAL_CONNECTIVITY:
-                    mUseHttps = false;
-                    transitionTo(mEvaluatingPrivateDnsState);
+                    mAcceptPartialConnectivity = true;
                     break;
                 default:
                     break;
@@ -849,6 +853,14 @@
                     // ignore any re-evaluation requests. After, restart the
                     // evaluation process via EvaluatingState#enter.
                     return (mEvaluateAttempts < IGNORE_REEVALUATE_ATTEMPTS) ? HANDLED : NOT_HANDLED;
+                // Disable HTTPS probe and transition to EvaluatingPrivateDnsState because:
+                // 1. Network is connected and finish the network validation.
+                // 2. NetworkMonitor detects network is partial connectivity and user accepts it.
+                case EVENT_ACCEPT_PARTIAL_CONNECTIVITY:
+                    mAcceptPartialConnectivity = true;
+                    mUseHttps = false;
+                    transitionTo(mEvaluatingPrivateDnsState);
+                    return HANDLED;
                 default:
                     return NOT_HANDLED;
             }
@@ -1081,7 +1093,12 @@
                         logNetworkEvent(NetworkEvent.NETWORK_PARTIAL_CONNECTIVITY);
                         notifyNetworkTested(NETWORK_TEST_RESULT_PARTIAL_CONNECTIVITY,
                                 probeResult.redirectUrl);
-                        transitionTo(mWaitingForNextProbeState);
+                        if (mAcceptPartialConnectivity) {
+                            mUseHttps = false;
+                            transitionTo(mEvaluatingPrivateDnsState);
+                        } else {
+                            transitionTo(mWaitingForNextProbeState);
+                        }
                     } else {
                         logNetworkEvent(NetworkEvent.NETWORK_VALIDATION_FAILED);
                         notifyNetworkTested(NETWORK_TEST_RESULT_INVALID, probeResult.redirectUrl);
@@ -1615,12 +1632,12 @@
                 return;
             }
             // See if the data sub is registered for PS services on cell.
-            final NetworkRegistrationInfo nrs = dataSs.getNetworkRegistrationInfo(
+            final NetworkRegistrationInfo nri = dataSs.getNetworkRegistrationInfo(
                     NetworkRegistrationInfo.DOMAIN_PS,
                     AccessNetworkConstants.TRANSPORT_TYPE_WWAN);
             latencyBroadcast.putExtra(
                     NetworkMonitorUtils.EXTRA_CELL_ID,
-                    nrs == null ? null : nrs.getCellIdentity());
+                    nri == null ? null : nri.getCellIdentity());
             latencyBroadcast.putExtra(NetworkMonitorUtils.EXTRA_CONNECTIVITY_TYPE, TYPE_MOBILE);
         } else {
             return;
diff --git a/services/ipmemorystore/java/com/android/server/net/ipmemorystore/IpMemoryStoreDatabase.java b/packages/NetworkStack/src/com/android/server/connectivity/ipmemorystore/IpMemoryStoreDatabase.java
similarity index 99%
rename from services/ipmemorystore/java/com/android/server/net/ipmemorystore/IpMemoryStoreDatabase.java
rename to packages/NetworkStack/src/com/android/server/connectivity/ipmemorystore/IpMemoryStoreDatabase.java
index bbecc63..4d4ceed 100644
--- a/services/ipmemorystore/java/com/android/server/net/ipmemorystore/IpMemoryStoreDatabase.java
+++ b/packages/NetworkStack/src/com/android/server/connectivity/ipmemorystore/IpMemoryStoreDatabase.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.server.net.ipmemorystore;
+package com.android.server.connectivity.ipmemorystore;
 
 import static android.net.shared.Inet4AddressUtils.inet4AddressToIntHTH;
 import static android.net.shared.Inet4AddressUtils.intToInet4AddressHTH;
diff --git a/services/ipmemorystore/java/com/android/server/net/ipmemorystore/IpMemoryStoreService.java b/packages/NetworkStack/src/com/android/server/connectivity/ipmemorystore/IpMemoryStoreService.java
similarity index 98%
rename from services/ipmemorystore/java/com/android/server/net/ipmemorystore/IpMemoryStoreService.java
rename to packages/NetworkStack/src/com/android/server/connectivity/ipmemorystore/IpMemoryStoreService.java
index d43dc6a..f801b35 100644
--- a/services/ipmemorystore/java/com/android/server/net/ipmemorystore/IpMemoryStoreService.java
+++ b/packages/NetworkStack/src/com/android/server/connectivity/ipmemorystore/IpMemoryStoreService.java
@@ -14,14 +14,14 @@
  * limitations under the License.
  */
 
-package com.android.server.net.ipmemorystore;
+package com.android.server.connectivity.ipmemorystore;
 
 import static android.net.ipmemorystore.Status.ERROR_DATABASE_CANNOT_BE_OPENED;
 import static android.net.ipmemorystore.Status.ERROR_GENERIC;
 import static android.net.ipmemorystore.Status.ERROR_ILLEGAL_ARGUMENT;
 import static android.net.ipmemorystore.Status.SUCCESS;
 
-import static com.android.server.net.ipmemorystore.IpMemoryStoreDatabase.EXPIRY_ERROR;
+import static com.android.server.connectivity.ipmemorystore.IpMemoryStoreDatabase.EXPIRY_ERROR;
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
@@ -40,7 +40,6 @@
 import android.net.ipmemorystore.SameL3NetworkResponse;
 import android.net.ipmemorystore.Status;
 import android.net.ipmemorystore.StatusParcelable;
-import android.net.ipmemorystore.Utils;
 import android.os.RemoteException;
 import android.util.Log;
 
diff --git a/services/ipmemorystore/java/com/android/server/net/ipmemorystore/RelevanceUtils.java b/packages/NetworkStack/src/com/android/server/connectivity/ipmemorystore/RelevanceUtils.java
similarity index 99%
rename from services/ipmemorystore/java/com/android/server/net/ipmemorystore/RelevanceUtils.java
rename to packages/NetworkStack/src/com/android/server/connectivity/ipmemorystore/RelevanceUtils.java
index aa45400..38d5544 100644
--- a/services/ipmemorystore/java/com/android/server/net/ipmemorystore/RelevanceUtils.java
+++ b/packages/NetworkStack/src/com/android/server/connectivity/ipmemorystore/RelevanceUtils.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.server.net.ipmemorystore;
+package com.android.server.connectivity.ipmemorystore;
 
 import com.android.internal.annotations.VisibleForTesting;
 
diff --git a/core/java/android/net/ipmemorystore/Utils.java b/packages/NetworkStack/src/com/android/server/connectivity/ipmemorystore/Utils.java
similarity index 94%
rename from core/java/android/net/ipmemorystore/Utils.java
rename to packages/NetworkStack/src/com/android/server/connectivity/ipmemorystore/Utils.java
index b361aca..9cbf490 100644
--- a/core/java/android/net/ipmemorystore/Utils.java
+++ b/packages/NetworkStack/src/com/android/server/connectivity/ipmemorystore/Utils.java
@@ -14,10 +14,11 @@
  * limitations under the License.
  */
 
-package android.net.ipmemorystore;
+package com.android.server.connectivity.ipmemorystore;
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.net.ipmemorystore.Blob;
 
 /** {@hide} */
 public class Utils {
diff --git a/packages/NetworkStack/tests/src/android/net/ip/IpClientTest.java b/packages/NetworkStack/tests/src/android/net/ip/IpClientTest.java
index 4536c47..eee12d6 100644
--- a/packages/NetworkStack/tests/src/android/net/ip/IpClientTest.java
+++ b/packages/NetworkStack/tests/src/android/net/ip/IpClientTest.java
@@ -51,6 +51,7 @@
 import com.android.internal.R;
 import com.android.server.NetworkObserver;
 import com.android.server.NetworkObserverRegistry;
+import com.android.server.NetworkStackService;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -90,6 +91,7 @@
     @Mock private AlarmManager mAlarm;
     @Mock private IpClient.Dependencies mDependencies;
     @Mock private ContentResolver mContentResolver;
+    @Mock private NetworkStackService.NetworkStackServiceManager mNetworkStackServiceManager;
 
     private NetworkObserver mObserver;
     private InterfaceParams mIfParams;
@@ -118,7 +120,8 @@
 
     private IpClient makeIpClient(String ifname) throws Exception {
         setTestInterfaceParams(ifname);
-        final IpClient ipc = new IpClient(mContext, ifname, mCb, mObserverRegistry, mDependencies);
+        final IpClient ipc = new IpClient(mContext, ifname, mCb, mObserverRegistry,
+                mNetworkStackServiceManager, mDependencies);
         verify(mNetd, timeout(TEST_TIMEOUT_MS).times(1)).interfaceSetEnableIPv6(ifname, false);
         verify(mNetd, timeout(TEST_TIMEOUT_MS).times(1)).interfaceClearAddrs(ifname);
         ArgumentCaptor<NetworkObserver> arg = ArgumentCaptor.forClass(NetworkObserver.class);
@@ -142,8 +145,8 @@
     public void testNullInterfaceNameMostDefinitelyThrows() throws Exception {
         setTestInterfaceParams(null);
         try {
-            final IpClient ipc = new IpClient(
-                    mContext, null, mCb, mObserverRegistry, mDependencies);
+            final IpClient ipc = new IpClient(mContext, null, mCb, mObserverRegistry,
+                    mNetworkStackServiceManager, mDependencies);
             ipc.shutdown();
             fail();
         } catch (NullPointerException npe) {
@@ -156,8 +159,8 @@
         final String ifname = "lo";
         setTestInterfaceParams(ifname);
         try {
-            final IpClient ipc = new IpClient(
-                    mContext, ifname, null, mObserverRegistry, mDependencies);
+            final IpClient ipc = new IpClient(mContext, ifname, null, mObserverRegistry,
+                    mNetworkStackServiceManager, mDependencies);
             ipc.shutdown();
             fail();
         } catch (NullPointerException npe) {
@@ -168,16 +171,16 @@
     @Test
     public void testInvalidInterfaceDoesNotThrow() throws Exception {
         setTestInterfaceParams(TEST_IFNAME);
-        final IpClient ipc = new IpClient(
-                mContext, TEST_IFNAME, mCb, mObserverRegistry, mDependencies);
+        final IpClient ipc = new IpClient(mContext, TEST_IFNAME, mCb, mObserverRegistry,
+                mNetworkStackServiceManager, mDependencies);
         ipc.shutdown();
     }
 
     @Test
     public void testInterfaceNotFoundFailsImmediately() throws Exception {
         setTestInterfaceParams(null);
-        final IpClient ipc = new IpClient(
-                mContext, TEST_IFNAME, mCb, mObserverRegistry, mDependencies);
+        final IpClient ipc = new IpClient(mContext, TEST_IFNAME, mCb, mObserverRegistry,
+                mNetworkStackServiceManager, mDependencies);
         ipc.startProvisioning(new ProvisioningConfiguration());
         verify(mCb, times(1)).onProvisioningFailure(any());
         ipc.shutdown();
diff --git a/packages/NetworkStack/tests/src/com/android/server/connectivity/NetworkMonitorTest.java b/packages/NetworkStack/tests/src/com/android/server/connectivity/NetworkMonitorTest.java
index d93aef2..d732c4e 100644
--- a/packages/NetworkStack/tests/src/com/android/server/connectivity/NetworkMonitorTest.java
+++ b/packages/NetworkStack/tests/src/com/android/server/connectivity/NetworkMonitorTest.java
@@ -583,7 +583,7 @@
         verify(mCallbacks, timeout(HANDLER_TIMEOUT_MS).times(1))
                 .notifyNetworkTested(NETWORK_TEST_RESULT_PARTIAL_CONNECTIVITY, null);
 
-        nm.notifyAcceptPartialConnectivity();
+        nm.setAcceptPartialConnectivity();
         verify(mCallbacks, timeout(HANDLER_TIMEOUT_MS).times(1))
                 .notifyNetworkTested(NETWORK_TEST_RESULT_VALID, null);
     }
diff --git a/tests/net/java/com/android/server/net/ipmemorystore/IpMemoryStoreServiceTest.java b/packages/NetworkStack/tests/src/com/android/server/connectivity/ipmemorystore/IpMemoryStoreServiceTest.java
similarity index 99%
rename from tests/net/java/com/android/server/net/ipmemorystore/IpMemoryStoreServiceTest.java
rename to packages/NetworkStack/tests/src/com/android/server/connectivity/ipmemorystore/IpMemoryStoreServiceTest.java
index be10680..d0e58b8 100644
--- a/tests/net/java/com/android/server/net/ipmemorystore/IpMemoryStoreServiceTest.java
+++ b/packages/NetworkStack/tests/src/com/android/server/connectivity/ipmemorystore/IpMemoryStoreServiceTest.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.server.net.ipmemorystore;
+package com.android.server.connectivity.ipmemorystore;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
diff --git a/tests/net/java/com/android/server/net/ipmemorystore/RelevanceUtilsTests.java b/packages/NetworkStack/tests/src/com/android/server/connectivity/ipmemorystore/RelevanceUtilsTests.java
similarity index 97%
rename from tests/net/java/com/android/server/net/ipmemorystore/RelevanceUtilsTests.java
rename to packages/NetworkStack/tests/src/com/android/server/connectivity/ipmemorystore/RelevanceUtilsTests.java
index 7413b91..3d3aabc 100644
--- a/tests/net/java/com/android/server/net/ipmemorystore/RelevanceUtilsTests.java
+++ b/packages/NetworkStack/tests/src/com/android/server/connectivity/ipmemorystore/RelevanceUtilsTests.java
@@ -14,9 +14,9 @@
  * limitations under the License.
  */
 
-package com.android.server.net.ipmemorystore;
+package com.android.server.connectivity.ipmemorystore;
 
-import static com.android.server.net.ipmemorystore.RelevanceUtils.CAPPED_RELEVANCE;
+import static com.android.server.connectivity.ipmemorystore.RelevanceUtils.CAPPED_RELEVANCE;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
diff --git a/packages/PackageInstaller/AndroidManifest.xml b/packages/PackageInstaller/AndroidManifest.xml
index 6d2c880..62535b6 100644
--- a/packages/PackageInstaller/AndroidManifest.xml
+++ b/packages/PackageInstaller/AndroidManifest.xml
@@ -92,6 +92,7 @@
 
         <activity android:name=".UninstallerActivity"
                 android:configChanges="orientation|keyboardHidden|screenSize"
+                android:theme="@style/Theme.AlertDialogActivity.NoActionBar"
                 android:excludeFromRecents="true"
                 android:noHistory="true">
             <intent-filter android:priority="1">
diff --git a/packages/PackageInstaller/res/values/themes.xml b/packages/PackageInstaller/res/values/themes.xml
index 6c8e4c5..b11d28b 100644
--- a/packages/PackageInstaller/res/values/themes.xml
+++ b/packages/PackageInstaller/res/values/themes.xml
@@ -24,4 +24,9 @@
     <style name="Theme.AlertDialogActivity"
             parent="@android:style/Theme.DeviceDefault.Light.Dialog.Alert" />
 
+    <style name="Theme.AlertDialogActivity.NoActionBar">
+        <item name="android:windowActionBar">false</item>
+        <item name="android:windowNoTitle">true</item>
+    </style>
+
 </resources>
diff --git a/packages/SettingsLib/AppPreference/res/layout/preference_app.xml b/packages/SettingsLib/AppPreference/res/layout/preference_app.xml
index b198f5a..711dad4 100644
--- a/packages/SettingsLib/AppPreference/res/layout/preference_app.xml
+++ b/packages/SettingsLib/AppPreference/res/layout/preference_app.xml
@@ -48,37 +48,32 @@
         android:paddingTop="16dp"
         android:paddingBottom="16dp">
 
-        <TextView android:id="@android:id/title"
-                  android:layout_width="wrap_content"
-                  android:layout_height="wrap_content"
-                  android:singleLine="true"
-                  android:textAppearance="?android:attr/textAppearanceListItem"
-                  android:ellipsize="marquee"
-                  android:fadingEdge="horizontal"/>
+        <TextView
+            android:id="@android:id/title"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:ellipsize="marquee"
+            android:fadingEdge="horizontal"
+            android:singleLine="true"
+            android:textAppearance="?android:attr/textAppearanceListItem"/>
 
-        <LinearLayout
-            android:id="@+id/summary_container"
+        <TextView
+            android:id="@android:id/summary"
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
-            android:visibility="gone">
-            <TextView android:id="@android:id/summary"
-                      android:layout_width="0dp"
-                      android:layout_height="wrap_content"
-                      android:layout_weight="1"
-                      android:textAppearance="?android:attr/textAppearanceSmall"
-                      android:textAlignment="viewStart"
-                      android:textColor="?android:attr/textColorSecondary"/>
+            android:textAppearance="?android:attr/textAppearanceSmall"
+            android:textColor="?android:attr/textColorSecondary"/>
 
-            <TextView android:id="@+id/appendix"
-                      android:layout_width="0dp"
-                      android:layout_height="wrap_content"
-                      android:layout_weight="1"
-                      android:textAppearance="?android:attr/textAppearanceSmall"
-                      android:textAlignment="viewEnd"
-                      android:textColor="?android:attr/textColorSecondary"
-                      android:maxLines="1"
-                      android:ellipsize="end"/>
-        </LinearLayout>
+        <TextView
+            android:id="@+id/appendix"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:ellipsize="end"
+            android:maxLines="1"
+            android:textAppearance="?android:attr/textAppearanceSmall"
+            android:textColor="?android:attr/textColorSecondary"
+            android:visibility="gone"/>
+
         <ProgressBar
             android:id="@android:id/progress"
             style="?android:attr/progressBarStyleHorizontal"
diff --git a/packages/SettingsLib/AppPreference/src/com/android/settingslib/widget/apppreference/AppPreference.java b/packages/SettingsLib/AppPreference/src/com/android/settingslib/widget/apppreference/AppPreference.java
index ab51a34..e88ac56 100644
--- a/packages/SettingsLib/AppPreference/src/com/android/settingslib/widget/apppreference/AppPreference.java
+++ b/packages/SettingsLib/AppPreference/src/com/android/settingslib/widget/apppreference/AppPreference.java
@@ -17,7 +17,6 @@
 package com.android.settingslib.widget.apppreference;
 
 import android.content.Context;
-import android.text.TextUtils;
 import android.util.AttributeSet;
 import android.view.View;
 import android.widget.ProgressBar;
@@ -52,8 +51,6 @@
     public void onBindViewHolder(PreferenceViewHolder view) {
         super.onBindViewHolder(view);
 
-        view.findViewById(R.id.summary_container)
-                .setVisibility(TextUtils.isEmpty(getSummary()) ? View.GONE : View.VISIBLE);
         final ProgressBar progress = (ProgressBar) view.findViewById(android.R.id.progress);
         if (mProgressVisible) {
             progress.setProgress(mProgress);
diff --git a/packages/SettingsLib/EntityHeaderWidgets/res/values/styles.xml b/packages/SettingsLib/EntityHeaderWidgets/res/values/styles.xml
index 0eefd4b..7db6014 100644
--- a/packages/SettingsLib/EntityHeaderWidgets/res/values/styles.xml
+++ b/packages/SettingsLib/EntityHeaderWidgets/res/values/styles.xml
@@ -31,7 +31,7 @@
     </style>
 
     <style name="AppEntitiesHeader.Text.Summary"
-           parent="@android:style/TextAppearance.Material.Body1">
+           parent="@*android:style/TextAppearance.DeviceDefault.Body1">
         <item name="android:textColor">?android:attr/textColorSecondary</item>
         <item name="android:textSize">14sp</item>
     </style>
diff --git a/packages/SettingsLib/LayoutPreference/res/layout/settings_entity_header.xml b/packages/SettingsLib/LayoutPreference/res/layout/settings_entity_header.xml
index e27ae7d..da575db 100644
--- a/packages/SettingsLib/LayoutPreference/res/layout/settings_entity_header.xml
+++ b/packages/SettingsLib/LayoutPreference/res/layout/settings_entity_header.xml
@@ -21,6 +21,8 @@
     style="@style/EntityHeader"
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
+    android:paddingStart="?android:attr/listPreferredItemPaddingStart"
+    android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
     android:orientation="horizontal">
 
     <LinearLayout
diff --git a/packages/SettingsLib/RestrictedLockUtils/src/com/android/settingslib/RestrictedLockUtils.java b/packages/SettingsLib/RestrictedLockUtils/src/com/android/settingslib/RestrictedLockUtils.java
index 8529e3e..87b5b57 100644
--- a/packages/SettingsLib/RestrictedLockUtils/src/com/android/settingslib/RestrictedLockUtils.java
+++ b/packages/SettingsLib/RestrictedLockUtils/src/com/android/settingslib/RestrictedLockUtils.java
@@ -20,6 +20,7 @@
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
+import android.content.pm.PackageManager;
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.provider.Settings;
@@ -47,7 +48,16 @@
         if (dpm == null) {
             return null;
         }
-        ComponentName adminComponent = dpm.getProfileOwnerAsUser(user);
+
+        Context userContext;
+        try {
+            userContext = context.createPackageContextAsUser(context.getPackageName(), 0, user);
+        } catch (PackageManager.NameNotFoundException e) {
+            throw new IllegalStateException(e);
+        }
+
+        ComponentName adminComponent = userContext.getSystemService(
+                DevicePolicyManager.class).getProfileOwner();
         if (adminComponent != null) {
             return new EnforcedAdmin(adminComponent, enforcedRestriction, user);
         }
diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml
index bf97d77..c6a995cb 100644
--- a/packages/SettingsLib/res/values/strings.xml
+++ b/packages/SettingsLib/res/values/strings.xml
@@ -113,6 +113,9 @@
     <!-- Summary for Connected wifi network without internet -->
     <string name="wifi_connected_no_internet">Connected, no internet</string>
 
+    <!-- Summary for connected wifi network with partial internet connectivity [CHAR LIMIT=50] -->
+    <string name="wifi_limited_connection">Limited connection</string>
+
     <!-- Wi-Fi status indicating that the current network is connected, but has no internet access. -->
     <string name="wifi_status_no_internet">No internet</string>
 
@@ -185,8 +188,12 @@
 
     <!-- Connected devices settings. Message when Bluetooth is connected and active, showing remote device status and battery level. [CHAR LIMIT=NONE] -->
     <string name="bluetooth_active_battery_level">Active, <xliff:g id="battery_level_as_percentage">%1$s</xliff:g> battery</string>
+    <!-- Connected devices settings. Message when Bluetooth is connected and active, showing remote device status and battery level for untethered headset. [CHAR LIMIT=NONE] -->
+    <string name="bluetooth_active_battery_level_untethered">Active, L: <xliff:g id="battery_level_as_percentage" example="25%">%1$s</xliff:g> battery, R: <xliff:g id="battery_level_as_percentage" example="25%">%2$s</xliff:g> battery</string>
     <!-- Connected devices settings. Message when Bluetooth is connected but not in use, showing remote device battery level. [CHAR LIMIT=NONE] -->
     <string name="bluetooth_battery_level"><xliff:g id="battery_level_as_percentage">%1$s</xliff:g> battery</string>
+    <!-- Connected devices settings. Message when Bluetooth is connected but not in use, showing remote device battery level for untethered headset. [CHAR LIMIT=NONE] -->
+    <string name="bluetooth_battery_level_untethered">L: <xliff:g id="battery_level_as_percentage" example="25%">%1$s</xliff:g> battery, R: <xliff:g id="battery_level_as_percentage" example="25%">%2$s</xliff:g> battery</string>
     <!-- Connected devices settings. Message when Bluetooth is connected and active but no battery information, showing remote device status. [CHAR LIMIT=NONE] -->
     <string name="bluetooth_active_no_battery_level">Active</string>
 
diff --git a/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java b/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java
index c9fbc7b..d4d0519 100644
--- a/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java
+++ b/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java
@@ -128,12 +128,12 @@
     // to protect access to these.
     final ArrayList<Session> mSessions = new ArrayList<Session>();
     final ArrayList<Session> mRebuildingSessions = new ArrayList<Session>();
-    final InterestingConfigChanges mInterestingConfigChanges = new InterestingConfigChanges();
+    private InterestingConfigChanges mInterestingConfigChanges = new InterestingConfigChanges();
     // Map: userid => (Map: package name => AppEntry)
     final SparseArray<HashMap<String, AppEntry>> mEntriesMap =
             new SparseArray<HashMap<String, AppEntry>>();
     final ArrayList<AppEntry> mAppEntries = new ArrayList<AppEntry>();
-    List<ApplicationInfo> mApplications = new ArrayList<ApplicationInfo>();
+    List<ApplicationInfo> mApplications = new ArrayList<>();
     long mCurId = 1;
     UUID mCurComputingSizeUuid;
     String mCurComputingSizePkg;
@@ -166,7 +166,7 @@
     /**
      * Flags to configure the session to request various types of info.
      */
-    @IntDef(prefix = { "FLAG_SESSION_" }, value = {
+    @IntDef(prefix = {"FLAG_SESSION_"}, value = {
             FLAG_SESSION_REQUEST_HOME_APP,
             FLAG_SESSION_REQUEST_ICONS,
             FLAG_SESSION_REQUEST_SIZES,
@@ -174,7 +174,13 @@
             FLAG_SESSION_REQUEST_LEANBACK_LAUNCHER
     })
     @Retention(RetentionPolicy.SOURCE)
-    public @interface SessionFlags {}
+    public @interface SessionFlags {
+    }
+
+    @VisibleForTesting
+    void setInterestingConfigChanges(InterestingConfigChanges interestingConfigChanges) {
+        mInterestingConfigChanges = interestingConfigChanges;
+    }
 
     public static final @SessionFlags int DEFAULT_SESSION_FLAGS =
             FLAG_SESSION_REQUEST_HOME_APP | FLAG_SESSION_REQUEST_ICONS |
@@ -190,6 +196,7 @@
         for (int userId : mUm.getProfileIdsWithDisabled(UserHandle.myUserId())) {
             mEntriesMap.put(userId, new HashMap<String, AppEntry>());
         }
+
         mThread = new HandlerThread("ApplicationsState.Loader",
                 Process.THREAD_PRIORITY_BACKGROUND);
         mThread.start();
@@ -256,12 +263,14 @@
             mPackageIntentReceiver = new PackageIntentReceiver();
             mPackageIntentReceiver.registerReceiver();
         }
-        mApplications = new ArrayList<ApplicationInfo>();
+
+        final List<ApplicationInfo> prevApplications = mApplications;
+        mApplications = new ArrayList<>();
         for (UserInfo user : mUm.getProfiles(UserHandle.myUserId())) {
             try {
                 // If this user is new, it needs a map created.
                 if (mEntriesMap.indexOfKey(user.id) < 0) {
-                    mEntriesMap.put(user.id, new HashMap<String, AppEntry>());
+                    mEntriesMap.put(user.id, new HashMap<>());
                 }
                 @SuppressWarnings("unchecked")
                 ParceledListSlice<ApplicationInfo> list =
@@ -279,14 +288,14 @@
             // should completely reload the app entries.
             clearEntries();
         } else {
-            for (int i=0; i<mAppEntries.size(); i++) {
+            for (int i = 0; i < mAppEntries.size(); i++) {
                 mAppEntries.get(i).sizeStale = true;
             }
         }
 
         mHaveDisabledApps = false;
         mHaveInstantApps = false;
-        for (int i=0; i<mApplications.size(); i++) {
+        for (int i = 0; i < mApplications.size(); i++) {
             final ApplicationInfo info = mApplications.get(i);
             // Need to trim out any applications that are disabled by
             // something different than the user.
@@ -312,8 +321,9 @@
                 entry.info = info;
             }
         }
-        if (mAppEntries.size() > mApplications.size()) {
-            // There are less apps now, some must have been uninstalled.
+
+        if (anyAppIsRemoved(prevApplications, mApplications)) {
+            // some apps have been uninstalled.
             clearEntries();
         }
         mCurComputingSizePkg = null;
@@ -322,6 +332,82 @@
         }
     }
 
+    /* The original design is mAppEntries.size() > mApplications.size().
+       It's correct if there is only the owner user and only one app is removed.
+       Problem 1:
+       If there is a user profile, the size of mAppEntries < mApplications is normal because
+       the number of app entries on UI (mAppEntries) should be equal to the number of apps got
+       from PMS (mApplications).
+
+       owner only case:
+       mApplications: user 0: 191
+       mAppEntries  : user 0: 191
+       total mAppEntries: 191, mApplications: 191
+       If an app is removed, cached mAppEntries: 191 , mApplications: 191 -> 190, it is detected
+       as the number of apps becomes less.
+
+       If there is a work profile, mAppEntries removes some apps that are not installed for the
+       owner user.
+
+       For example, in the following case, 6 apps are removed from mAppEntries for the owner.
+       mApplications: user 0: 197, user 10: 189 => total 386
+       mAppEntries  : user 0: 191, user 10: 189 => total 380
+       If an app is removed, cached mAppEntries: 380 , mApplications: 386 -> 385, the size of
+       mAppEntries is still not larger than mApplications, then does not clear mAppEntries.
+
+       Problem 2:
+       If remove an app and add another app outside Settings (e.g. Play Store) and back to
+       Settings, the amount of apps are not changed, it causes the entries keep the removed app.
+
+       Another case, if adding more apps than removing apps (e.g. add 2 apps and remove 1 app),
+       the final number of apps (mApplications) is even increased,
+
+       Therefore, should not only count on number of apps to determine any app is removed.
+       Compare the change of applications instead.
+    */
+    private static boolean anyAppIsRemoved(List<ApplicationInfo> prevApplications,
+            List<ApplicationInfo> applications) {
+
+        // No cache
+        if (prevApplications.size() == 0) {
+            return false;
+        }
+
+        if (applications.size() < prevApplications.size()) {
+            return true;
+        }
+
+        // build package sets of all applications <userId, HashSet of packages>
+        final HashMap<String, HashSet<String>> packageMap = new HashMap<>();
+        for (ApplicationInfo application : applications) {
+            final String userId = String.valueOf(UserHandle.getUserId(application.uid));
+
+            HashSet<String> appPackages = packageMap.get(userId);
+            if (appPackages == null) {
+                appPackages = new HashSet<>();
+                packageMap.put(userId, appPackages);
+            }
+            if (hasFlag(application.flags, ApplicationInfo.FLAG_INSTALLED)) {
+                appPackages.add(application.packageName);
+            }
+        }
+
+        // detect any previous app is removed
+        for (ApplicationInfo prevApplication : prevApplications) {
+            if (!hasFlag(prevApplication.flags, ApplicationInfo.FLAG_INSTALLED)) {
+                continue;
+            }
+            final String userId = String.valueOf(UserHandle.getUserId(prevApplication.uid));
+
+            final HashSet<String> packagesSet = packageMap.get(userId);
+            if (packagesSet == null || !packagesSet.remove(prevApplication.packageName)) {
+                return true;
+            }
+        }
+
+        return false;
+    }
+
     @VisibleForTesting
     void clearEntries() {
         for (int i = 0; i < mEntriesMap.size(); i++) {
@@ -346,7 +432,7 @@
         if (!mResumed) {
             return;
         }
-        for (int i=0; i<mSessions.size(); i++) {
+        for (int i = 0; i < mSessions.size(); i++) {
             if (mSessions.get(i).mResumed) {
                 return;
             }
@@ -449,7 +535,7 @@
         if (DEBUG_LOCKING) Log.v(TAG, "sumCacheSizes about to acquire lock...");
         synchronized (mEntriesMap) {
             if (DEBUG_LOCKING) Log.v(TAG, "-> sumCacheSizes now has lock");
-            for (int i=mAppEntries.size()-1; i>=0; i--) {
+            for (int i = mAppEntries.size() - 1; i >= 0; i--) {
                 sum += mAppEntries.get(i).cacheSize;
             }
             if (DEBUG_LOCKING) Log.v(TAG, "...sumCacheSizes releasing lock");
@@ -458,7 +544,7 @@
     }
 
     int indexOfApplicationInfoLocked(String pkgName, int userId) {
-        for (int i=mApplications.size()-1; i>=0; i--) {
+        for (int i = mApplications.size() - 1; i >= 0; i--) {
             ApplicationInfo appInfo = mApplications.get(i);
             if (appInfo.packageName.equals(pkgName)
                     && UserHandle.getUserId(appInfo.uid) == userId) {
@@ -642,7 +728,7 @@
                 return;
             }
             mActiveSessions.clear();
-            for (int i=0; i<mSessions.size(); i++) {
+            for (int i = 0; i < mSessions.size(); i++) {
                 Session s = mSessions.get(i);
                 if (s.mResumed) {
                     mActiveSessions.add(new WeakReference<>(s));
@@ -784,7 +870,7 @@
 
             ArrayList<AppEntry> filteredApps = new ArrayList<AppEntry>();
             if (DEBUG) Log.i(TAG, "Rebuilding...");
-            for (int i=0; i<apps.size(); i++) {
+            for (int i = 0; i < apps.size(); i++) {
                 AppEntry entry = apps.get(i);
                 if (entry != null && (filter == null || filter.filterApp(entry))) {
                     synchronized (mEntriesMap) {
@@ -954,7 +1040,7 @@
                 }
             }
             if (rebuildingSessions != null) {
-                for (int i=0; i<rebuildingSessions.size(); i++) {
+                for (int i = 0; i < rebuildingSessions.size(); i++) {
                     rebuildingSessions.get(i).handleRebuildList();
                 }
             }
@@ -1047,9 +1133,9 @@
                             // If we do not specify MATCH_DIRECT_BOOT_AWARE or
                             // MATCH_DIRECT_BOOT_UNAWARE, system will derive and update the flags
                             // according to the user's lock state. When the user is locked,
-                            // components
-                            // with ComponentInfo#directBootAware == false will be filtered. We should
-                            // explicitly include both direct boot aware and unaware components here.
+                            // components with ComponentInfo#directBootAware == false will be
+                            // filtered. W should explicitly include both direct boot aware and
+                            // unaware component here.
                             List<ResolveInfo> intents = mPm.queryIntentActivitiesAsUser(
                                     launchIntent,
                                     PackageManager.MATCH_DISABLED_COMPONENTS
@@ -1128,8 +1214,10 @@
                         synchronized (mEntriesMap) {
                             if (DEBUG_LOCKING) Log.v(TAG, "MSG_LOAD_SIZES acquired lock");
                             if (mCurComputingSizePkg != null) {
-                                if (DEBUG_LOCKING) Log.v(TAG,
-                                        "MSG_LOAD_SIZES releasing: currently computing");
+                                if (DEBUG_LOCKING) {
+                                    Log.v(TAG,
+                                            "MSG_LOAD_SIZES releasing: currently computing");
+                                }
                                 return;
                             }
 
@@ -1181,8 +1269,10 @@
 
                                         });
                                     }
-                                    if (DEBUG_LOCKING) Log.v(TAG,
-                                            "MSG_LOAD_SIZES releasing: now computing");
+                                    if (DEBUG_LOCKING) {
+                                        Log.v(TAG,
+                                                "MSG_LOAD_SIZES releasing: now computing");
+                                    }
                                     return;
                                 }
                             }
@@ -1255,8 +1345,10 @@
                                 entry.internalSizeStr = getSizeStr(entry.internalSize);
                                 entry.externalSize = getTotalExternalSize(stats);
                                 entry.externalSizeStr = getSizeStr(entry.externalSize);
-                                if (DEBUG) Log.i(TAG, "Set size of " + entry.label + " " + entry
-                                        + ": " + entry.sizeStr);
+                                if (DEBUG) {
+                                    Log.i(TAG, "Set size of " + entry.label + " " + entry
+                                            + ": " + entry.sizeStr);
+                                }
                                 sizeChanged = true;
                             }
                         }
@@ -1299,9 +1391,11 @@
             userFilter.addAction(Intent.ACTION_USER_REMOVED);
             mContext.registerReceiver(this, userFilter);
         }
+
         void unregisterReceiver() {
             mContext.unregisterReceiver(this);
         }
+
         @Override
         public void onReceive(Context context, Intent intent) {
             String actionStr = intent.getAction();
@@ -1354,12 +1448,19 @@
 
     public interface Callbacks {
         void onRunningStateChanged(boolean running);
+
         void onPackageListChanged();
+
         void onRebuildComplete(ArrayList<AppEntry> apps);
+
         void onPackageIconChanged();
+
         void onPackageSizeChanged(String packageName);
+
         void onAllSizesComputed();
+
         void onLauncherInfoChanged();
+
         void onLoadEntriesCompleted();
     }
 
@@ -1491,6 +1592,7 @@
      */
     public static final Comparator<AppEntry> ALPHA_COMPARATOR = new Comparator<AppEntry>() {
         private final Collator sCollator = Collator.getInstance();
+
         @Override
         public int compare(AppEntry object1, AppEntry object2) {
             int compareResult = sCollator.compare(object1.label, object2.label);
@@ -1504,6 +1606,7 @@
                     return compareResult;
                 }
             }
+
             return object1.info.uid - object2.info.uid;
         }
     };
@@ -1540,9 +1643,11 @@
 
     public interface AppFilter {
         void init();
+
         default void init(Context context) {
             init();
         }
+
         boolean filterApp(AppEntry info);
     }
 
@@ -1697,7 +1802,8 @@
         @Override
         public boolean filterApp(AppEntry entry) {
             return !AppUtils.isInstant(entry.info)
-                && hasFlag(entry.info.privateFlags, ApplicationInfo.PRIVATE_FLAG_HAS_DOMAIN_URLS);
+                    && hasFlag(entry.info.privateFlags,
+                    ApplicationInfo.PRIVATE_FLAG_HAS_DOMAIN_URLS);
         }
     };
 
@@ -1707,7 +1813,7 @@
         @Override
         public void init(Context context) {
             mHidePackageNames = context.getResources()
-                .getStringArray(R.array.config_hideWhenDisabled_packageNames);
+                    .getStringArray(R.array.config_hideWhenDisabled_packageNames);
         }
 
         @Override
@@ -1720,7 +1826,7 @@
                 if (!entry.info.enabled) {
                     return false;
                 } else if (entry.info.enabledSetting ==
-                    PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED) {
+                        PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED) {
                     return false;
                 }
             }
@@ -1798,7 +1904,7 @@
         @Override
         public boolean filterApp(AppEntry entry) {
             boolean isMusicApp;
-            synchronized(entry) {
+            synchronized (entry) {
                 isMusicApp = entry.info.category == ApplicationInfo.CATEGORY_AUDIO;
             }
             return isMusicApp;
@@ -1813,7 +1919,7 @@
         @Override
         public boolean filterApp(AppEntry entry) {
             boolean isMovieApp;
-            synchronized(entry) {
+            synchronized (entry) {
                 isMovieApp = entry.info.category == ApplicationInfo.CATEGORY_VIDEO;
             }
             return isMovieApp;
@@ -1823,7 +1929,8 @@
     public static final AppFilter FILTER_PHOTOS =
             new AppFilter() {
                 @Override
-                public void init() {}
+                public void init() {
+                }
 
                 @Override
                 public boolean filterApp(AppEntry entry) {
@@ -1838,7 +1945,8 @@
     public static final AppFilter FILTER_OTHER_APPS =
             new AppFilter() {
                 @Override
-                public void init() {}
+                public void init() {
+                }
 
                 @Override
                 public boolean filterApp(AppEntry entry) {
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothUtils.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothUtils.java
index 081f8a0..bb8c8a6 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothUtils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothUtils.java
@@ -1,7 +1,6 @@
 package com.android.settingslib.bluetooth;
 
 import android.bluetooth.BluetoothClass;
-import android.bluetooth.BluetoothDevice;
 import android.bluetooth.BluetoothProfile;
 import android.content.Context;
 import android.graphics.drawable.Drawable;
@@ -10,7 +9,6 @@
 import androidx.annotation.DrawableRes;
 
 import com.android.settingslib.R;
-import com.android.settingslib.graph.BluetoothDeviceLayerDrawable;
 
 import java.util.List;
 
@@ -51,38 +49,29 @@
 
     public static Pair<Drawable, String> getBtClassDrawableWithDescription(Context context,
             CachedBluetoothDevice cachedDevice) {
-        return getBtClassDrawableWithDescription(context, cachedDevice, 1 /* iconScale */);
-    }
-
-    public static Pair<Drawable, String> getBtClassDrawableWithDescription(Context context,
-            CachedBluetoothDevice cachedDevice, float iconScale) {
         BluetoothClass btClass = cachedDevice.getBtClass();
-        final int level = cachedDevice.getBatteryLevel();
         if (btClass != null) {
             switch (btClass.getMajorDeviceClass()) {
                 case BluetoothClass.Device.Major.COMPUTER:
                     return new Pair<>(getBluetoothDrawable(context,
-                            com.android.internal.R.drawable.ic_bt_laptop, level, iconScale),
+                            com.android.internal.R.drawable.ic_bt_laptop),
                             context.getString(R.string.bluetooth_talkback_computer));
 
                 case BluetoothClass.Device.Major.PHONE:
                     return new Pair<>(
                             getBluetoothDrawable(context,
-                                    com.android.internal.R.drawable.ic_phone, level,
-                                    iconScale),
+                                    com.android.internal.R.drawable.ic_phone),
                             context.getString(R.string.bluetooth_talkback_phone));
 
                 case BluetoothClass.Device.Major.PERIPHERAL:
                     return new Pair<>(
-                            getBluetoothDrawable(context, HidProfile.getHidClassDrawable(btClass),
-                                    level, iconScale),
+                            getBluetoothDrawable(context, HidProfile.getHidClassDrawable(btClass)),
                             context.getString(R.string.bluetooth_talkback_input_peripheral));
 
                 case BluetoothClass.Device.Major.IMAGING:
                     return new Pair<>(
                             getBluetoothDrawable(context,
-                                    com.android.internal.R.drawable.ic_settings_print, level,
-                                    iconScale),
+                                    com.android.internal.R.drawable.ic_settings_print),
                             context.getString(R.string.bluetooth_talkback_imaging));
 
                 default:
@@ -94,38 +83,33 @@
         for (LocalBluetoothProfile profile : profiles) {
             int resId = profile.getDrawableResource(btClass);
             if (resId != 0) {
-                return new Pair<>(getBluetoothDrawable(context, resId, level, iconScale), null);
+                return new Pair<>(getBluetoothDrawable(context, resId), null);
             }
         }
         if (btClass != null) {
             if (btClass.doesClassMatch(BluetoothClass.PROFILE_HEADSET)) {
                 return new Pair<>(
                         getBluetoothDrawable(context,
-                                com.android.internal.R.drawable.ic_bt_headset_hfp, level,
-                                iconScale),
+                                com.android.internal.R.drawable.ic_bt_headset_hfp),
                         context.getString(R.string.bluetooth_talkback_headset));
             }
             if (btClass.doesClassMatch(BluetoothClass.PROFILE_A2DP)) {
                 return new Pair<>(
                         getBluetoothDrawable(context,
-                                com.android.internal.R.drawable.ic_bt_headphones_a2dp, level,
-                                iconScale),
+                                com.android.internal.R.drawable.ic_bt_headphones_a2dp),
                         context.getString(R.string.bluetooth_talkback_headphone));
             }
         }
         return new Pair<>(
                 getBluetoothDrawable(context,
-                        com.android.internal.R.drawable.ic_settings_bluetooth, level, iconScale),
+                        com.android.internal.R.drawable.ic_settings_bluetooth),
                 context.getString(R.string.bluetooth_talkback_bluetooth));
     }
 
-    public static Drawable getBluetoothDrawable(Context context, @DrawableRes int resId,
-            int batteryLevel, float iconScale) {
-        if (batteryLevel != BluetoothDevice.BATTERY_LEVEL_UNKNOWN) {
-            return BluetoothDeviceLayerDrawable.createLayerDrawable(context, resId, batteryLevel,
-                    iconScale);
-        } else {
-            return context.getDrawable(resId);
-        }
+    /**
+     * Get bluetooth drawable by {@code resId}
+     */
+    public static Drawable getBluetoothDrawable(Context context, @DrawableRes int resId) {
+        return context.getDrawable(resId);
     }
 }
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
index ab95910..2405666 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
@@ -32,6 +32,7 @@
 import androidx.annotation.VisibleForTesting;
 
 import com.android.settingslib.R;
+import com.android.settingslib.Utils;
 
 import java.util.ArrayList;
 import java.util.Collection;
@@ -830,6 +831,8 @@
         boolean a2dpConnected = true;        // A2DP is connected
         boolean hfpConnected = true;         // HFP is connected
         boolean hearingAidConnected = true;  // Hearing Aid is connected
+        int leftBattery = -1;
+        int rightBattery = -1;
 
         synchronized (mProfileLock) {
             for (LocalBluetoothProfile profile : getProfiles()) {
@@ -877,8 +880,23 @@
         int stringRes = R.string.bluetooth_pairing;
         //when profile is connected, information would be available
         if (profileConnected) {
+            // Update Meta data for connected device
+            if (Boolean.parseBoolean(
+                    mDevice.getMetadata(BluetoothDevice.METADATA_IS_UNTHETHERED_HEADSET))) {
+                try {
+                    leftBattery = Integer.parseInt(
+                            mDevice.getMetadata(BluetoothDevice.METADATA_UNTHETHERED_LEFT_BATTERY));
+                    rightBattery = Integer.parseInt(mDevice.getMetadata(
+                                    BluetoothDevice.METADATA_UNTHETHERED_RIGHT_BATTERY));
+                } catch (NumberFormatException e) {
+                    Log.d(TAG, "Parse error for unthethered battery level.");
+                }
+            }
+
             // Set default string with battery level in device connected situation.
-            if (batteryLevelPercentageString != null) {
+            if (isTwsBatteryAvailable(leftBattery, rightBattery)) {
+                stringRes = R.string.bluetooth_battery_level_untethered;
+            } else if (batteryLevelPercentageString != null) {
                 stringRes = R.string.bluetooth_battery_level;
             }
 
@@ -887,22 +905,36 @@
             //    2. Headset device active with in-calling state.
             //    3. A2DP device active without in-calling state.
             if (a2dpConnected || hfpConnected || hearingAidConnected) {
-                final boolean isOnCall =
-                        com.android.settingslib.Utils.isAudioModeOngoingCall(mContext);
+                final boolean isOnCall = Utils.isAudioModeOngoingCall(mContext);
                 if ((mIsActiveDeviceHearingAid)
                         || (mIsActiveDeviceHeadset && isOnCall)
                         || (mIsActiveDeviceA2dp && !isOnCall)) {
-                    stringRes = (batteryLevelPercentageString != null)
-                            ? R.string.bluetooth_active_battery_level
-                            : R.string.bluetooth_active_no_battery_level;
+                    if (isTwsBatteryAvailable(leftBattery, rightBattery)) {
+                        stringRes = R.string.bluetooth_active_battery_level_untethered;
+                    } else if (batteryLevelPercentageString != null) {
+                        stringRes = R.string.bluetooth_active_battery_level;
+                    } else {
+                        stringRes = R.string.bluetooth_active_no_battery_level;
+                    }
                 }
             }
         }
 
-        return (stringRes != R.string.bluetooth_pairing
-                || getBondState() == BluetoothDevice.BOND_BONDING)
-                ? mContext.getString(stringRes, batteryLevelPercentageString)
-                : null;
+        if (stringRes != R.string.bluetooth_pairing
+                || getBondState() == BluetoothDevice.BOND_BONDING) {
+            if (isTwsBatteryAvailable(leftBattery, rightBattery)) {
+                return mContext.getString(stringRes, Utils.formatPercentage(leftBattery),
+                        Utils.formatPercentage(rightBattery));
+            } else {
+                return mContext.getString(stringRes, batteryLevelPercentageString);
+            }
+        } else {
+            return null;
+        }
+    }
+
+    private boolean isTwsBatteryAvailable(int leftBattery, int rightBattery) {
+        return leftBattery >= 0 && rightBattery >= 0;
     }
 
     /**
diff --git a/packages/SettingsLib/src/com/android/settingslib/drawer/Tile.java b/packages/SettingsLib/src/com/android/settingslib/drawer/Tile.java
index bee1b3c..d28b00a 100644
--- a/packages/SettingsLib/src/com/android/settingslib/drawer/Tile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/drawer/Tile.java
@@ -276,6 +276,12 @@
             return null;
         }
         ensureMetadataNotStale(context);
+        final ActivityInfo activityInfo = getActivityInfo(context);
+        if (activityInfo == null) {
+            Log.w(TAG, "Cannot find ActivityInfo for " + getDescription());
+            return null;
+        }
+
         int iconResId = mMetaData.getInt(META_DATA_PREFERENCE_ICON);
         // Set the icon
         if (iconResId == 0) {
@@ -283,11 +289,11 @@
             // ICON_URI should be loaded in app UI when need the icon object. Handling IPC at this
             // level is too complex because we don't have a strong threading contract for this class
             if (!mMetaData.containsKey(META_DATA_PREFERENCE_ICON_URI)) {
-                iconResId = getActivityInfo(context).icon;
+                iconResId = activityInfo.icon;
             }
         }
         if (iconResId != 0) {
-            return Icon.createWithResource(getActivityInfo(context).packageName, iconResId);
+            return Icon.createWithResource(activityInfo.packageName, iconResId);
         } else {
             return null;
         }
diff --git a/packages/SettingsLib/src/com/android/settingslib/media/PhoneMediaDevice.java b/packages/SettingsLib/src/com/android/settingslib/media/PhoneMediaDevice.java
index da140aa..8c3fcc0 100644
--- a/packages/SettingsLib/src/com/android/settingslib/media/PhoneMediaDevice.java
+++ b/packages/SettingsLib/src/com/android/settingslib/media/PhoneMediaDevice.java
@@ -70,13 +70,18 @@
         final HearingAidProfile hapProfile = mProfileManager.getHearingAidProfile();
         final A2dpProfile a2dpProfile = mProfileManager.getA2dpProfile();
 
+        // Some device may not have HearingAidProfile, consider all situation to set active device.
         boolean isConnected = false;
-
         if (hapProfile != null && a2dpProfile != null) {
             isConnected = hapProfile.setActiveDevice(null) && a2dpProfile.setActiveDevice(null);
-            updateSummary(true);
-            setConnectedRecord();
+        } else if (a2dpProfile != null) {
+            isConnected = a2dpProfile.setActiveDevice(null);
+        } else if (hapProfile != null) {
+            isConnected = hapProfile.setActiveDevice(null);
         }
+        updateSummary(isConnected);
+        setConnectedRecord();
+
         Log.d(TAG, "connect() device : " + getName() + ", is selected : " + isConnected);
         return isConnected;
     }
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
index 800c401..3acbcd3 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
@@ -1424,6 +1424,9 @@
                     int id = context.getResources()
                             .getIdentifier("network_available_sign_in", "string", "android");
                     return context.getString(id);
+                } else if (nc.hasCapability(
+                        NetworkCapabilities.NET_CAPABILITY_PARTIAL_CONNECTIVITY)) {
+                    return context.getString(R.string.wifi_limited_connection);
                 } else if (!nc.hasCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED)) {
                     return context.getString(R.string.wifi_connected_no_internet);
                 }
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiStatusTracker.java b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiStatusTracker.java
index 2ab369c..5352936 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiStatusTracker.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiStatusTracker.java
@@ -11,6 +11,7 @@
 package com.android.settingslib.wifi;
 
 import static android.net.NetworkCapabilities.NET_CAPABILITY_CAPTIVE_PORTAL;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_PARTIAL_CONNECTIVITY;
 import static android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED;
 
 import android.content.Context;
@@ -158,6 +159,9 @@
             if (networkCapabilities.hasCapability(NET_CAPABILITY_CAPTIVE_PORTAL)) {
                 statusLabel = mContext.getString(R.string.wifi_status_sign_in_required);
                 return;
+            } else if (networkCapabilities.hasCapability(NET_CAPABILITY_PARTIAL_CONNECTIVITY)) {
+                statusLabel = mContext.getString(R.string.wifi_limited_connection);
+                return;
             } else if (!networkCapabilities.hasCapability(NET_CAPABILITY_VALIDATED)) {
                 statusLabel = mContext.getString(R.string.wifi_status_no_internet);
                 return;
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/applications/ApplicationsStateRoboTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/applications/ApplicationsStateRoboTest.java
index a098ecc..b27efd0 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/applications/ApplicationsStateRoboTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/applications/ApplicationsStateRoboTest.java
@@ -16,11 +16,17 @@
 
 package com.android.settingslib.applications;
 
+import static android.os.UserHandle.MU_ENABLED;
+
 import static com.google.common.truth.Truth.assertThat;
 
+import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Matchers.any;
 import static org.mockito.Matchers.anyInt;
 import static org.mockito.Matchers.anyString;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 import static org.robolectric.shadow.api.Shadow.extract;
@@ -40,10 +46,13 @@
 import android.content.pm.PackageManager;
 import android.content.pm.ParceledListSlice;
 import android.content.pm.ResolveInfo;
+import android.content.res.Resources;
 import android.graphics.drawable.ColorDrawable;
 import android.graphics.drawable.Drawable;
 import android.os.Handler;
+import android.os.RemoteException;
 import android.os.UserHandle;
+import android.os.UserManager;
 import android.text.TextUtils;
 import android.util.IconDrawableFactory;
 
@@ -70,6 +79,7 @@
 import org.robolectric.shadows.ShadowLooper;
 
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.List;
 import java.util.UUID;
 
@@ -82,6 +92,19 @@
     private final static String HOME_PACKAGE_NAME = "com.android.home";
     private final static String LAUNCHABLE_PACKAGE_NAME = "com.android.launchable";
 
+    private static final int PROFILE_USERID = 10;
+
+    private static final String PKG_1 = "PKG1";
+    private static final int OWNER_UID_1 = 1001;
+    private static final int PROFILE_UID_1 = UserHandle.getUid(PROFILE_USERID, OWNER_UID_1);
+
+    private static final String PKG_2 = "PKG2";
+    private static final int OWNER_UID_2 = 1002;
+    private static final int PROFILE_UID_2 = UserHandle.getUid(PROFILE_USERID, OWNER_UID_2);
+
+    private static final String PKG_3 = "PKG3";
+    private static final int OWNER_UID_3 = 1003;
+
     /** Class under test */
     private ApplicationsState mApplicationsState;
     private Session mSession;
@@ -171,7 +194,7 @@
         storageStats.dataBytes = 20;
         storageStats.cacheBytes = 30;
         when(mStorageStatsManager.queryStatsForPackage(any(UUID.class),
-                anyString(), any(UserHandle.class))).thenReturn(storageStats);
+            anyString(), any(UserHandle.class))).thenReturn(storageStats);
 
         // Set up 3 installed apps, in which 1 is hidden module
         final List<ApplicationInfo> infos = new ArrayList<>();
@@ -195,11 +218,16 @@
     }
 
     private ApplicationInfo createApplicationInfo(String packageName) {
+        return createApplicationInfo(packageName, 0);
+    }
+
+    private ApplicationInfo createApplicationInfo(String packageName, int uid) {
         ApplicationInfo appInfo = new ApplicationInfo();
         appInfo.sourceDir = "foo";
         appInfo.flags |= ApplicationInfo.FLAG_INSTALLED;
         appInfo.storageUuid = UUID.randomUUID();
         appInfo.packageName = packageName;
+        appInfo.uid = uid;
         return appInfo;
     }
 
@@ -211,10 +239,14 @@
     }
 
     private void addApp(String packageName, int id) {
-        ApplicationInfo appInfo = createApplicationInfo(packageName);
+        addApp(packageName, id, 0);
+    }
+
+    private void addApp(String packageName, int id, int userId) {
+        ApplicationInfo appInfo = createApplicationInfo(packageName, id);
         AppEntry appEntry = createAppEntry(appInfo, id);
         mApplicationsState.mAppEntries.add(appEntry);
-        mApplicationsState.mEntriesMap.get(0).put(appInfo.packageName, appEntry);
+        mApplicationsState.mEntriesMap.get(userId).put(appInfo.packageName, appEntry);
     }
 
     private void processAllMessages() {
@@ -351,4 +383,328 @@
         assertThat(mApplications.get(1).packageName).isEqualTo("test.package.3");
     }
 
+    @Test
+    public void removeAndInstall_noWorkprofile_doResumeIfNeededLocked_shouldClearEntries()
+            throws RemoteException {
+        // scenario: only owner user
+        // (PKG_1, PKG_2) -> (PKG_2, PKG_3)
+        // PKG_1 is removed and PKG_3 is installed before app is resumed.
+        ApplicationsState.sInstance = null;
+        mApplicationsState = spy(
+            ApplicationsState
+                .getInstance(RuntimeEnvironment.application, mock(IPackageManager.class)));
+
+        // Previous Applications:
+        ApplicationInfo appInfo;
+        final ArrayList<ApplicationInfo> prevAppList = new ArrayList<>();
+        appInfo = createApplicationInfo(PKG_1, OWNER_UID_1);
+        prevAppList.add(appInfo);
+        appInfo = createApplicationInfo(PKG_2, OWNER_UID_2);
+        prevAppList.add(appInfo);
+        mApplicationsState.mApplications = prevAppList;
+
+        // Previous Entries:
+        // (PKG_1, PKG_2)
+        addApp(PKG_1, OWNER_UID_1, 0);
+        addApp(PKG_2, OWNER_UID_2, 0);
+
+        // latest Applications:
+        // (PKG_2, PKG_3)
+        final ArrayList<ApplicationInfo> appList = new ArrayList<>();
+        appInfo = createApplicationInfo(PKG_2, OWNER_UID_2);
+        appList.add(appInfo);
+        appInfo = createApplicationInfo(PKG_3, OWNER_UID_3);
+        appList.add(appInfo);
+        setupDoResumeIfNeededLocked(appList, null);
+
+        mApplicationsState.doResumeIfNeededLocked();
+
+        verify(mApplicationsState).clearEntries();
+    }
+
+    @Test
+    public void noAppRemoved_noWorkprofile_doResumeIfNeededLocked_shouldNotClearEntries()
+            throws RemoteException {
+        // scenario: only owner user
+        // (PKG_1, PKG_2)
+        ApplicationsState.sInstance = null;
+        mApplicationsState = spy(
+            ApplicationsState
+                .getInstance(RuntimeEnvironment.application, mock(IPackageManager.class)));
+
+        ApplicationInfo appInfo;
+        // Previous Applications
+        final ArrayList<ApplicationInfo> prevAppList = new ArrayList<>();
+        appInfo = createApplicationInfo(PKG_1, OWNER_UID_1);
+        prevAppList.add(appInfo);
+        appInfo = createApplicationInfo(PKG_2, OWNER_UID_2);
+        prevAppList.add(appInfo);
+        mApplicationsState.mApplications = prevAppList;
+
+        // Previous Entries:
+        // (pk1, PKG_2)
+        addApp(PKG_1, OWNER_UID_1, 0);
+        addApp(PKG_2, OWNER_UID_2, 0);
+
+        // latest Applications:
+        // (PKG_2, PKG_3)
+        final ArrayList<ApplicationInfo> appList = new ArrayList<>();
+        appInfo = createApplicationInfo(PKG_1, OWNER_UID_1);
+        appList.add(appInfo);
+        appInfo = createApplicationInfo(PKG_2, OWNER_UID_2);
+        appList.add(appInfo);
+        setupDoResumeIfNeededLocked(appList, null);
+
+        mApplicationsState.doResumeIfNeededLocked();
+
+        verify(mApplicationsState, never()).clearEntries();
+    }
+
+    @Test
+    public void removeProfileApp_workprofileExists_doResumeIfNeededLocked_shouldClearEntries()
+            throws RemoteException {
+        if (!MU_ENABLED) {
+            return;
+        }
+        // [Preconditions]
+        // 2 apps (PKG_1, PKG_2) for owner, PKG_1 is not in installed state
+        // 2 apps (PKG_1, PKG_2) for non-owner.
+        //
+        // [Actions]
+        // profile user's PKG_2 is removed before resume
+        //
+        // Applications:
+        // owner -  (PKG_1 - uninstalled, PKG_2) -> (PKG_1 - uninstalled, PKG_2)
+        // profile - (PKG_1, PKG_2) -> (PKG_1)
+        //
+        // Previous Entries:
+        // owner - (PKG_2)
+        // profile - (PKG_1, PKG_2)
+
+        ShadowUserManager shadowUserManager = Shadow
+                .extract(RuntimeEnvironment.application.getSystemService(UserManager.class));
+        shadowUserManager.addProfile(PROFILE_USERID, "profile");
+
+        ApplicationsState.sInstance = null;
+        mApplicationsState = spy(
+            ApplicationsState
+                .getInstance(RuntimeEnvironment.application, mock(IPackageManager.class)));
+
+        ApplicationInfo appInfo;
+        // Previous Applications
+        // owner -  (PKG_1 - uninstalled, PKG_2)
+        // profile - (PKG_1, PKG_2)
+        final ArrayList<ApplicationInfo> prevAppList = new ArrayList<>();
+        appInfo = createApplicationInfo(PKG_1, OWNER_UID_1);
+        appInfo.flags ^= ApplicationInfo.FLAG_INSTALLED;
+        prevAppList.add(appInfo);
+        appInfo = createApplicationInfo(PKG_2, OWNER_UID_2);
+        prevAppList.add(appInfo);
+
+        appInfo = createApplicationInfo(PKG_1, PROFILE_UID_1);
+        prevAppList.add(appInfo);
+        appInfo = createApplicationInfo(PKG_2, PROFILE_UID_2);
+        prevAppList.add(appInfo);
+
+        mApplicationsState.mApplications = prevAppList;
+        // Previous Entries:
+        // owner (PKG_2), profile (pk1, PKG_2)
+        // PKG_1 is not installed for owner, hence it's removed from entries
+        addApp(PKG_2, OWNER_UID_2, 0);
+        addApp(PKG_1, PROFILE_UID_1, PROFILE_USERID);
+        addApp(PKG_2, PROFILE_UID_2, PROFILE_USERID);
+
+        // latest Applications:
+        // owner (PKG_1, PKG_2), profile (PKG_1)
+        // owner's PKG_1 is still listed and is in non-installed state
+        // profile user's PKG_2 is removed by a user before resume
+        //owner
+        final ArrayList<ApplicationInfo> ownerAppList = new ArrayList<>();
+        appInfo = createApplicationInfo(PKG_1, OWNER_UID_1);
+        appInfo.flags ^= ApplicationInfo.FLAG_INSTALLED;
+        ownerAppList.add(appInfo);
+        appInfo = createApplicationInfo(PKG_2, OWNER_UID_2);
+        ownerAppList.add(appInfo);
+        //profile
+        appInfo = createApplicationInfo(PKG_1, PROFILE_UID_1);
+        setupDoResumeIfNeededLocked(ownerAppList, new ArrayList<>(Arrays.asList(appInfo)));
+
+        mApplicationsState.doResumeIfNeededLocked();
+
+        verify(mApplicationsState).clearEntries();
+    }
+
+    @Test
+    public void removeOwnerApp_workprofileExists_doResumeIfNeededLocked_shouldClearEntries()
+            throws RemoteException {
+        if (!MU_ENABLED) {
+            return;
+        }
+        // [Preconditions]
+        // 2 apps (PKG_1, PKG_2) for owner, PKG_1 is not in installed state
+        // 2 apps (PKG_1, PKG_2) for non-owner.
+        //
+        // [Actions]
+        // Owner user's PKG_2 is removed before resume
+        //
+        // Applications:
+        // owner -  (PKG_1 - uninstalled, PKG_2) -> (PKG_1 - uninstalled, PKG_2 - uninstalled)
+        // profile - (PKG_1, PKG_2) -> (PKG_1, PKG_2)
+        //
+        // Previous Entries:
+        // owner - (PKG_2)
+        // profile - (PKG_1, PKG_2)
+
+        ShadowUserManager shadowUserManager = Shadow
+                .extract(RuntimeEnvironment.application.getSystemService(UserManager.class));
+        shadowUserManager.addProfile(PROFILE_USERID, "profile");
+
+        ApplicationsState.sInstance = null;
+        mApplicationsState = spy(
+            ApplicationsState
+                .getInstance(RuntimeEnvironment.application, mock(IPackageManager.class)));
+
+        ApplicationInfo appInfo;
+        // Previous Applications:
+        // owner -  (PKG_1 - uninstalled, PKG_2)
+        // profile - (PKG_1, PKG_2)
+        final ArrayList<ApplicationInfo> prevAppList = new ArrayList<>();
+        appInfo = createApplicationInfo(PKG_1, OWNER_UID_1);
+        appInfo.flags ^= ApplicationInfo.FLAG_INSTALLED;
+        prevAppList.add(appInfo);
+        appInfo = createApplicationInfo(PKG_2, OWNER_UID_2);
+        prevAppList.add(appInfo);
+
+        appInfo = createApplicationInfo(PKG_1, PROFILE_UID_1);
+        prevAppList.add(appInfo);
+        appInfo = createApplicationInfo(PKG_2, PROFILE_UID_2);
+        prevAppList.add(appInfo);
+
+        mApplicationsState.mApplications = prevAppList;
+
+        // Previous Entries:
+        // owner (PKG_2), profile (pk1, PKG_2)
+        // PKG_1 is not installed for owner, hence it's removed from entries
+        addApp(PKG_2, OWNER_UID_2, 0);
+        addApp(PKG_1, PROFILE_UID_1, PROFILE_USERID);
+        addApp(PKG_2, PROFILE_UID_2, PROFILE_USERID);
+
+        // latest Applications:
+        // owner (PKG_1 - uninstalled, PKG_2 - uninstalled), profile (PKG_1, PKG_2)
+        // owner's PKG_1, PKG_2 is still listed and is in non-installed state
+        // profile user's PKG_2 is removed before resume
+        //owner
+        final ArrayList<ApplicationInfo> ownerAppList = new ArrayList<>();
+        appInfo = createApplicationInfo(PKG_1, OWNER_UID_1);
+        appInfo.flags ^= ApplicationInfo.FLAG_INSTALLED;
+        ownerAppList.add(appInfo);
+        appInfo = createApplicationInfo(PKG_2, OWNER_UID_2);
+        appInfo.flags ^= ApplicationInfo.FLAG_INSTALLED;
+        ownerAppList.add(appInfo);
+
+        //profile
+        final ArrayList<ApplicationInfo> profileAppList = new ArrayList<>();
+        appInfo = createApplicationInfo(PKG_1, PROFILE_UID_1);
+        profileAppList.add(appInfo);
+        appInfo = createApplicationInfo(PKG_2, PROFILE_UID_2);
+        profileAppList.add(appInfo);
+        setupDoResumeIfNeededLocked(ownerAppList, profileAppList);
+
+        mApplicationsState.doResumeIfNeededLocked();
+
+        verify(mApplicationsState).clearEntries();
+    }
+
+    @Test
+    public void noAppRemoved_workprofileExists_doResumeIfNeededLocked_shouldNotClearEntries()
+            throws RemoteException {
+        if (!MU_ENABLED) {
+            return;
+        }
+        // [Preconditions]
+        // 2 apps (PKG_1, PKG_2) for owner, PKG_1 is not in installed state
+        // 2 apps (PKG_1, PKG_2) for non-owner.
+        //
+        // Applications:
+        // owner -  (PKG_1 - uninstalled, PKG_2)
+        // profile - (PKG_1, PKG_2)
+        //
+        // Previous Entries:
+        // owner - (PKG_2)
+        // profile - (PKG_1, PKG_2)
+
+        ShadowUserManager shadowUserManager = Shadow
+                .extract(RuntimeEnvironment.application.getSystemService(UserManager.class));
+        shadowUserManager.addProfile(PROFILE_USERID, "profile");
+
+        ApplicationsState.sInstance = null;
+        mApplicationsState = spy(
+            ApplicationsState
+                .getInstance(RuntimeEnvironment.application, mock(IPackageManager.class)));
+
+        ApplicationInfo appInfo;
+        // Previous Applications:
+        // owner -  (PKG_1 - uninstalled, PKG_2)
+        // profile - (PKG_1, PKG_2)
+        final ArrayList<ApplicationInfo> prevAppList = new ArrayList<>();
+        appInfo = createApplicationInfo(PKG_1, OWNER_UID_1);
+        appInfo.flags ^= ApplicationInfo.FLAG_INSTALLED;
+        prevAppList.add(appInfo);
+        appInfo = createApplicationInfo(PKG_2, OWNER_UID_2);
+        prevAppList.add(appInfo);
+
+        appInfo = createApplicationInfo(PKG_1, PROFILE_UID_1);
+        prevAppList.add(appInfo);
+        appInfo = createApplicationInfo(PKG_2, PROFILE_UID_2);
+        prevAppList.add(appInfo);
+
+        mApplicationsState.mApplications = prevAppList;
+        // Previous Entries:
+        // owner (PKG_2), profile (pk1, PKG_2)
+        // PKG_1 is not installed for owner, hence it's removed from entries
+        addApp(PKG_2, OWNER_UID_2, 0);
+        addApp(PKG_1, PROFILE_UID_1, PROFILE_USERID);
+        addApp(PKG_2, PROFILE_UID_2, PROFILE_USERID);
+
+        // latest Applications:
+        // owner (PKG_1 - uninstalled, PKG_2), profile (PKG_1, PKG_2)
+        // owner's PKG_1 is still listed and is in non-installed state
+
+        // owner
+        final ArrayList<ApplicationInfo> ownerAppList = new ArrayList<>();
+        appInfo = createApplicationInfo(PKG_1, OWNER_UID_1);
+        appInfo.flags ^= ApplicationInfo.FLAG_INSTALLED;
+        ownerAppList.add(appInfo);
+        appInfo = createApplicationInfo(PKG_2, OWNER_UID_2);
+        ownerAppList.add(appInfo);
+
+        // profile
+        final ArrayList<ApplicationInfo> profileAppList = new ArrayList<>();
+        appInfo = createApplicationInfo(PKG_1, PROFILE_UID_1);
+        profileAppList.add(appInfo);
+        appInfo = createApplicationInfo(PKG_2, PROFILE_UID_2);
+        profileAppList.add(appInfo);
+        setupDoResumeIfNeededLocked(ownerAppList, profileAppList);
+
+        mApplicationsState.doResumeIfNeededLocked();
+
+        verify(mApplicationsState, never()).clearEntries();
+    }
+
+    private void setupDoResumeIfNeededLocked(ArrayList<ApplicationInfo> ownerApps,
+            ArrayList<ApplicationInfo> profileApps)
+            throws RemoteException {
+
+        if (ownerApps != null) {
+            when(mApplicationsState.mIpm.getInstalledApplications(anyInt(), eq(0)))
+                .thenReturn(new ParceledListSlice<>(ownerApps));
+        }
+        if (profileApps != null) {
+            when(mApplicationsState.mIpm.getInstalledApplications(anyInt(), eq(PROFILE_USERID)))
+                .thenReturn(new ParceledListSlice<>(profileApps));
+        }
+        final InterestingConfigChanges configChanges = mock(InterestingConfigChanges.class);
+        when(configChanges.applyNewConfig(any(Resources.class))).thenReturn(false);
+        mApplicationsState.setInterestingConfigChanges(configChanges);
+    }
 }
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/BluetoothUtilsTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/BluetoothUtilsTest.java
index 7a71551..b713e08 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/BluetoothUtilsTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/BluetoothUtilsTest.java
@@ -15,36 +15,55 @@
  */
 package com.android.settingslib.bluetooth;
 
-import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
 
-import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothClass;
+import android.content.Context;
 import android.graphics.drawable.Drawable;
+import android.util.Pair;
 
-import com.android.settingslib.graph.BluetoothDeviceLayerDrawable;
-
+import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
+import org.mockito.Answers;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
 import org.robolectric.RobolectricTestRunner;
 import org.robolectric.RuntimeEnvironment;
 
 @RunWith(RobolectricTestRunner.class)
 public class BluetoothUtilsTest {
 
-    @Test
-    public void testGetBluetoothDrawable_noBatteryLevel_returnSimpleDrawable() {
-        final Drawable drawable = BluetoothUtils.getBluetoothDrawable(
-                RuntimeEnvironment.application, com.android.internal.R.drawable.ic_bt_laptop,
-                BluetoothDevice.BATTERY_LEVEL_UNKNOWN, 1 /* iconScale */);
+    @Mock(answer = Answers.RETURNS_DEEP_STUBS)
+    private CachedBluetoothDevice mCachedBluetoothDevice;
+    private Context mContext;
 
-        assertThat(drawable).isNotInstanceOf(BluetoothDeviceLayerDrawable.class);
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+
+        mContext = spy(RuntimeEnvironment.application);
     }
 
     @Test
-    public void testGetBluetoothDrawable_hasBatteryLevel_returnLayerDrawable() {
-        final Drawable drawable = BluetoothUtils.getBluetoothDrawable(
-                RuntimeEnvironment.application, com.android.internal.R.drawable.ic_bt_laptop,
-                10 /* batteryLevel */, 1 /* iconScale */);
+    public void getBtClassDrawableWithDescription_typePhone_returnPhoneDrawable() {
+        when(mCachedBluetoothDevice.getBtClass().getMajorDeviceClass()).thenReturn(
+                BluetoothClass.Device.Major.PHONE);
+        final Pair<Drawable, String> pair = BluetoothUtils.getBtClassDrawableWithDescription(
+                mContext, mCachedBluetoothDevice);
 
-        assertThat(drawable).isInstanceOf(BluetoothDeviceLayerDrawable.class);
+        verify(mContext).getDrawable(com.android.internal.R.drawable.ic_phone);
     }
-}
+
+    @Test
+    public void getBtClassDrawableWithDescription_typeComputer_returnComputerDrawable() {
+        when(mCachedBluetoothDevice.getBtClass().getMajorDeviceClass()).thenReturn(
+                BluetoothClass.Device.Major.COMPUTER);
+        final Pair<Drawable, String> pair = BluetoothUtils.getBtClassDrawableWithDescription(
+                mContext, mCachedBluetoothDevice);
+
+        verify(mContext).getDrawable(com.android.internal.R.drawable.ic_bt_laptop);
+    }
+}
\ No newline at end of file
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceTest.java
index 4e5d38a..79b84b9 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceTest.java
@@ -41,14 +41,16 @@
 
 @RunWith(RobolectricTestRunner.class)
 public class CachedBluetoothDeviceTest {
-    private final static String DEVICE_NAME = "TestName";
-    private final static String DEVICE_ALIAS = "TestAlias";
-    private final static String DEVICE_ADDRESS = "AA:BB:CC:DD:EE:FF";
-    private final static String DEVICE_ALIAS_NEW = "TestAliasNew";
-    private final static short RSSI_1 = 10;
-    private final static short RSSI_2 = 11;
-    private final static boolean JUSTDISCOVERED_1 = true;
-    private final static boolean JUSTDISCOVERED_2 = false;
+    private static final String DEVICE_NAME = "TestName";
+    private static final String DEVICE_ALIAS = "TestAlias";
+    private static final String DEVICE_ADDRESS = "AA:BB:CC:DD:EE:FF";
+    private static final String DEVICE_ALIAS_NEW = "TestAliasNew";
+    private static final String TWS_BATTERY_LEFT = "15";
+    private static final String TWS_BATTERY_RIGHT = "25";
+    private static final short RSSI_1 = 10;
+    private static final short RSSI_2 = 11;
+    private static final boolean JUSTDISCOVERED_1 = true;
+    private static final boolean JUSTDISCOVERED_2 = false;
     @Mock
     private LocalBluetoothProfileManager mProfileManager;
     @Mock
@@ -447,6 +449,41 @@
     }
 
     @Test
+    public void getConnectionSummary_trueWirelessActiveDeviceWithBattery_returnActiveWithBattery() {
+        updateProfileStatus(mA2dpProfile, BluetoothProfile.STATE_CONNECTED);
+        updateProfileStatus(mHfpProfile, BluetoothProfile.STATE_CONNECTED);
+        updateProfileStatus(mHearingAidProfile, BluetoothProfile.STATE_CONNECTED);
+        when(mDevice.getBondState()).thenReturn(BluetoothDevice.BOND_BONDED);
+        mCachedDevice.onActiveDeviceChanged(true, BluetoothProfile.HEARING_AID);
+        when(mDevice.getMetadata(BluetoothDevice.METADATA_IS_UNTHETHERED_HEADSET)).thenReturn(
+                "true");
+        when(mDevice.getMetadata(BluetoothDevice.METADATA_UNTHETHERED_LEFT_BATTERY)).thenReturn(
+                TWS_BATTERY_LEFT);
+        when(mDevice.getMetadata(BluetoothDevice.METADATA_UNTHETHERED_RIGHT_BATTERY)).thenReturn(
+                TWS_BATTERY_RIGHT);
+
+        assertThat(mCachedDevice.getConnectionSummary()).isEqualTo(
+                "Active, L: 15% battery, R: 25% battery");
+    }
+
+    @Test
+    public void getConnectionSummary_trueWirelessDeviceWithBattery_returnActiveWithBattery() {
+        updateProfileStatus(mA2dpProfile, BluetoothProfile.STATE_CONNECTED);
+        updateProfileStatus(mHfpProfile, BluetoothProfile.STATE_CONNECTED);
+        updateProfileStatus(mHearingAidProfile, BluetoothProfile.STATE_CONNECTED);
+        when(mDevice.getBondState()).thenReturn(BluetoothDevice.BOND_BONDED);
+        when(mDevice.getMetadata(BluetoothDevice.METADATA_IS_UNTHETHERED_HEADSET)).thenReturn(
+                "true");
+        when(mDevice.getMetadata(BluetoothDevice.METADATA_UNTHETHERED_LEFT_BATTERY)).thenReturn(
+                TWS_BATTERY_LEFT);
+        when(mDevice.getMetadata(BluetoothDevice.METADATA_UNTHETHERED_RIGHT_BATTERY)).thenReturn(
+                TWS_BATTERY_RIGHT);
+
+        assertThat(mCachedDevice.getConnectionSummary()).isEqualTo(
+                "L: 15% battery, R: 25% battery");
+    }
+
+    @Test
     public void getCarConnectionSummary_singleProfileConnectDisconnect() {
         // Test without battery level
         // Set PAN profile to be connected and test connection state summary
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/PhoneMediaDeviceTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/PhoneMediaDeviceTest.java
index 50a6a9d..0752dc0 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/PhoneMediaDeviceTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/PhoneMediaDeviceTest.java
@@ -100,6 +100,30 @@
     }
 
     @Test
+    public void connect_hearingAidProfileIsNullAndA2dpProfileNotNull_isConnectedReturnTrue() {
+        when(mLocalProfileManager.getHearingAidProfile()).thenReturn(null);
+
+        when(mA2dpProfile.setActiveDevice(null)).thenReturn(true);
+        assertThat(mPhoneMediaDevice.connect()).isTrue();
+    }
+
+    @Test
+    public void connect_hearingAidProfileNotNullAndA2dpProfileIsNull_isConnectedReturnTrue() {
+        when(mLocalProfileManager.getA2dpProfile()).thenReturn(null);
+
+        when(mHapProfile.setActiveDevice(null)).thenReturn(true);
+        assertThat(mPhoneMediaDevice.connect()).isTrue();
+    }
+
+    @Test
+    public void connect_hearingAidProfileAndA2dpProfileIsNull_isConnectedReturnFalse() {
+        when(mLocalProfileManager.getA2dpProfile()).thenReturn(null);
+        when(mLocalProfileManager.getHearingAidProfile()).thenReturn(null);
+
+        assertThat(mPhoneMediaDevice.connect()).isFalse();
+    }
+
+    @Test
     public void updateSummary_isActiveIsTrue_returnActiveString() {
         mPhoneMediaDevice.updateSummary(true);
 
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/testutils/shadow/ShadowUserManager.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/testutils/shadow/ShadowUserManager.java
index c50d646..ca1eefc 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/testutils/shadow/ShadowUserManager.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/testutils/shadow/ShadowUserManager.java
@@ -29,6 +29,7 @@
 
 @Implements(value = UserManager.class)
 public class ShadowUserManager extends org.robolectric.shadows.ShadowUserManager {
+    private List<UserInfo> mUserInfos = addProfile(0, "Owner");
 
     @Implementation
     protected static UserManager get(Context context) {
@@ -37,16 +38,24 @@
 
     @Implementation
     protected int[] getProfileIdsWithDisabled(int userId) {
-        return new int[]{0};
+        return mUserInfos.stream().mapToInt(s -> s.id).toArray();
     }
 
     @Implementation
     protected List<UserInfo> getProfiles() {
-        UserInfo userInfo = new UserInfo();
-        userInfo.id = 0;
-        List<UserInfo> userInfos = new ArrayList<>();
-        userInfos.add(userInfo);
-        return userInfos;
+        return mUserInfos;
+    }
+
+    public List<UserInfo> addProfile(int id, String name) {
+        List<UserInfo> userInfoList = mUserInfos;
+        if (userInfoList == null) {
+            userInfoList = new ArrayList<>();
+        }
+        final UserInfo userInfo = new UserInfo();
+        userInfo.id = id;
+        userInfo.name = name;
+        userInfoList.add(userInfo);
+        return userInfoList;
     }
 
     @Implementation
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/apppreference/AppPreferenceTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/apppreference/AppPreferenceTest.java
index 042616a..2848888 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/apppreference/AppPreferenceTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/apppreference/AppPreferenceTest.java
@@ -57,24 +57,6 @@
     }
 
     @Test
-    public void setSummary_showSummaryContainer() {
-        mPref.setSummary("test");
-        mPref.onBindViewHolder(mHolder);
-
-        assertThat(mHolder.findViewById(R.id.summary_container).getVisibility())
-                .isEqualTo(View.VISIBLE);
-    }
-
-    @Test
-    public void noSummary_hideSummaryContainer() {
-        mPref.setSummary(null);
-        mPref.onBindViewHolder(mHolder);
-
-        assertThat(mHolder.findViewById(R.id.summary_container).getVisibility())
-                .isEqualTo(View.GONE);
-    }
-
-    @Test
     public void foobar_testName() {
         float iconSize = mContext.getResources().getDimension(R.dimen.secondary_app_icon_size);
         assertThat(Float.floatToIntBits(iconSize)).isEqualTo(Float.floatToIntBits(32));
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index ff25ad9..9e46ad6 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -3235,7 +3235,7 @@
         }
 
         private final class UpgradeController {
-            private static final int SETTINGS_VERSION = 175;
+            private static final int SETTINGS_VERSION = 176;
 
             private final int mUserId;
 
@@ -4286,6 +4286,31 @@
                     currentVersion = 175;
                 }
 
+                if (currentVersion == 175) {
+                    // Version 175: Set the default value for System Settings:
+                    // RING_VIBRATION_INTENSITY. If the notification vibration intensity has been
+                    // set and ring vibration intensity hasn't, the ring vibration intensity should
+                    // followed notification vibration intensity.
+
+                    final SettingsState systemSettings = getSystemSettingsLocked(userId);
+
+                    Setting notificationVibrationIntensity = systemSettings.getSettingLocked(
+                            Settings.System.NOTIFICATION_VIBRATION_INTENSITY);
+
+                    Setting ringVibrationIntensity = systemSettings.getSettingLocked(
+                            Settings.System.RING_VIBRATION_INTENSITY);
+
+                    if (!notificationVibrationIntensity.isNull()
+                            && ringVibrationIntensity.isNull()) {
+                        systemSettings.insertSettingLocked(
+                                Settings.System.RING_VIBRATION_INTENSITY,
+                                notificationVibrationIntensity.getValue(),
+                                null , true, SettingsState.SYSTEM_PACKAGE_NAME);
+                    }
+
+                    currentVersion = 176;
+                }
+
                 // vXXX: Add new settings above this point.
 
                 if (currentVersion != newVersion) {
diff --git a/packages/SettingsProvider/test/src/com/android/providers/settings/DeviceConfigServiceTest.java b/packages/SettingsProvider/test/src/com/android/providers/settings/DeviceConfigServiceTest.java
index df4656a..e588b3d 100644
--- a/packages/SettingsProvider/test/src/com/android/providers/settings/DeviceConfigServiceTest.java
+++ b/packages/SettingsProvider/test/src/com/android/providers/settings/DeviceConfigServiceTest.java
@@ -147,7 +147,7 @@
         // make sValue the default value
         executeShellCommand(
                 "device_config put " + sNamespace + " " + sKey + " " + sValue + " default");
-        // make newValue the current value (as set by a trusted package)
+        // make newValue the current value (as set by a untrusted package)
         executeShellCommand(
                 "device_config put " + sNamespace + " " + sKey + " " + newValue);
         String result = getFromContentProvider(mContentResolver, sNamespace, sKey);
@@ -156,13 +156,7 @@
         // reset values that were set by untrusted packages
         executeShellCommand("device_config reset untrusted_defaults " + sNamespace);
         result = getFromContentProvider(mContentResolver, sNamespace, sKey);
-        // the current value was set by a trusted package, so it's not reset
-        assertEquals(newValue, result);
-
-        // reset values that were set by untrusted or trusted packages
-        executeShellCommand("device_config reset trusted_defaults " + sNamespace);
-        result = getFromContentProvider(mContentResolver, sNamespace, sKey);
-        // the default value has been restored
+        // the current value was set by a untrusted package, so it's reset
         assertEquals(sValue, result);
     }
 
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index d639e5e..441f88c 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -86,6 +86,7 @@
     <uses-permission android:name="android.permission.DELETE_CACHE_FILES" />
     <uses-permission android:name="android.permission.DELETE_PACKAGES" />
     <uses-permission android:name="android.permission.MANAGE_ROLLBACKS" />
+    <uses-permission android:name="android.permission.TEST_MANAGE_ROLLBACKS" />
     <uses-permission android:name="android.permission.ACCESS_SURFACE_FLINGER" />
     <uses-permission android:name="android.permission.READ_FRAME_BUFFER" />
     <uses-permission android:name="android.permission.DEVICE_POWER" />
@@ -178,6 +179,9 @@
     <!-- Permission needed to run network tests in CTS -->
     <uses-permission android:name="android.permission.MANAGE_TEST_NETWORKS" />
 
+    <!-- Permission needed to run keyguard manager tests in CTS -->
+    <uses-permission android:name="android.permission.CONTROL_KEYGUARD_SECURE_NOTIFICATIONS" />
+
     <application android:label="@string/app_label"
                  android:defaultToDeviceProtectedStorage="true"
                  android:directBootAware="true">
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/VolumeDialogController.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/VolumeDialogController.java
index 2b10ccb..3d2f570 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/VolumeDialogController.java
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/VolumeDialogController.java
@@ -60,7 +60,8 @@
 
     boolean areCaptionsEnabled();
     void setCaptionsEnabled(boolean isEnabled);
-    void getCaptionsComponentState();
+
+    void getCaptionsComponentState(boolean fromTooltip);
 
     @ProvidesInterface(version = StreamState.VERSION)
     public static final class StreamState {
@@ -190,6 +191,6 @@
         void onScreenOff();
         void onShowSafetyWarning(int flags);
         void onAccessibilityModeChanged(Boolean showA11yStream);
-        void onCaptionComponentStateChanged(Boolean isComponentEnabled);
+        void onCaptionComponentStateChanged(Boolean isComponentEnabled, Boolean fromTooltip);
     }
 }
diff --git a/packages/SystemUI/res-keyguard/layout/keyguard_message_area.xml b/packages/SystemUI/res-keyguard/layout/keyguard_message_area.xml
index e1bf6cb..5da7611 100644
--- a/packages/SystemUI/res-keyguard/layout/keyguard_message_area.xml
+++ b/packages/SystemUI/res-keyguard/layout/keyguard_message_area.xml
@@ -17,15 +17,24 @@
 */
 -->
 
-<!-- This contains emergency call button and carrier as shared by pin/pattern/password screens -->
-<com.android.keyguard.KeyguardMessageArea
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_width="match_parent"
-    android:layout_height="wrap_content"
-    android:gravity="center"
-    style="@style/Keyguard.TextView"
-    android:id="@+id/keyguard_message_area"
-    android:singleLine="true"
-    android:ellipsize="marquee"
-    android:focusable="true" />
-
+<!-- This contains error message field and padlock shared by pin/pattern/password screens -->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+              android:orientation="vertical"
+              android:layout_width="match_parent"
+              android:layout_height="wrap_content" >
+    <FrameLayout
+        android:id="@+id/lock_icon_container"
+        android:layout_gravity="center"
+        android:layout_marginBottom="@dimen/keyguard_lock_padding"
+        android:layout_width="@dimen/keyguard_lock_width"
+        android:layout_height="@dimen/keyguard_lock_height" />
+    <com.android.keyguard.KeyguardMessageArea
+        android:id="@+id/keyguard_message_area"
+        style="@style/Keyguard.TextView"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:gravity="center"
+        android:singleLine="true"
+        android:ellipsize="marquee"
+        android:focusable="true" />
+</LinearLayout>
\ No newline at end of file
diff --git a/packages/SystemUI/res-keyguard/values-sw320dp/dimens.xml b/packages/SystemUI/res-keyguard/values-sw320dp/dimens.xml
index 38d2ecc3..91ca5c5 100644
--- a/packages/SystemUI/res-keyguard/values-sw320dp/dimens.xml
+++ b/packages/SystemUI/res-keyguard/values-sw320dp/dimens.xml
@@ -21,6 +21,6 @@
 
     <!-- Height of the sliding KeyguardSecurityContainer
          (includes 2x keyguard_security_view_top_margin) -->
-    <dimen name="keyguard_security_height">345dp</dimen>
+    <dimen name="keyguard_security_height">395dp</dimen>
 
 </resources>
diff --git a/packages/SystemUI/res-keyguard/values-sw360dp/dimens.xml b/packages/SystemUI/res-keyguard/values-sw360dp/dimens.xml
index 90c4795..d7c9975 100644
--- a/packages/SystemUI/res-keyguard/values-sw360dp/dimens.xml
+++ b/packages/SystemUI/res-keyguard/values-sw360dp/dimens.xml
@@ -21,5 +21,5 @@
 
     <!-- Height of the sliding KeyguardSecurityContainer (includes 2x
          keyguard_security_view_top_margin) -->
-    <dimen name="keyguard_security_height">400dp</dimen>
+    <dimen name="keyguard_security_height">450dp</dimen>
 </resources>
diff --git a/packages/SystemUI/res-keyguard/values-sw540dp-port/dimens.xml b/packages/SystemUI/res-keyguard/values-sw540dp-port/dimens.xml
index 9ea04dc..a3c37e4 100644
--- a/packages/SystemUI/res-keyguard/values-sw540dp-port/dimens.xml
+++ b/packages/SystemUI/res-keyguard/values-sw540dp-port/dimens.xml
@@ -20,5 +20,5 @@
 <resources>
     <!-- Height of the sliding KeyguardSecurityContainer
         (includes 2x keyguard_security_view_top_margin) -->
-    <dimen name="keyguard_security_height">500dp</dimen>
+    <dimen name="keyguard_security_height">550dp</dimen>
 </resources>
diff --git a/packages/SystemUI/res-keyguard/values-sw720dp/dimens.xml b/packages/SystemUI/res-keyguard/values-sw720dp/dimens.xml
index 9157822..1dc61c5 100644
--- a/packages/SystemUI/res-keyguard/values-sw720dp/dimens.xml
+++ b/packages/SystemUI/res-keyguard/values-sw720dp/dimens.xml
@@ -20,7 +20,7 @@
 
     <!-- Height of the sliding KeyguardSecurityContainer
          (includes 2x keyguard_security_view_top_margin) -->
-    <dimen name="keyguard_security_height">420dp</dimen>
+    <dimen name="keyguard_security_height">470dp</dimen>
 
     <dimen name="widget_big_font_size">100dp</dimen>
 </resources>
diff --git a/packages/SystemUI/res-keyguard/values/dimens.xml b/packages/SystemUI/res-keyguard/values/dimens.xml
index b6a41c1..d67c98a 100644
--- a/packages/SystemUI/res-keyguard/values/dimens.xml
+++ b/packages/SystemUI/res-keyguard/values/dimens.xml
@@ -27,11 +27,11 @@
 
     <!-- Height of the sliding KeyguardSecurityContainer
          (includes 2x keyguard_security_view_top_margin) -->
-    <dimen name="keyguard_security_height">400dp</dimen>
+    <dimen name="keyguard_security_height">450dp</dimen>
 
     <!-- Max Height of the sliding KeyguardSecurityContainer
          (includes 2x keyguard_security_view_top_margin) -->
-    <dimen name="keyguard_security_max_height">455dp</dimen>
+    <dimen name="keyguard_security_max_height">505dp</dimen>
 
     <!-- Margin around the various security views -->
     <dimen name="keyguard_security_view_top_margin">8dp</dimen>
diff --git a/packages/SystemUI/res/drawable/ic_remove_no_shadow.xml b/packages/SystemUI/res/drawable/ic_remove_no_shadow.xml
new file mode 100644
index 0000000..bed06b5
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_remove_no_shadow.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ 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
+  -->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="24dp"
+        android:height="24dp"
+        android:viewportWidth="24.0"
+        android:viewportHeight="24.0"
+        android:tint="?android:attr/textColorPrimary" >
+    <path
+        android:fillColor="#FFFFFFFF"
+        android:pathData="M13.41,12l5.29-5.29c0.39-0.39,0.39-1.02,0-1.41c-0.39-0.39-1.02-0.39-1.41,0L12,10.59L6.71,
+        5.29c-0.39-0.39-1.02-0.39-1.41,0c-0.39,0.39-0.39,1.02,0,1.41L10.59,12l-5.29,5.29c-0.39,0.39-0.39,1.02,
+        0,1.41c0.39,0.39,1.02,0.39,1.41,0L12,13.41l5.29,5.29c0.39,0.39,1.02,0.39,1.41,0c0.39-0.39,0.39-1.02,0-1.41L13.41,12z"/>
+</vector>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/ic_signal_sensors.xml b/packages/SystemUI/res/drawable/ic_signal_sensors.xml
deleted file mode 100644
index faaddf6..0000000
--- a/packages/SystemUI/res/drawable/ic_signal_sensors.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<!--
-     Copyright (C) 2018 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 android:height="48dp" android:viewportHeight="5"
-    android:viewportWidth="5" android:width="48dp" xmlns:android="http://schemas.android.com/apk/res/android">
-    <path android:fillColor="#00000000"
-        android:pathData="m4.762,0.661 l-4.233,4.233"
-        android:strokeAlpha="1" android:strokeColor="#000000"
-        android:strokeLineCap="round" android:strokeLineJoin="miter" android:strokeWidth=".5"/>
-    <path android:fillColor="#00000000"
-        android:pathData="M0.265,2.778L1.058,2.778l0.529,-1.323 0.529,2.646 0.529,-3.175 0.529,2.646 0.529,-1.587 0.265,0.794h1.058"
-        android:strokeAlpha="1" android:strokeColor="#000000"
-        android:strokeLineCap="round" android:strokeLineJoin="round" android:strokeWidth=".33"/>
-</vector>
-
diff --git a/packages/SystemUI/res/drawable/ic_volume_odi_captions.xml b/packages/SystemUI/res/drawable/ic_volume_odi_captions.xml
index 9b90729..675aee9 100644
--- a/packages/SystemUI/res/drawable/ic_volume_odi_captions.xml
+++ b/packages/SystemUI/res/drawable/ic_volume_odi_captions.xml
@@ -19,6 +19,23 @@
     android:viewportWidth="24"
     android:viewportHeight="24">
   <path
-      android:fillColor="#FF000000"
-      android:pathData="M20,4C21.1,4 22,4.9 22,6L22,18C22,19.1 21.1,20 20,20L4,20C2.9,20 2,19.1 2,18L2,6C2,4.9 2.9,4 4,4L20,4ZM20,18L20,6L4,6L4,18L20,18ZM6,10L8,10L8,12L6,12L6,10ZM6,14L14,14L14,16L6,16L6,14ZM16,14L18,14L18,16L16,16L16,14ZM10,10L18,10L18,12L10,12L10,10Z"/>
+      android:pathData="M16,12h2v2h-2z"
+      android:fillColor="#1A73E8"
+      android:fillType="nonZero"/>
+  <path
+      android:pathData="M6,12h8v2h-8z"
+      android:fillColor="#1A73E8"
+      android:fillType="nonZero"/>
+  <path
+      android:pathData="M20,2C21.1046,2 22,2.8954 22,4L22,16C22,17.1046 21.1046,18 20,18L6,18L2,22L2,4C2,2.8954 2.8954,2 4,2L20,2ZM20,16L20,4L4,4L4,16L20,16Z"
+      android:fillColor="#1A73E8"
+      android:fillType="nonZero"/>
+  <path
+      android:pathData="M6,8h2v2h-2z"
+      android:fillColor="#1A73E8"
+      android:fillType="nonZero"/>
+  <path
+      android:pathData="M10,8h8v2h-8z"
+      android:fillColor="#1A73E8"
+      android:fillType="nonZero"/>
 </vector>
diff --git a/packages/SystemUI/res/drawable/ic_volume_odi_captions_disabled.xml b/packages/SystemUI/res/drawable/ic_volume_odi_captions_disabled.xml
index f3d8d3b9..e818455 100644
--- a/packages/SystemUI/res/drawable/ic_volume_odi_captions_disabled.xml
+++ b/packages/SystemUI/res/drawable/ic_volume_odi_captions_disabled.xml
@@ -19,6 +19,19 @@
     android:viewportWidth="24"
     android:viewportHeight="24">
   <path
-      android:fillColor="#FF000000"
-      android:pathData="M16.9675,14L18,14L18,15.0275L16.9675,14ZM20,17.0176L20,6L8.9281,6L6.9182,4L20,4C21.1,4 22,4.9 22,6L22,18C22,18.2949 21.9353,18.5755 21.8194,18.8281L20,17.0176ZM12.9478,10L18,10L18,12L14.9576,12L12.9478,10ZM1.2823,0.8824L22.8489,22.4489L21.6337,23.6641L17.9696,20L4,20C2.9,20 2,19.1 2,18L2,6C2,5.4577 2.2188,4.964 2.5724,4.6028L0.0672,2.0975L1.2823,0.8824ZM13.9696,16L6,16L6,14L11.9696,14L8,10.0304L8,12L6,12L6,10L7.9696,10L4,6.0304L4,18L15.9696,18L13.9696,16Z"/>
+      android:pathData="M2.07,0.64L22,20.59L20.6,22L16.6,18L6,18L2,22L2,4C2.0006,3.8236 2.0276,3.6484 2.08,3.48L0.66,2.05L2.07,0.64ZM5.17,16L14.6,16L12.6,14L6,14L6,12L10.6,12L8,9.4L8,10L6,10L6,8L6.6,8L4,5.4L4,16L5.17,16Z"
+      android:fillColor="#1A73E8"
+      android:fillType="nonZero"/>
+  <path
+      android:pathData="M18,12l-1.74,0l1.74,1.74z"
+      android:fillColor="#1A73E8"
+      android:fillType="nonZero"/>
+  <path
+      android:pathData="M18,8l-5.74,0l2,2l3.74,0z"
+      android:fillColor="#1A73E8"
+      android:fillType="nonZero"/>
+  <path
+      android:pathData="M20,4L20,15.74L21.53,17.27C21.8296,16.9142 21.9958,16.4651 22,16L22,4C22,2.8954 21.1046,2 20,2L6.26,2L8.26,4L20,4Z"
+      android:fillColor="#1A73E8"
+      android:fillType="nonZero"/>
 </vector>
diff --git a/packages/SystemUI/res/drawable/stat_sys_sensors_off.xml b/packages/SystemUI/res/drawable/stat_sys_sensors_off.xml
new file mode 100644
index 0000000..ca8f993
--- /dev/null
+++ b/packages/SystemUI/res/drawable/stat_sys_sensors_off.xml
@@ -0,0 +1,41 @@
+<!--
+     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.
+-->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:insetLeft="3dp"
+        android:insetRight="3dp"
+        android:width="17dp"
+        android:height="17dp"
+        android:viewportWidth="24.0"
+        android:viewportHeight="24.0">
+    <path
+        android:pathData="M21.966,2 L2,22"
+        android:strokeLineCap="round"
+        android:strokeColor="#000000"
+        android:fillColor="#00000000"
+        android:strokeWidth="1.6521436"
+        android:strokeLineJoin="miter"
+        android:strokeAlpha="1"/>
+    <path
+        android:pathData="M0.752,12L4.496,12l2.496,-6.25 2.496,12.5 2.496,-15 2.496,12.5 2.496,-7.5 1.248,3.75h4.992"
+        android:strokeLineCap="round"
+        android:strokeColor="#000000"
+        android:fillColor="#00000000"
+        android:strokeWidth="1.25090861"
+        android:strokeLineJoin="round"
+        android:strokeAlpha="1"/>
+</vector>
+
diff --git a/packages/SystemUI/res/drawable/volume_tool_tip_rounded_bg.xml b/packages/SystemUI/res/drawable/volume_tool_tip_rounded_bg.xml
new file mode 100644
index 0000000..22e8c48
--- /dev/null
+++ b/packages/SystemUI/res/drawable/volume_tool_tip_rounded_bg.xml
@@ -0,0 +1,19 @@
+<!--
+  ~ 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
+  -->
+<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle">
+    <solid android:color="?android:attr/colorAccent" />
+    <corners android:radius="8dp" />
+</shape>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout-land/volume_dialog.xml b/packages/SystemUI/res/layout-land/volume_dialog.xml
new file mode 100644
index 0000000..c1e74ef
--- /dev/null
+++ b/packages/SystemUI/res/layout-land/volume_dialog.xml
@@ -0,0 +1,143 @@
+<!--
+  ~ 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
+  -->
+<FrameLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/volume_dialog_container"
+    android:layout_width="wrap_content"
+    android:layout_height="wrap_content"
+    android:gravity="right"
+    android:layout_gravity="right"
+    android:background="@android:color/transparent"
+    android:theme="@style/volume_dialog_theme">
+
+    <FrameLayout
+        android:id="@+id/volume_dialog"
+        android:minWidth="@dimen/volume_dialog_panel_width"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:gravity="right"
+        android:layout_gravity="right"
+        android:background="@android:color/transparent"
+        android:paddingRight="@dimen/volume_dialog_panel_transparent_padding_right"
+        android:paddingTop="@dimen/volume_dialog_panel_transparent_padding"
+        android:paddingBottom="@dimen/volume_dialog_panel_transparent_padding"
+        android:paddingLeft="@dimen/volume_dialog_panel_transparent_padding"
+        android:clipToPadding="false">
+
+        <FrameLayout
+            android:id="@+id/ringer"
+            android:layout_width="@dimen/volume_dialog_ringer_size"
+            android:layout_height="@dimen/volume_dialog_ringer_size"
+            android:layout_marginBottom="@dimen/volume_dialog_spacer"
+            android:gravity="right"
+            android:layout_gravity="right"
+            android:translationZ="@dimen/volume_dialog_elevation"
+            android:clipToPadding="false"
+            android:background="@drawable/rounded_bg_full">
+            <com.android.keyguard.AlphaOptimizedImageButton
+                android:id="@+id/ringer_icon"
+                style="@style/VolumeButtons"
+                android:background="@drawable/rounded_ripple"
+                android:layout_width="match_parent"
+                android:layout_height="match_parent"
+                android:tint="@color/accent_tint_color_selector"
+                android:layout_gravity="center"
+                android:soundEffectsEnabled="false" />
+
+            <include layout="@layout/volume_dnd_icon"
+                     android:layout_width="match_parent"
+                     android:layout_height="wrap_content"
+                     android:layout_marginRight="@dimen/volume_dialog_stream_padding"
+                     android:layout_marginTop="6dp"/>
+        </FrameLayout>
+
+        <LinearLayout
+            android:id="@+id/main"
+            android:layout_width="wrap_content"
+            android:minWidth="@dimen/volume_dialog_panel_width"
+            android:layout_height="wrap_content"
+            android:layout_marginTop="68dp"
+            android:gravity="right"
+            android:layout_gravity="right"
+            android:orientation="vertical"
+            android:translationZ="@dimen/volume_dialog_elevation"
+            android:clipChildren="false"
+            android:clipToPadding="false"
+            android:background="@drawable/rounded_bg_full" >
+            <LinearLayout
+                android:id="@+id/volume_dialog_rows"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:minWidth="@dimen/volume_dialog_panel_width"
+                android:gravity="center"
+                android:orientation="horizontal"
+                android:paddingRight="@dimen/volume_dialog_stream_padding"
+                android:paddingLeft="@dimen/volume_dialog_stream_padding">
+                <!-- volume rows added and removed here! :-) -->
+            </LinearLayout>
+            <FrameLayout
+                android:id="@+id/settings_container"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:background="@drawable/rounded_bg_bottom_background">
+                <com.android.keyguard.AlphaOptimizedImageButton
+                    android:id="@+id/settings"
+                    android:src="@drawable/ic_tune_black_16dp"
+                    android:layout_width="@dimen/volume_dialog_tap_target_size"
+                    android:layout_height="@dimen/volume_dialog_tap_target_size"
+                    android:layout_gravity="center"
+                    android:contentDescription="@string/accessibility_volume_settings"
+                    android:background="@drawable/ripple_drawable_20dp"
+                    android:tint="?android:attr/textColorSecondary"
+                    android:soundEffectsEnabled="false" />
+            </FrameLayout>
+        </LinearLayout>
+
+        <FrameLayout
+            android:id="@+id/odi_captions"
+            android:layout_width="@dimen/volume_dialog_caption_size"
+            android:layout_height="@dimen/volume_dialog_caption_size"
+            android:layout_marginRight="68dp"
+            android:gravity="right"
+            android:layout_gravity="right"
+            android:clipToPadding="false"
+            android:translationZ="@dimen/volume_dialog_elevation"
+            android:background="@drawable/rounded_bg_full">
+            <com.android.keyguard.AlphaOptimizedImageButton
+                android:id="@+id/odi_captions_icon"
+                android:src="@drawable/ic_volume_odi_captions_disabled"
+                style="@style/VolumeButtons"
+                android:background="@drawable/rounded_ripple"
+                android:layout_width="match_parent"
+                android:layout_height="match_parent"
+                android:tint="@color/accent_tint_color_selector"
+                android:layout_gravity="center"
+                android:soundEffectsEnabled="false" />
+        </FrameLayout>
+
+        <ViewStub
+            android:id="@+id/odi_captions_tooltip_stub"
+            android:inflatedId="@+id/odi_captions_tooltip_view"
+            android:layout="@layout/volume_tool_tip_view"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_marginRight="@dimen/volume_tool_tip_right_margin"
+            android:layout_marginTop="@dimen/volume_tool_tip_top_margin"
+            android:layout_gravity="right"/>
+
+    </FrameLayout>
+
+</FrameLayout>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/biometric_dialog.xml b/packages/SystemUI/res/layout/biometric_dialog.xml
index 1e8cd5a..83557f2 100644
--- a/packages/SystemUI/res/layout/biometric_dialog.xml
+++ b/packages/SystemUI/res/layout/biometric_dialog.xml
@@ -39,152 +39,158 @@
             android:layout_height="0dp"
             android:layout_weight="1" />
 
-        <LinearLayout
+        <ScrollView
             android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:orientation="horizontal">
-
-            <!-- This is not a Space since Spaces cannot be clicked. The width of this changes depending
-             on horizontal/portrait orientation -->
-            <View
-                android:id="@+id/left_space"
-                android:layout_weight="1"
-                android:layout_width="0dp"
-                android:layout_height="match_parent"/>
+            android:layout_height="wrap_content">
 
             <LinearLayout
-                android:id="@+id/dialog"
                 android:layout_width="match_parent"
                 android:layout_height="wrap_content"
-                android:orientation="vertical"
-                android:background="@drawable/biometric_dialog_bg"
-                android:layout_marginBottom="@dimen/biometric_dialog_border_padding"
-                android:layout_marginLeft="@dimen/biometric_dialog_border_padding"
-                android:layout_marginRight="@dimen/biometric_dialog_border_padding">
+                android:orientation="horizontal">
 
-                <TextView
-                    android:id="@+id/title"
-                    android:fontFamily="@*android:string/config_headlineFontFamilyMedium"
-                    android:layout_width="match_parent"
-                    android:layout_height="wrap_content"
-                    android:layout_marginEnd="24dp"
-                    android:layout_marginStart="24dp"
-                    android:layout_marginTop="24dp"
-                    android:gravity="@integer/biometric_dialog_text_gravity"
-                    android:textSize="20sp"
-                    android:maxLines="1"
-                    android:singleLine="true"
-                    android:ellipsize="marquee"
-                    android:marqueeRepeatLimit="marquee_forever"
-                    android:textColor="?android:attr/textColorPrimary"/>
+                <!-- This is not a Space since Spaces cannot be clicked. The width of this changes
+                depending on horizontal/portrait orientation -->
+                <View
+                    android:id="@+id/left_space"
+                    android:layout_weight="1"
+                    android:layout_width="0dp"
+                    android:layout_height="match_parent"/>
 
-                <TextView
-                    android:id="@+id/subtitle"
-                    android:layout_width="match_parent"
-                    android:layout_height="wrap_content"
-                    android:layout_marginTop="8dp"
-                    android:layout_marginStart="24dp"
-                    android:layout_marginEnd="24dp"
-                    android:gravity="@integer/biometric_dialog_text_gravity"
-                    android:textSize="16sp"
-                    android:maxLines="1"
-                    android:singleLine="true"
-                    android:ellipsize="marquee"
-                    android:marqueeRepeatLimit="marquee_forever"
-                    android:textColor="?android:attr/textColorPrimary"/>
+                    <LinearLayout
+                        android:id="@+id/dialog"
+                        android:layout_width="match_parent"
+                        android:layout_height="wrap_content"
+                        android:orientation="vertical"
+                        android:background="@drawable/biometric_dialog_bg"
+                        android:layout_marginBottom="@dimen/biometric_dialog_border_padding"
+                        android:layout_marginLeft="@dimen/biometric_dialog_border_padding"
+                        android:layout_marginRight="@dimen/biometric_dialog_border_padding">
 
-                <TextView
-                    android:id="@+id/description"
-                    android:layout_width="match_parent"
-                    android:layout_height="wrap_content"
-                    android:layout_marginEnd="24dp"
-                    android:layout_marginStart="24dp"
-                    android:gravity="@integer/biometric_dialog_text_gravity"
-                    android:paddingTop="8dp"
-                    android:textSize="16sp"
-                    android:maxLines="4"
-                    android:textColor="?android:attr/textColorPrimary"/>
+                        <TextView
+                            android:id="@+id/title"
+                            android:fontFamily="@*android:string/config_headlineFontFamilyMedium"
+                            android:layout_width="match_parent"
+                            android:layout_height="wrap_content"
+                            android:layout_marginEnd="24dp"
+                            android:layout_marginStart="24dp"
+                            android:layout_marginTop="24dp"
+                            android:gravity="@integer/biometric_dialog_text_gravity"
+                            android:textSize="20sp"
+                            android:maxLines="1"
+                            android:singleLine="true"
+                            android:ellipsize="marquee"
+                            android:marqueeRepeatLimit="marquee_forever"
+                            android:textColor="?android:attr/textColorPrimary"/>
 
-                <ImageView
-                    android:id="@+id/biometric_icon"
-                    android:layout_width="@dimen/biometric_dialog_biometric_icon_size"
-                    android:layout_height="@dimen/biometric_dialog_biometric_icon_size"
-                    android:layout_gravity="center_horizontal"
-                    android:layout_marginTop="48dp"
-                    android:scaleType="fitXY" />
+                        <TextView
+                            android:id="@+id/subtitle"
+                            android:layout_width="match_parent"
+                            android:layout_height="wrap_content"
+                            android:layout_marginTop="8dp"
+                            android:layout_marginStart="24dp"
+                            android:layout_marginEnd="24dp"
+                            android:gravity="@integer/biometric_dialog_text_gravity"
+                            android:textSize="16sp"
+                            android:maxLines="1"
+                            android:singleLine="true"
+                            android:ellipsize="marquee"
+                            android:marqueeRepeatLimit="marquee_forever"
+                            android:textColor="?android:attr/textColorPrimary"/>
 
-                <TextView
-                    android:id="@+id/error"
-                    android:layout_width="match_parent"
-                    android:layout_height="wrap_content"
-                    android:layout_marginEnd="24dp"
-                    android:layout_marginStart="24dp"
-                    android:paddingTop="16dp"
-                    android:paddingBottom="24dp"
-                    android:textSize="12sp"
-                    android:gravity="center_horizontal"
-                    android:accessibilityLiveRegion="polite"
-                    android:contentDescription="@string/accessibility_biometric_dialog_help_area"
-                    android:textColor="?android:attr/textColorSecondary"/>
+                        <TextView
+                            android:id="@+id/description"
+                            android:layout_width="match_parent"
+                            android:layout_height="wrap_content"
+                            android:layout_marginEnd="24dp"
+                            android:layout_marginStart="24dp"
+                            android:gravity="@integer/biometric_dialog_text_gravity"
+                            android:paddingTop="8dp"
+                            android:textSize="16sp"
+                            android:maxLines="4"
+                            android:textColor="?android:attr/textColorPrimary"/>
 
-                <LinearLayout
-                    android:layout_width="match_parent"
-                    android:layout_height="72dip"
-                    android:paddingTop="24dp"
-                    android:layout_gravity="center_vertical"
-                    style="?android:attr/buttonBarStyle"
-                    android:orientation="horizontal"
-                    android:measureWithLargestChild="true">
-                    <Space android:id="@+id/leftSpacer"
-                        android:layout_width="12dp"
-                        android:layout_height="match_parent"
-                        android:visibility="visible" />
-                    <!-- Negative Button -->
-                    <Button android:id="@+id/button2"
-                        android:layout_width="wrap_content"
-                        android:layout_height="match_parent"
-                        style="@*android:style/Widget.DeviceDefault.Button.Borderless.Colored"
-                        android:gravity="center"
-                        android:maxLines="2" />
-                    <Space android:id="@+id/middleSpacer"
-                        android:layout_width="0dp"
-                        android:layout_height="match_parent"
-                        android:layout_weight="1"
-                        android:visibility="visible" />
-                    <!-- Positive Button -->
-                    <Button android:id="@+id/button1"
-                        android:layout_width="wrap_content"
-                        android:layout_height="match_parent"
-                        style="@*android:style/Widget.DeviceDefault.Button.Colored"
-                        android:gravity="center"
-                        android:maxLines="2"
-                        android:text="@string/biometric_dialog_confirm"
-                        android:visibility="gone"/>
-                    <!-- Try Again Button -->
-                    <Button android:id="@+id/button_try_again"
-                        android:layout_width="wrap_content"
-                        android:layout_height="match_parent"
-                        style="@*android:style/Widget.DeviceDefault.Button.Colored"
-                        android:gravity="center"
-                        android:maxLines="2"
-                        android:text="@string/biometric_dialog_try_again"
-                        android:visibility="gone"/>
-                    <Space android:id="@+id/rightSpacer"
-                        android:layout_width="12dip"
-                        android:layout_height="match_parent"
-                        android:visibility="visible" />
-                </LinearLayout>
+                        <ImageView
+                            android:id="@+id/biometric_icon"
+                            android:layout_width="@dimen/biometric_dialog_biometric_icon_size"
+                            android:layout_height="@dimen/biometric_dialog_biometric_icon_size"
+                            android:layout_gravity="center_horizontal"
+                            android:layout_marginTop="48dp"
+                            android:scaleType="fitXY" />
+
+                        <TextView
+                            android:id="@+id/error"
+                            android:layout_width="match_parent"
+                            android:layout_height="wrap_content"
+                            android:layout_marginEnd="24dp"
+                            android:layout_marginStart="24dp"
+                            android:paddingTop="16dp"
+                            android:paddingBottom="24dp"
+                            android:textSize="12sp"
+                            android:gravity="center_horizontal"
+                            android:accessibilityLiveRegion="polite"
+                            android:contentDescription="@string/accessibility_biometric_dialog_help_area"
+                            android:textColor="?android:attr/textColorSecondary"/>
+
+                        <LinearLayout
+                            android:layout_width="match_parent"
+                            android:layout_height="72dip"
+                            android:paddingTop="24dp"
+                            android:layout_gravity="center_vertical"
+                            style="?android:attr/buttonBarStyle"
+                            android:orientation="horizontal"
+                            android:measureWithLargestChild="true">
+                            <Space android:id="@+id/leftSpacer"
+                                android:layout_width="12dp"
+                                android:layout_height="match_parent"
+                                android:visibility="visible" />
+                            <!-- Negative Button -->
+                            <Button android:id="@+id/button2"
+                                android:layout_width="wrap_content"
+                                android:layout_height="match_parent"
+                                style="@*android:style/Widget.DeviceDefault.Button.Borderless.Colored"
+                                android:gravity="center"
+                                android:maxLines="2" />
+                            <Space android:id="@+id/middleSpacer"
+                                android:layout_width="0dp"
+                                android:layout_height="match_parent"
+                                android:layout_weight="1"
+                                android:visibility="visible" />
+                            <!-- Positive Button -->
+                            <Button android:id="@+id/button1"
+                                android:layout_width="wrap_content"
+                                android:layout_height="match_parent"
+                                style="@*android:style/Widget.DeviceDefault.Button.Colored"
+                                android:gravity="center"
+                                android:maxLines="2"
+                                android:text="@string/biometric_dialog_confirm"
+                                android:visibility="gone"/>
+                            <!-- Try Again Button -->
+                            <Button android:id="@+id/button_try_again"
+                                android:layout_width="wrap_content"
+                                android:layout_height="match_parent"
+                                style="@*android:style/Widget.DeviceDefault.Button.Colored"
+                                android:gravity="center"
+                                android:maxLines="2"
+                                android:text="@string/biometric_dialog_try_again"
+                                android:visibility="gone"/>
+                            <Space android:id="@+id/rightSpacer"
+                                android:layout_width="12dip"
+                                android:layout_height="match_parent"
+                                android:visibility="visible" />
+                        </LinearLayout>
+                    </LinearLayout>
+
+                <!-- This is not a Space since Spaces cannot be clicked. The width of this changes
+                depending on horizontal/portrait orientation -->
+                <View
+                    android:id="@+id/right_space"
+                    android:layout_weight="1"
+                    android:layout_width="0dp"
+                    android:layout_height="match_parent" />
+
             </LinearLayout>
 
-            <!-- This is not a Space since Spaces cannot be clicked. The width of this changes depending
-             on horizontal/portrait orientation -->
-            <View
-                android:id="@+id/right_space"
-                android:layout_weight="1"
-                android:layout_width="0dp"
-                android:layout_height="match_parent" />
-
-        </LinearLayout>
+        </ScrollView>
 
     </LinearLayout>
 
diff --git a/packages/SystemUI/res/layout/qs_carrier.xml b/packages/SystemUI/res/layout/qs_carrier.xml
index 6edccba..b94a316 100644
--- a/packages/SystemUI/res/layout/qs_carrier.xml
+++ b/packages/SystemUI/res/layout/qs_carrier.xml
@@ -24,7 +24,8 @@
     android:background="@android:color/transparent"
     android:clickable="false"
     android:clipChildren="false"
-    android:clipToPadding="false" >
+    android:clipToPadding="false"
+    android:focusable="true" >
 
     <include
         layout="@layout/mobile_signal_group"
diff --git a/packages/SystemUI/res/layout/qs_carrier_group.xml b/packages/SystemUI/res/layout/qs_carrier_group.xml
index 20190b7..36f382b 100644
--- a/packages/SystemUI/res/layout/qs_carrier_group.xml
+++ b/packages/SystemUI/res/layout/qs_carrier_group.xml
@@ -34,7 +34,8 @@
         android:id="@+id/qs_carrier_divider1"
         android:layout_width="@dimen/qs_header_carrier_separator_width"
         android:layout_height="match_parent"
-        android:visibility="gone" />
+        android:visibility="gone"
+        android:importantForAccessibility="no"/>
 
     <include
         layout="@layout/qs_carrier"
@@ -47,7 +48,8 @@
         android:layout_width="@dimen/qs_header_carrier_separator_width"
         android:layout_height="match_parent"
         android:layout_weight="1"
-        android:visibility="gone" />
+        android:visibility="gone"
+        android:importantForAccessibility="no"/>
 
     <include
         layout="@layout/qs_carrier"
diff --git a/packages/SystemUI/res/layout/quick_qs_status_icons.xml b/packages/SystemUI/res/layout/quick_qs_status_icons.xml
index 74002ac..fa74536 100644
--- a/packages/SystemUI/res/layout/quick_qs_status_icons.xml
+++ b/packages/SystemUI/res/layout/quick_qs_status_icons.xml
@@ -26,7 +26,9 @@
     android:layout_below="@id/quick_status_bar_system_icons"
     android:clipChildren="false"
     android:clipToPadding="false"
-    android:minHeight="20dp" >
+    android:minHeight="20dp"
+    android:clickable="false"
+    android:focusable="true">
 
     <com.android.systemui.statusbar.policy.DateView
         android:id="@+id/date"
diff --git a/packages/SystemUI/res/layout/screen_record_dialog.xml b/packages/SystemUI/res/layout/screen_record_dialog.xml
index 6c5c7fa..3d63b7d 100644
--- a/packages/SystemUI/res/layout/screen_record_dialog.xml
+++ b/packages/SystemUI/res/layout/screen_record_dialog.xml
@@ -5,26 +5,25 @@
               android:clipChildren="false"
               android:clipToPadding="false"
               android:gravity="top"
-              android:orientation="vertical">
-
-    <Space
-        android:layout_width="match_parent"
-        android:layout_height="10dp"/>
+              android:orientation="vertical"
+              android:padding="@dimen/global_actions_padding"
+              android:background="@drawable/rounded_bg_full">
 
     <LinearLayout
         android:layout_width="match_parent"
         android:layout_height="match_parent"
-        android:orientation="vertical"
-        android:background="@android:color/white">
+        android:orientation="vertical">
         <CheckBox
             android:id="@+id/checkbox_mic"
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
+            android:textAppearance="?android:attr/textAppearanceMedium"
             android:text="@string/screenrecord_mic_label"/>
         <CheckBox
             android:id="@+id/checkbox_taps"
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
+            android:textAppearance="?android:attr/textAppearanceMedium"
             android:text="@string/screenrecord_taps_label"/>
         <Button
             android:id="@+id/record_button"
@@ -34,8 +33,4 @@
         />
     </LinearLayout>
 
-    <Space
-        android:layout_width="match_parent"
-        android:layout_height="10dp"/>
-
 </LinearLayout>
diff --git a/packages/SystemUI/res/layout/volume_dialog.xml b/packages/SystemUI/res/layout/volume_dialog.xml
index 130be89..1d0a242 100644
--- a/packages/SystemUI/res/layout/volume_dialog.xml
+++ b/packages/SystemUI/res/layout/volume_dialog.xml
@@ -15,32 +15,38 @@
 -->
 <FrameLayout
     xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/volume_dialog_container"
     android:layout_width="wrap_content"
     android:layout_height="wrap_content"
+    android:gravity="right"
+    android:layout_gravity="right"
     android:background="@android:color/transparent"
-    android:theme="@style/qs_theme">
+    android:theme="@style/volume_dialog_theme">
+
     <!-- right-aligned to be physically near volume button -->
     <LinearLayout
         android:id="@+id/volume_dialog"
         android:minWidth="@dimen/volume_dialog_panel_width"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
-        android:layout_gravity="center_vertical|right"
+        android:gravity="right"
+        android:layout_gravity="right"
         android:background="@android:color/transparent"
         android:paddingRight="@dimen/volume_dialog_panel_transparent_padding_right"
         android:paddingTop="@dimen/volume_dialog_panel_transparent_padding"
         android:paddingBottom="@dimen/volume_dialog_panel_transparent_padding"
         android:paddingLeft="@dimen/volume_dialog_panel_transparent_padding"
         android:orientation="vertical"
-        android:clipToPadding="false" >
+        android:clipToPadding="false">
 
         <FrameLayout
             android:id="@+id/ringer"
             android:layout_width="@dimen/volume_dialog_ringer_size"
             android:layout_height="@dimen/volume_dialog_ringer_size"
             android:layout_marginBottom="@dimen/volume_dialog_spacer"
-            android:translationZ="@dimen/volume_dialog_elevation"
+            android:gravity="right"
             android:layout_gravity="right"
+            android:translationZ="@dimen/volume_dialog_elevation"
             android:clipToPadding="false"
             android:background="@drawable/rounded_bg_full">
             <com.android.keyguard.AlphaOptimizedImageButton
@@ -62,11 +68,14 @@
 
         <LinearLayout
             android:id="@+id/main"
-            android:layout_width="wrap_content"
             android:minWidth="@dimen/volume_dialog_panel_width"
+            android:layout_width="wrap_content"
             android:layout_height="wrap_content"
+            android:gravity="right"
+            android:layout_gravity="right"
             android:orientation="vertical"
             android:translationZ="@dimen/volume_dialog_elevation"
+            android:clipChildren="false"
             android:clipToPadding="false"
             android:background="@drawable/rounded_bg_full" >
             <LinearLayout
@@ -103,10 +112,10 @@
             android:layout_width="@dimen/volume_dialog_caption_size"
             android:layout_height="@dimen/volume_dialog_caption_size"
             android:layout_marginTop="@dimen/volume_dialog_spacer"
-            android:translationZ="@dimen/volume_dialog_elevation"
+            android:gravity="right"
             android:layout_gravity="right"
             android:clipToPadding="false"
-            android:visibility="gone"
+            android:translationZ="@dimen/volume_dialog_elevation"
             android:background="@drawable/rounded_bg_full">
             <com.android.keyguard.AlphaOptimizedImageButton
                 android:id="@+id/odi_captions_icon"
@@ -121,4 +130,15 @@
         </FrameLayout>
 
     </LinearLayout>
+
+    <ViewStub
+        android:id="@+id/odi_captions_tooltip_stub"
+        android:inflatedId="@+id/odi_captions_tooltip_view"
+        android:layout="@layout/volume_tool_tip_view"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_gravity="bottom | right"
+        android:layout_marginRight="@dimen/volume_tool_tip_right_margin"
+        android:layout_marginBottom="@dimen/volume_tool_tip_bottom_margin"/>
+
 </FrameLayout>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/volume_dialog_row.xml b/packages/SystemUI/res/layout/volume_dialog_row.xml
index 6128da8..b9efc5b 100644
--- a/packages/SystemUI/res/layout/volume_dialog_row.xml
+++ b/packages/SystemUI/res/layout/volume_dialog_row.xml
@@ -20,7 +20,7 @@
     android:layout_width="@dimen/volume_dialog_panel_width"
     android:clipChildren="false"
     android:clipToPadding="false"
-    android:theme="@style/qs_theme">
+    android:theme="@style/volume_dialog_theme">
 
     <LinearLayout
         android:layout_height="wrap_content"
diff --git a/packages/SystemUI/res/layout/volume_tool_tip_view.xml b/packages/SystemUI/res/layout/volume_tool_tip_view.xml
new file mode 100644
index 0000000..9fe885e
--- /dev/null
+++ b/packages/SystemUI/res/layout/volume_tool_tip_view.xml
@@ -0,0 +1,63 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ 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
+  -->
+
+<com.android.systemui.volume.VolumeToolTipView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/tooltip_view"
+    android:layout_height="wrap_content"
+    android:layout_width="wrap_content"
+    android:orientation="horizontal">
+
+    <LinearLayout
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:paddingStart="16dp"
+        android:paddingEnd="4dp"
+        android:background="@drawable/volume_tool_tip_rounded_bg"
+        android:orientation="horizontal">
+
+        <TextView
+            android:id="@+id/text"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_gravity="center_vertical"
+            android:textColor="@android:color/white"
+            android:text="@string/volume_odi_captions_tip"
+            android:textSize="14sp"/>
+        <ImageView
+            android:id="@+id/dismiss"
+            android:layout_width="40dp"
+            android:layout_height="40dp"
+            android:layout_gravity="center_vertical"
+            android:padding="12dp"
+            android:layout_marginStart="2dp"
+            android:layout_marginEnd="2dp"
+            android:alpha="0.7"
+            android:src="@drawable/ic_remove_no_shadow"
+            android:tint="@android:color/white"
+            android:background="?android:attr/selectableItemBackgroundBorderless"
+            android:contentDescription="@string/accessibility_volume_close_odi_captions_tip"/>
+    </LinearLayout>
+
+    <View
+        android:id="@+id/arrow"
+        android:layout_width="8dp"
+        android:layout_height="10dp"
+        android:layout_marginLeft="-2dp"
+        android:layout_gravity="center_vertical"/>
+
+</com.android.systemui.volume.VolumeToolTipView>
\ No newline at end of file
diff --git a/packages/SystemUI/res/values-land/dimens.xml b/packages/SystemUI/res/values-land/dimens.xml
index bb0c6f6..77e79c9 100644
--- a/packages/SystemUI/res/values-land/dimens.xml
+++ b/packages/SystemUI/res/values-land/dimens.xml
@@ -34,4 +34,7 @@
     <bool name="quick_settings_wide">true</bool>
     <dimen name="qs_detail_margin_top">0dp</dimen>
     <dimen name="qs_paged_tile_layout_padding_bottom">0dp</dimen>
+
+    <dimen name="volume_tool_tip_right_margin">136dp</dimen>
+    <dimen name="volume_tool_tip_top_margin">12dp</dimen>
 </resources>
diff --git a/packages/SystemUI/res/values/attrs.xml b/packages/SystemUI/res/values/attrs.xml
index 0fed96e..27d2bcd 100644
--- a/packages/SystemUI/res/values/attrs.xml
+++ b/packages/SystemUI/res/values/attrs.xml
@@ -18,8 +18,6 @@
     <declare-styleable name="KeyButtonView">
         <!-- key code to send when pressed; if absent or 0, no key is sent -->
         <attr name="keyCode" format="integer" />
-        <!-- does this button generate longpress / repeat events? -->
-        <attr name="keyRepeat" format="boolean" />
         <!-- Should this button play sound effects, default true -->
         <attr name="playSound" format="boolean" />
         <attr name="android:contentDescription" />
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 30cbaaa..27cebcc 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -351,6 +351,12 @@
 
     <dimen name="volume_dialog_elevation">9dp</dimen>
 
+    <dimen name="volume_tool_tip_right_margin">76dp</dimen>
+
+    <dimen name="volume_tool_tip_bottom_margin">32dp</dimen>
+
+    <dimen name="volume_tool_tip_arrow_corner_radius">2dp</dimen>
+
     <!-- Gravity for the notification panel -->
     <integer name="notification_panel_layout_gravity">0x31</integer><!-- center_horizontal|top -->
 
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index da43391..f8bec4a 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -447,6 +447,9 @@
     <!-- Content description of the cell data being disabled. [CHAR LIMIT=NONE] -->
     <string name="cell_data_off_content_description">Mobile data off</string>
 
+    <!-- Content description of the cell data for not default subscription. [CHAR LIMIT=NONE] -->
+    <string name="not_default_data_content_description">Not set to use data</string>
+
     <!-- Content description of the cell data being disabled but shortened. [CHAR LIMIT=20] -->
     <string name="cell_data_off">Off</string>
 
@@ -1069,10 +1072,10 @@
     <string name="battery_saver_notification_action_text">Turn off Battery Saver</string>
 
     <!-- Media projection permission dialog warning text. [CHAR LIMIT=NONE] -->
-    <string name="media_projection_dialog_text"><xliff:g id="app_seeking_permission" example="Hangouts">%s</xliff:g> will start capturing everything on your screen including notifications, passwords, photos, messages and payment information.</string>
+    <string name="media_projection_dialog_text">While recording or casting, <xliff:g id="app_seeking_permission" example="Hangouts">%s</xliff:g> can capture any sensitive information, such as audio that you play and your passwords, payment info, photos, and messages.</string>
 
     <!-- Media projection permission dialog warning title. [CHAR LIMIT=NONE] -->
-    <string name="media_projection_dialog_title">Allow <xliff:g id="app_seeking_permission" example="Hangouts">%s</xliff:g> to record or cast your screen?</string>
+    <string name="media_projection_dialog_title">Exposing sensitive info during casting/recording </string>
 
     <!-- Media projection permission dialog permanent grant check box. [CHAR LIMIT=NONE] -->
     <string name="media_projection_remember_text">Don\'t show again</string>
@@ -1307,6 +1310,12 @@
     <!-- Content description for accessibility (not shown on the screen): volume dialog collapse button. [CHAR LIMIT=NONE] -->
     <string name="accessibility_volume_collapse">Collapse</string>
 
+    <!-- Label for the odi caption initial tool tip. [CHAR LIMIT=28] -->
+    <string name="volume_odi_captions_tip">Automatically caption media</string>
+
+    <!-- Content description for accessibility: Clear the odi caption tool tip. [CHAR LIMIT=NONE] -->
+    <string name="accessibility_volume_close_odi_captions_tip">Close captions tip</string>
+
     <!-- content description for audio output chooser [CHAR LIMIT=NONE]-->
     <string name="accessibility_output_chooser">Switch output device</string>
 
@@ -2370,12 +2379,29 @@
     <string name="bubbles_deep_link_button_description">Open <xliff:g id="app_name" example="YouTube">%1$s</xliff:g></string>
     <!-- Text used for content description of settings button in the header of expanded bubble
          view. [CHAR_LIMIT=NONE] -->
-    <string name="bubbles_settings_button_description">Open notification settings for <xliff:g id="app_name" example="YouTube">%1$s</xliff:g></string>
+    <string name="bubbles_settings_button_description">Settings for <xliff:g id="app_name" example="YouTube">%1$s</xliff:g> bubbles</string>
     <!-- Text for asking the user whether bubbles (floating app content) should be enabled for an
          app. [CHAR LIMIT=NONE] -->
-    <string name="bubbles_prompt">Allow bubbles from this app?</string>
+    <string name="bubbles_prompt">Allow bubbles from <xliff:g id="app_name" example="YouTube">%1$s</xliff:g>?</string>
     <!-- Text used for button allowing user to opt out of bubbles [CHAR LIMIT=20] -->
-    <string name="no_bubbles">Block</string>
+    <string name="no_bubbles">Deny</string>
     <!-- Text used for button allowing user to approve / enable bubbles [CHAR LIMIT=20] -->
     <string name="yes_bubbles">Allow</string>
+    <!-- Text used for the button allowing users to postpone their decision to allow or deny bubbles [CHAR LIMIT=40] -->
+    <string name="ask_me_later_bubbles">Ask me later</string>
+    <!-- Content description when a bubble is focused. [CHAR LIMIT=NONE] -->
+    <string name="bubble_content_description_single"><xliff:g id="notification_title" example="some title">%1$s</xliff:g> from <xliff:g id="app_name" example="YouTube">%2$s</xliff:g></string>
+    <!-- Content description when the stack of bubbles is focused. [CHAR LIMIT=NONE] -->
+    <string name="bubble_content_description_stack"><xliff:g id="notification_title" example="some title">%1$s</xliff:g> from <xliff:g id="app_name" example="YouTube">%2$s</xliff:g> and <xliff:g id="bubble_count" example="4">%3$d</xliff:g> more</string>
+    <!-- Action in accessibility menu to move the stack of bubbles [CHAR LIMIT=20] -->
+    <string name="bubble_accessibility_action_move">Move</string>
+    <!-- Action in accessibility menu to move the stack of bubbles to the top left of the screen. [CHAR LIMIT=30] -->
+    <string name="bubble_accessibility_action_move_top_left">Move top left</string>
+    <!-- Action in accessibility menu to move the stack of bubbles to the top right of the screen. [CHAR LIMIT=30] -->
+    <string name="bubble_accessibility_action_move_top_right">Move top right</string>
+    <!-- Action in accessibility menu to move the stack of bubbles to the bottom left of the screen. [CHAR LIMIT=30]-->
+    <string name="bubble_accessibility_action_move_bottom_left">Move bottom left</string>
+    <!-- Action in accessibility menu to move the stack of bubbles to the bottom right of the screen. [CHAR LIMIT=30]-->
+    <string name="bubble_accessibility_action_move_bottom_right">Move bottom right</string>
+
 </resources>
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index 0f5df45..1c13750 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -319,6 +319,10 @@
         <item name="android:windowIsFloating">true</item>
     </style>
 
+    <style name="volume_dialog_theme" parent="qs_theme">
+        <item name="android:windowIsFloating">false</item>
+    </style>
+
     <style name="systemui_theme_remote_input" parent="@android:style/Theme.DeviceDefault.Light">
         <item name="android:colorAccent">@color/remote_input_accent</item>
     </style>
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java
index 0f71ffb..6b07ed8 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java
@@ -219,6 +219,7 @@
             IRecentsAnimationRunner runner = null;
             if (animationHandler != null) {
                 runner = new IRecentsAnimationRunner.Stub() {
+                    @Override
                     public void onAnimationStart(IRecentsAnimationController controller,
                             RemoteAnimationTarget[] apps, Rect homeContentInsets,
                             Rect minimizedHomeBounds) {
@@ -230,8 +231,9 @@
                                 homeContentInsets, minimizedHomeBounds);
                     }
 
-                    public void onAnimationCanceled() {
-                        animationHandler.onAnimationCanceled();
+                    @Override
+                    public void onAnimationCanceled(boolean deferredWithScreenshot) {
+                        animationHandler.onAnimationCanceled(deferredWithScreenshot);
                     }
                 };
             }
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RecentsAnimationControllerCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RecentsAnimationControllerCompat.java
index 9bebb14..1d9105c 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RecentsAnimationControllerCompat.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RecentsAnimationControllerCompat.java
@@ -84,4 +84,20 @@
             Log.e(TAG, "Failed to finish recents animation", e);
         }
     }
+
+    public void setCancelWithDeferredScreenshot(boolean screenshot) {
+        try {
+            mAnimationController.setCancelWithDeferredScreenshot(screenshot);
+        } catch (RemoteException e) {
+            Log.e(TAG, "Failed to set cancel with deferred screenshot", e);
+        }
+    }
+
+    public void cleanupScreenshot() {
+        try {
+            mAnimationController.cleanupScreenshot();
+        } catch (RemoteException e) {
+            Log.e(TAG, "Failed to clean up screenshot of recents animation", e);
+        }
+    }
 }
\ No newline at end of file
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RecentsAnimationListener.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RecentsAnimationListener.java
index a473db1..5850fda 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RecentsAnimationListener.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RecentsAnimationListener.java
@@ -29,5 +29,5 @@
     /**
      * Called when the animation into Recents was canceled. This call is made on the binder thread.
      */
-    void onAnimationCanceled();
-}
\ No newline at end of file
+    void onAnimationCanceled(boolean deferredWithScreenshot);
+}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java
index d40fa66..ce65b5a 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java
@@ -60,8 +60,8 @@
      */
     private ViewGroup mBigClockContainer;
     /**
-     * Status area (date and other stuff) shown below the clock. Plugin can decide whether
-     * or not to show it below the alternate clock.
+     * Status area (date and other stuff) shown below the clock. Plugin can decide whether or not to
+     * show it below the alternate clock.
      */
     private View mKeyguardStatusArea;
     /**
@@ -75,24 +75,19 @@
     private boolean mSupportsDarkText;
     private int[] mColorPalette;
 
+    /**
+     * Track the state of the status bar to know when to hide the big_clock_container.
+     */
+    private int mStatusBarState;
+
     private final StatusBarStateController.StateListener mStateListener =
             new StatusBarStateController.StateListener() {
                 @Override
                 public void onStateChanged(int newState) {
-                    if (mBigClockContainer == null) {
-                        return;
-                    }
-                    if (newState == StatusBarState.SHADE) {
-                        if (mBigClockContainer.getVisibility() == View.VISIBLE) {
-                            mBigClockContainer.setVisibility(View.INVISIBLE);
-                        }
-                    } else {
-                        if (mBigClockContainer.getVisibility() == View.INVISIBLE) {
-                            mBigClockContainer.setVisibility(View.VISIBLE);
-                        }
-                    }
+                    mStatusBarState = newState;
+                    updateBigClockVisibility();
                 }
-    };
+            };
 
     private ClockManager.ClockChangedListener mClockChangedListener = this::setClockPlugin;
 
@@ -139,7 +134,9 @@
     protected void onAttachedToWindow() {
         super.onAttachedToWindow();
         Dependency.get(ClockManager.class).addOnClockChangedListener(mClockChangedListener);
-        Dependency.get(StatusBarStateController.class).addCallback(mStateListener);
+        StatusBarStateController stateController = Dependency.get(StatusBarStateController.class);
+        stateController.addCallback(mStateListener);
+        mStateListener.onStateChanged(stateController.getState());
         SysuiColorExtractor colorExtractor = Dependency.get(SysuiColorExtractor.class);
         colorExtractor.addOnColorsChangedListener(mColorsListener);
         updateColors(colorExtractor);
@@ -151,7 +148,7 @@
         Dependency.get(ClockManager.class).removeOnClockChangedListener(mClockChangedListener);
         Dependency.get(StatusBarStateController.class).removeCallback(mStateListener);
         Dependency.get(SysuiColorExtractor.class)
-            .removeOnColorsChangedListener(mColorsListener);
+                .removeOnColorsChangedListener(mColorsListener);
         setClockPlugin(null);
     }
 
@@ -164,7 +161,7 @@
             }
             if (mBigClockContainer != null) {
                 mBigClockContainer.removeAllViews();
-                mBigClockContainer.setVisibility(View.GONE);
+                updateBigClockVisibility();
             }
             mClockPlugin = null;
         }
@@ -184,7 +181,7 @@
         View bigClockView = plugin.getBigClockView();
         if (bigClockView != null && mBigClockContainer != null) {
             mBigClockContainer.addView(bigClockView);
-            mBigClockContainer.setVisibility(View.VISIBLE);
+            updateBigClockVisibility();
         }
         // Hide default clock.
         if (!plugin.shouldShowStatusArea()) {
@@ -208,12 +205,10 @@
             View bigClockView = mClockPlugin.getBigClockView();
             if (bigClockView != null) {
                 container.addView(bigClockView);
-                if (container.getVisibility() == View.GONE) {
-                    container.setVisibility(View.VISIBLE);
-                }
             }
         }
         mBigClockContainer = container;
+        updateBigClockVisibility();
     }
 
     /**
@@ -254,6 +249,7 @@
 
     /**
      * Set the amount (ratio) that the device has transitioned to doze.
+     *
      * @param darkAmount Amount of transition to doze: 1f for doze and 0f for awake.
      */
     public void setDarkAmount(float darkAmount) {
@@ -307,9 +303,24 @@
         }
     }
 
+    private void updateBigClockVisibility() {
+        if (mBigClockContainer == null) {
+            return;
+        }
+        final boolean inDisplayState = mStatusBarState == StatusBarState.KEYGUARD
+                || mStatusBarState == StatusBarState.SHADE_LOCKED;
+        final int visibility =
+                inDisplayState && mBigClockContainer.getChildCount() != 0 ? View.VISIBLE
+                        : View.GONE;
+        if (mBigClockContainer.getVisibility() != visibility) {
+            mBigClockContainer.setVisibility(visibility);
+        }
+    }
+
     /**
-     * Sets if the keyguard slice is showing a center-aligned header. We need a smaller clock
-     * in these cases.
+     * Sets if the keyguard slice is showing a center-aligned header. We need a smaller clock in
+     * these
+     * cases.
      */
     public void setKeyguardShowingHeader(boolean hasHeader) {
         if (mShowingHeader == hasHeader || hasCustomClock()) {
@@ -327,12 +338,12 @@
                 mClockView.getPaddingRight(), paddingBottom);
     }
 
-    @VisibleForTesting (otherwise = VisibleForTesting.NONE)
+    @VisibleForTesting(otherwise = VisibleForTesting.NONE)
     ClockManager.ClockChangedListener getClockChangedListener() {
         return mClockChangedListener;
     }
 
-    @VisibleForTesting (otherwise = VisibleForTesting.NONE)
+    @VisibleForTesting(otherwise = VisibleForTesting.NONE)
     StatusBarStateController.StateListener getStateListener() {
         return mStateListener;
     }
@@ -352,7 +363,8 @@
 
     /**
      * Special layout transition that scales the clock view as its bounds change, to make it look
-     * like the text is shrinking.
+     * like
+     * the text is shrinking.
      */
     private class ClockBoundsTransition extends ChangeBounds {
 
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardHostView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardHostView.java
index cf22286..14ead04 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardHostView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardHostView.java
@@ -157,6 +157,10 @@
         mSecurityContainer.showPrimarySecurityScreen(false);
     }
 
+    public KeyguardSecurityView getCurrentSecurityView() {
+        return mSecurityContainer != null ? mSecurityContainer.getCurrentSecurityView() : null;
+    }
+
     /**
      * Show a string explaining why the security view needs to be solved.
      *
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
index 14df70c..e87b313 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
@@ -53,6 +53,7 @@
     private KeyguardSecurityViewFlipper mSecurityViewFlipper;
     private boolean mIsVerifyUnlockOnly;
     private SecurityMode mCurrentSecuritySelection = SecurityMode.Invalid;
+    private KeyguardSecurityView mCurrentSecurityView;
     private SecurityCallback mSecurityCallback;
     private AlertDialog mAlertDialog;
 
@@ -405,6 +406,7 @@
         }
 
         mCurrentSecuritySelection = securityMode;
+        mCurrentSecurityView = newView;
         mSecurityCallback.onSecurityModeChanged(securityMode,
                 securityMode != SecurityMode.None && newView.needsInput());
     }
@@ -506,6 +508,10 @@
         return mCurrentSecuritySelection;
     }
 
+    public KeyguardSecurityView getCurrentSecurityView() {
+        return mCurrentSecurityView;
+    }
+
     public void verifyUnlock() {
         mIsVerifyUnlockOnly = true;
         showSecurityScreen(getSecurityMode());
diff --git a/packages/SystemUI/src/com/android/systemui/Dependency.java b/packages/SystemUI/src/com/android/systemui/Dependency.java
index b7d1900..70f2cce 100644
--- a/packages/SystemUI/src/com/android/systemui/Dependency.java
+++ b/packages/SystemUI/src/com/android/systemui/Dependency.java
@@ -97,6 +97,7 @@
 import com.android.systemui.statusbar.policy.RemoteInputQuickSettingsDisabler;
 import com.android.systemui.statusbar.policy.RotationLockController;
 import com.android.systemui.statusbar.policy.SecurityController;
+import com.android.systemui.statusbar.policy.SensorPrivacyController;
 import com.android.systemui.statusbar.policy.SmartReplyConstants;
 import com.android.systemui.statusbar.policy.UserInfoController;
 import com.android.systemui.statusbar.policy.UserSwitcherController;
@@ -291,6 +292,7 @@
     @Inject Lazy<ActivityManagerWrapper> mActivityManagerWrapper;
     @Inject Lazy<DevicePolicyManagerWrapper> mDevicePolicyManagerWrapper;
     @Inject Lazy<PackageManagerWrapper> mPackageManagerWrapper;
+    @Inject Lazy<SensorPrivacyController> mSensorPrivacyController;
 
     @Inject
     public Dependency() {
@@ -461,6 +463,7 @@
         mProviders.put(ActivityManagerWrapper.class, mActivityManagerWrapper::get);
         mProviders.put(DevicePolicyManagerWrapper.class, mDevicePolicyManagerWrapper::get);
         mProviders.put(PackageManagerWrapper.class, mPackageManagerWrapper::get);
+        mProviders.put(SensorPrivacyController.class, mSensorPrivacyController::get);
 
 
         // TODO(b/118592525): to support multi-display , we start to add something which is
diff --git a/packages/SystemUI/src/com/android/systemui/DependencyBinder.java b/packages/SystemUI/src/com/android/systemui/DependencyBinder.java
index 3c6f081..53050bf 100644
--- a/packages/SystemUI/src/com/android/systemui/DependencyBinder.java
+++ b/packages/SystemUI/src/com/android/systemui/DependencyBinder.java
@@ -60,6 +60,8 @@
 import com.android.systemui.statusbar.policy.RotationLockControllerImpl;
 import com.android.systemui.statusbar.policy.SecurityController;
 import com.android.systemui.statusbar.policy.SecurityControllerImpl;
+import com.android.systemui.statusbar.policy.SensorPrivacyController;
+import com.android.systemui.statusbar.policy.SensorPrivacyControllerImpl;
 import com.android.systemui.statusbar.policy.UserInfoController;
 import com.android.systemui.statusbar.policy.UserInfoControllerImpl;
 import com.android.systemui.statusbar.policy.ZenModeController;
@@ -225,5 +227,11 @@
     /**
      */
     @Binds
+    public abstract SensorPrivacyController provideSensorPrivacyControllerImpl(
+            SensorPrivacyControllerImpl controllerImpl);
+
+    /**
+     */
+    @Binds
     public abstract QSHost provideQsHost(QSTileHost controllerImpl);
 }
diff --git a/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java b/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java
index 0113d05..ed2a6b5 100644
--- a/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java
+++ b/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java
@@ -19,9 +19,7 @@
 import android.content.Context;
 import android.graphics.Rect;
 import android.opengl.GLSurfaceView;
-import android.os.Build;
 import android.service.wallpaper.WallpaperService;
-import android.util.Log;
 import android.view.SurfaceHolder;
 
 import com.android.systemui.glwallpaper.ImageWallpaperRenderer;
@@ -34,15 +32,7 @@
     private static final String TAG = ImageWallpaper.class.getSimpleName();
 
     @Override
-    public void onCreate() {
-        super.onCreate();
-    }
-
-    @Override
     public Engine onCreateEngine() {
-        if (Build.IS_DEBUGGABLE) {
-            Log.v(TAG, "We are using GLEngine");
-        }
         return new GLEngine(this);
     }
 
@@ -72,8 +62,15 @@
             }
         }
 
+        @Override
+        public void onDestroy() {
+            if (mWallpaperSurfaceView != null) {
+                mWallpaperSurfaceView.onPause();
+            }
+        }
+
         private class GLWallpaperSurfaceView extends GLSurfaceView implements ImageGLView {
-            private WallpaperStatusListener mWallpaperChangedListener;
+            private WallpaperStatusListener mWallpaperStatusListener;
 
             GLWallpaperSurfaceView(Context context) {
                 super(context);
@@ -88,18 +85,18 @@
             @Override
             public void setRenderer(Renderer renderer) {
                 super.setRenderer(renderer);
-                mWallpaperChangedListener = (WallpaperStatusListener) renderer;
+                mWallpaperStatusListener = (WallpaperStatusListener) renderer;
             }
 
             private void notifyAmbientModeChanged(boolean inAmbient, long duration) {
-                if (mWallpaperChangedListener != null) {
-                    mWallpaperChangedListener.onAmbientModeChanged(inAmbient, duration);
+                if (mWallpaperStatusListener != null) {
+                    mWallpaperStatusListener.onAmbientModeChanged(inAmbient, duration);
                 }
             }
 
             private void notifyOffsetsChanged(float xOffset, float yOffset) {
-                if (mWallpaperChangedListener != null) {
-                    mWallpaperChangedListener.onOffsetsChanged(
+                if (mWallpaperStatusListener != null) {
+                    mWallpaperStatusListener.onOffsetsChanged(
                             xOffset, yOffset, getHolder().getSurfaceFrame());
                 }
             }
diff --git a/packages/SystemUI/src/com/android/systemui/Prefs.java b/packages/SystemUI/src/com/android/systemui/Prefs.java
index d437555..2797570 100644
--- a/packages/SystemUI/src/com/android/systemui/Prefs.java
+++ b/packages/SystemUI/src/com/android/systemui/Prefs.java
@@ -57,7 +57,8 @@
             Key.SEEN_RINGER_GUIDANCE_COUNT,
             Key.QS_HAS_TURNED_OFF_MOBILE_DATA,
             Key.TOUCHED_RINGER_TOGGLE,
-            Key.QUICK_STEP_INTERACTION_FLAGS
+            Key.QUICK_STEP_INTERACTION_FLAGS,
+            Key.HAS_SEEN_ODI_CAPTIONS_TOOLTIP
     })
     public @interface Key {
         @Deprecated
@@ -103,6 +104,7 @@
         String QS_HAS_TURNED_OFF_MOBILE_DATA = "QsHasTurnedOffMobileData";
         String TOUCHED_RINGER_TOGGLE = "TouchedRingerToggle";
         String QUICK_STEP_INTERACTION_FLAGS = "QuickStepInteractionFlags";
+        String HAS_SEEN_ODI_CAPTIONS_TOOLTIP = "HasSeenODICaptionsTooltip";
     }
 
     public static boolean getBoolean(Context context, @Key String key, boolean defaultValue) {
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/BiometricDialogImpl.java b/packages/SystemUI/src/com/android/systemui/biometrics/BiometricDialogImpl.java
index 016b8fe..4028109 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/BiometricDialogImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/BiometricDialogImpl.java
@@ -191,32 +191,41 @@
         mCurrentDialogArgs = args;
         final int type = args.argi1;
 
+        // Create a new dialog but do not replace the current one yet.
+        BiometricDialogView newDialog;
         if (type == BiometricAuthenticator.TYPE_FINGERPRINT) {
-            mCurrentDialog = new FingerprintDialogView(mContext, mCallback);
+            newDialog = new FingerprintDialogView(mContext, mCallback);
         } else if (type == BiometricAuthenticator.TYPE_FACE) {
-            mCurrentDialog = new FaceDialogView(mContext, mCallback);
+            newDialog = new FaceDialogView(mContext, mCallback);
         } else {
             Log.e(TAG, "Unsupported type: " + type);
-        }
-
-        if (savedState != null) {
-            mCurrentDialog.restoreState(savedState);
-        }
-
-        if (DEBUG) Log.d(TAG, "handleShowDialog, isAnimatingAway: "
-                + mCurrentDialog.isAnimatingAway() + " type: " + type);
-
-        if (mCurrentDialog.isAnimatingAway()) {
-            mCurrentDialog.forceRemove();
-        } else if (mDialogShowing) {
-            Log.w(TAG, "Dialog already showing");
             return;
         }
+
+        if (DEBUG) Log.d(TAG, "handleShowDialog, "
+                + " savedState: " + savedState
+                + " mCurrentDialog: " + mCurrentDialog
+                + " newDialog: " + newDialog
+                + " type: " + type);
+
+        if (savedState != null) {
+            // SavedState is only non-null if it's from onConfigurationChanged. Restore the state
+            // even though it may be removed / re-created again
+            newDialog.restoreState(savedState);
+        } else if (mCurrentDialog != null && mDialogShowing) {
+            // If somehow we're asked to show a dialog, the old one doesn't need to be animated
+            // away. This can happen if the app cancels and re-starts auth during configuration
+            // change. This is ugly because we also have to do things on onConfigurationChanged
+            // here.
+            mCurrentDialog.forceRemove();
+        }
+
         mReceiver = (IBiometricServiceReceiverInternal) args.arg2;
-        mCurrentDialog.setBundle((Bundle)args.arg1);
-        mCurrentDialog.setRequireConfirmation((boolean) args.arg3);
-        mCurrentDialog.setUserId(args.argi2);
-        mCurrentDialog.setSkipIntro(skipAnimation);
+        newDialog.setBundle((Bundle) args.arg1);
+        newDialog.setRequireConfirmation((boolean) args.arg3);
+        newDialog.setUserId(args.argi2);
+        newDialog.setSkipIntro(skipAnimation);
+        mCurrentDialog = newDialog;
         mWindowManager.addView(mCurrentDialog, mCurrentDialog.getLayoutParams());
         mDialogShowing = true;
     }
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
index e0ed111..4a2731e 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
@@ -61,6 +61,7 @@
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.notification.row.NotificationContentInflater.InflationFlag;
 import com.android.systemui.statusbar.phone.StatusBarWindowController;
+import com.android.systemui.statusbar.policy.ConfigurationController;
 
 import java.lang.annotation.Retention;
 
@@ -74,7 +75,8 @@
  * The controller manages addition, removal, and visible state of bubbles on screen.
  */
 @Singleton
-public class BubbleController implements BubbleExpandedView.OnBubbleBlockedListener {
+public class BubbleController implements BubbleExpandedView.OnBubbleBlockedListener,
+        ConfigurationController.ConfigurationListener {
 
     private static final String TAG = "BubbleController";
 
@@ -84,6 +86,7 @@
     @IntDef({DISMISS_USER_GESTURE, DISMISS_AGED, DISMISS_TASK_FINISHED, DISMISS_BLOCKED,
             DISMISS_NOTIF_CANCEL, DISMISS_ACCESSIBILITY_ACTION})
     @interface DismissReason {}
+
     static final int DISMISS_USER_GESTURE = 1;
     static final int DISMISS_AGED = 2;
     static final int DISMISS_TASK_FINISHED = 3;
@@ -151,6 +154,7 @@
     public interface BubbleExpandListener {
         /**
          * Called when the expansion state of the bubble stack changes.
+         *
          * @param isExpanding whether it's expanding or collapsing
          * @param key the notification key associated with bubble being expanded
          */
@@ -179,13 +183,16 @@
 
     @Inject
     public BubbleController(Context context, StatusBarWindowController statusBarWindowController,
-                            BubbleData data) {
-        this(context, statusBarWindowController, data, null /* synchronizer */);
+            BubbleData data, ConfigurationController configurationController) {
+        this(context, statusBarWindowController, data, null /* synchronizer */,
+                configurationController);
     }
 
     public BubbleController(Context context, StatusBarWindowController statusBarWindowController,
-            BubbleData data, @Nullable BubbleStackView.SurfaceSynchronizer synchronizer) {
+            BubbleData data, @Nullable BubbleStackView.SurfaceSynchronizer synchronizer,
+            ConfigurationController configurationController) {
         mContext = context;
+        configurationController.addCallback(this /* configurationListener */);
 
         mNotificationEntryManager = Dependency.get(NotificationEntryManager.class);
         mNotificationEntryManager.addNotificationEntryListener(mEntryListener);
@@ -215,6 +222,20 @@
         mSurfaceSynchronizer = synchronizer;
     }
 
+    @Override
+    public void onUiModeChanged() {
+        if (mStackView != null) {
+            mStackView.onConfigChanged();
+        }
+    }
+
+    @Override
+    public void onOverlayChanged() {
+        if (mStackView != null) {
+            mStackView.onConfigChanged();
+        }
+    }
+
     /**
      * Set a listener to be notified when some states of the bubbles change.
      */
@@ -295,7 +316,7 @@
     /**
      * Adds or updates a bubble associated with the provided notification entry.
      *
-     * @param notif the notification associated with this bubble.
+     * @param notif          the notification associated with this bubble.
      * @param updatePosition whether this update should promote the bubble to the top of the stack.
      */
     public void updateBubble(NotificationEntry notif, boolean updatePosition) {
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java
index 856b9d6..14e910f 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java
@@ -94,6 +94,9 @@
     private boolean mActivityViewReady = false;
     private PendingIntent mBubbleIntent;
 
+    private boolean mKeyboardVisible;
+    private boolean mNeedsNewHeight;
+
     private int mMinHeight;
     private int mHeaderHeight;
     private int mBubbleHeight;
@@ -227,21 +230,15 @@
                 true /* singleTaskInstance */);
         addView(mActivityView);
 
-        mActivityView.setOnApplyWindowInsetsListener((View view, WindowInsets insets) -> {
-            ActivityView activityView = (ActivityView) view;
-            // Here we assume that the position of the ActivityView on the screen
-            // remains regardless of IME status. When we move ActivityView, the
-            // forwardedInsets should be computed not against the current location
-            // and size, but against the post-moved location and size.
-            Point displaySize = new Point();
-            view.getContext().getDisplay().getSize(displaySize);
-            int[] windowLocation = view.getLocationOnScreen();
-            final int windowBottom = windowLocation[1] + view.getHeight();
+        setOnApplyWindowInsetsListener((View view, WindowInsets insets) -> {
+            // Keep track of IME displaying because we should not make any adjustments that might
+            // cause a config change while the IME is displayed otherwise it'll loose focus.
             final int keyboardHeight = insets.getSystemWindowInsetBottom()
                     - insets.getStableInsetBottom();
-            final int insetsBottom = Math.max(0,
-                    windowBottom + keyboardHeight - displaySize.y);
-            activityView.setForwardedInsets(Insets.of(0, 0, 0, insetsBottom));
+            mKeyboardVisible = keyboardHeight != 0;
+            if (!mKeyboardVisible && mNeedsNewHeight) {
+                updateHeight();
+            }
             return view.onApplyWindowInsets(insets);
         });
 
@@ -258,6 +255,34 @@
         }
     }
 
+    @Override
+    protected void onDetachedFromWindow() {
+        super.onDetachedFromWindow();
+        mKeyboardVisible = false;
+        mNeedsNewHeight = false;
+        if (mActivityView != null) {
+            mActivityView.setForwardedInsets(Insets.of(0, 0, 0, 0));
+        }
+    }
+
+    /**
+     * Called by {@link BubbleStackView} when the insets for the expanded state should be updated.
+     * This should be done post-move and post-animation.
+     */
+    void updateInsets(WindowInsets insets) {
+        if (usingActivityView()) {
+            Point displaySize = new Point();
+            mActivityView.getContext().getDisplay().getSize(displaySize);
+            int[] windowLocation = mActivityView.getLocationOnScreen();
+            final int windowBottom = windowLocation[1] + mActivityView.getHeight();
+            final int keyboardHeight = insets.getSystemWindowInsetBottom()
+                    - insets.getStableInsetBottom();
+            final int insetsBottom = Math.max(0,
+                    windowBottom + keyboardHeight - displaySize.y);
+            mActivityView.setForwardedInsets(Insets.of(0, 0, 0, insetsBottom));
+        }
+    }
+
     /**
      * Creates a background with corners rounded based on how the view is configured to display
      */
@@ -354,6 +379,13 @@
         }
     }
 
+    /**
+     * Update bubble expanded view header when user toggles dark mode.
+     */
+    void updateHeaderColor() {
+        mHeaderView.setBackgroundColor(mContext.getColor(R.attr.colorAccent));
+    }
+
     private void updateHeaderView() {
         mSettingsIcon.setContentDescription(getResources().getString(
                 R.string.bubbles_settings_button_description, mAppName));
@@ -378,6 +410,8 @@
             mPermissionView.setVisibility(VISIBLE);
             ((ImageView) mPermissionView.findViewById(R.id.pkgicon)).setImageDrawable(mAppIcon);
             ((TextView) mPermissionView.findViewById(R.id.pkgname)).setText(mAppName);
+            ((TextView) mPermissionView.findViewById(R.id.prompt)).setText(
+                    getResources().getString(R.string.bubbles_prompt, mAppName));
             logBubbleClickEvent(mEntry.notification,
                     StatsLog.BUBBLE_UICHANGED__ACTION__PERMISSION_DIALOG_SHOWN);
         }
@@ -441,9 +475,15 @@
             int height = Math.min(desiredHeight, max);
             height = Math.max(height, mMinHeight);
             LayoutParams lp = (LayoutParams) mActivityView.getLayoutParams();
-            lp.height = height;
-            mBubbleHeight = height;
-            mActivityView.setLayoutParams(lp);
+            mNeedsNewHeight =  lp.height != height;
+            if (!mKeyboardVisible) {
+                // If the keyboard is visible... don't adjust the height because that will cause
+                // a configuration change and the keyboard will be lost.
+                lp.height = height;
+                mBubbleHeight = height;
+                mActivityView.setLayoutParams(lp);
+                mNeedsNewHeight = false;
+            }
         } else {
             mBubbleHeight = mNotifRow != null ? mNotifRow.getIntrinsicHeight() : mMinHeight;
         }
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
index 1cc6b87..580acb8 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
@@ -128,6 +128,7 @@
 
     private Bubble mExpandedBubble;
     private boolean mIsExpanded;
+    private boolean mImeVisible;
 
     private BubbleTouchHandler mTouchHandler;
     private BubbleController.BubbleExpandListener mExpandListener;
@@ -236,6 +237,35 @@
         setClipChildren(false);
         setFocusable(true);
         mBubbleContainer.bringToFront();
+
+        setOnApplyWindowInsetsListener((View view, WindowInsets insets) -> {
+            final int keyboardHeight = insets.getSystemWindowInsetBottom()
+                    - insets.getStableInsetBottom();
+            if (!mIsExpanded) {
+                return view.onApplyWindowInsets(insets);
+            }
+            mImeVisible = keyboardHeight != 0;
+
+            float newY = getYPositionForExpandedView();
+            if (newY < 0) {
+                // TODO: This means our expanded content is too big to fit on screen. Right now
+                // we'll let it translate off but we should be clipping it & pushing the header
+                // down so that it always remains visible.
+            }
+            mExpandedViewYAnim.animateToFinalPosition(newY);
+            mExpandedAnimationController.updateYPosition(
+                    // Update the insets after we're done translating otherwise position
+                    // calculation for them won't be correct.
+                    () -> mExpandedBubble.expandedView.updateInsets(insets));
+            return view.onApplyWindowInsets(insets);
+        });
+    }
+
+    /**
+     * Handle config changes.
+     */
+    public void onConfigChanged() {
+        mExpandedBubble.expandedView.updateHeaderColor();
     }
 
     @Override
@@ -639,15 +669,6 @@
         }
     }
 
-    /**
-     * The width of the collapsed stack of bubbles.
-     */
-    public int getStackWidth() {
-        return mBubblePadding * (mBubbleContainer.getChildCount() - 1)
-                + mBubbleSize + mBubbleContainer.getPaddingEnd()
-                + mBubbleContainer.getPaddingStart();
-    }
-
     private void notifyExpansionChanged(NotificationEntry entry, boolean expanded) {
         if (mExpandListener != null) {
             mExpandListener.onBubbleExpandChanged(expanded, entry != null ? entry.key : null);
@@ -836,8 +857,13 @@
             // calculation is correct)
             mExpandedBubble.expandedView.updateView();
             final float y = getYPositionForExpandedView();
-            mExpandedViewContainer.setTranslationY(y);
-            // Then update the view so that ActivityView knows we translated
+            if (!mExpandedViewYAnim.isRunning()) {
+                // We're not animating so set the value
+                mExpandedViewContainer.setTranslationY(y);
+            } else {
+                // We are animating so update the value
+                mExpandedViewYAnim.animateToFinalPosition(y);
+            }
             mExpandedBubble.expandedView.updateView();
         }
 
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleView.java
index b409a31..7a68be4 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleView.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleView.java
@@ -193,11 +193,19 @@
         if (mEntry == null) {
             return;
         }
+        Notification.BubbleMetadata metadata = mEntry.getBubbleMetadata();
         Notification n = mEntry.notification.getNotification();
-        boolean isLarge = n.getLargeIcon() != null;
-        Icon ic = isLarge ? n.getLargeIcon() : n.getSmallIcon();
+        Icon ic;
+        boolean needsTint;
+        if (metadata != null) {
+            ic = metadata.getIcon();
+            needsTint = ic.getType() != Icon.TYPE_ADAPTIVE_BITMAP;
+        } else {
+            needsTint = n.getLargeIcon() == null;
+            ic = needsTint ? n.getSmallIcon() : n.getLargeIcon();
+        }
         Drawable iconDrawable = ic.loadDrawable(mContext);
-        if (!isLarge) {
+        if (needsTint) {
             // Center icon on coloured background
             iconDrawable.setTint(Color.WHITE); // TODO: dark mode
             Drawable bg = new ColorDrawable(n.color);
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/animation/ExpandedAnimationController.java b/packages/SystemUI/src/com/android/systemui/bubbles/animation/ExpandedAnimationController.java
index 1f29883..40e08be 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/animation/ExpandedAnimationController.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/animation/ExpandedAnimationController.java
@@ -198,6 +198,19 @@
     }
 
     /**
+     * Animates the bubbles to {@link #getExpandedY()} position. Used in response to IME showing.
+     */
+    public void updateYPosition(Runnable after) {
+        if (mLayout == null) return;
+
+        for (int i = 0; i < mLayout.getChildCount(); i++) {
+            boolean isLast = i == mLayout.getChildCount() - 1;
+            mLayout.animateValueForChildAtIndex(DynamicAnimation.TRANSLATION_Y, i,
+                    getExpandedY(), isLast ? after : null);
+        }
+    }
+
+    /**
      * Animates the bubbles, starting at the given index, to the left or right by the given number
      * of bubble widths. Passing zero for numBubbleWidths will animate the bubbles to their normal
      * positions.
@@ -213,18 +226,25 @@
 
     /** The Y value of the row of expanded bubbles. */
     public float getExpandedY() {
-        boolean showOnTop = mLayout != null
-                && BubbleController.showBubblesAtTop(mLayout.getContext());
-        final WindowInsets insets = mLayout != null ? mLayout.getRootWindowInsets() : null;
-        if (showOnTop && insets != null) {
+        if (mLayout == null || mLayout.getRootWindowInsets() == null) {
+            return 0;
+        }
+        final boolean showOnTop = BubbleController.showBubblesAtTop(mLayout.getContext());
+        final WindowInsets insets = mLayout.getRootWindowInsets();
+        if (showOnTop) {
             return mBubblePaddingPx + Math.max(
                     mStatusBarHeight,
                     insets.getDisplayCutout() != null
                             ? insets.getDisplayCutout().getSafeInsetTop()
                             : 0);
         } else {
-            int bottomInset = insets != null ? insets.getSystemWindowInsetBottom() : 0;
-            return mDisplaySize.y - mBubbleSizePx - (mPipDismissHeight - bottomInset);
+            int keyboardHeight = insets.getSystemWindowInsetBottom()
+                    - insets.getStableInsetBottom();
+            float bottomInset = keyboardHeight > 0
+                    ? keyboardHeight
+                    : (mPipDismissHeight - insets.getStableInsetBottom());
+            // Stable insets are excluded from display size, so we must subtract it
+            return mDisplaySize.y - mBubbleSizePx - mBubblePaddingPx - bottomInset;
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeService.java b/packages/SystemUI/src/com/android/systemui/doze/DozeService.java
index d06feed..2db7306 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeService.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeService.java
@@ -61,7 +61,9 @@
 
     @Override
     public void onDestroy() {
-        mPluginManager.removePluginListener(this);
+        if (mPluginManager != null) {
+            mPluginManager.removePluginListener(this);
+        }
         super.onDestroy();
         mDozeMachine = null;
     }
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java b/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
index bc3f48d..031f562 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
@@ -164,16 +164,9 @@
                     if (screenX != -1 && screenY != -1) {
                         mDozeHost.onSlpiTap(screenX, screenY);
                     }
-                    // Logs screen wake up reason of either single or double tap.
-                    mMetricsLogger.write(new LogMaker(MetricsEvent.DOZING)
-                            .setType(MetricsEvent.TYPE_UPDATE).setSubtype(pulseReason));
-                    mMachine.wakeUp();
+                    gentleWakeUp(pulseReason);
                 } else if (isPickup) {
-                    // Logs screen wake up reason of lift.
-                    mMetricsLogger.write(new LogMaker(MetricsEvent.DOZING)
-                            .setType(MetricsEvent.TYPE_UPDATE)
-                            .setSubtype(DozeLog.REASON_SENSOR_PICKUP));
-                    mMachine.wakeUp();
+                    gentleWakeUp(pulseReason);
                 } else {
                     mDozeHost.extendPulse();
                 }
@@ -190,6 +183,20 @@
         }
     }
 
+    private void gentleWakeUp(int reason) {
+        // Log screen wake up reason (lift/pickup, tap, double-tap)
+        mMetricsLogger.write(new LogMaker(MetricsEvent.DOZING)
+                .setType(MetricsEvent.TYPE_UPDATE)
+                .setSubtype(reason));
+        if (mDozeParameters.getDisplayNeedsBlanking()) {
+            // Let's prepare the display to wake-up by drawing black.
+            // This will cover the hardware wake-up sequence, where the display
+            // becomes black for a few frames.
+            mDozeHost.setAodDimmingScrim(255f);
+        }
+        mMachine.wakeUp();
+    }
+
     private void onProximityFar(boolean far) {
         final boolean near = !far;
         final DozeMachine.State state = mMachine.getState();
diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
index 0adbefe..f07887e 100644
--- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
@@ -92,8 +92,6 @@
 import com.android.systemui.plugins.GlobalActionsPanelPlugin;
 import com.android.systemui.statusbar.phone.ScrimController;
 import com.android.systemui.statusbar.policy.ConfigurationController;
-import com.android.systemui.statusbar.policy.ExtensionController;
-import com.android.systemui.statusbar.policy.ExtensionController.Extension;
 import com.android.systemui.util.EmergencyDialerConstants;
 import com.android.systemui.util.leak.RotationUtils;
 import com.android.systemui.volume.SystemUIInterpolators.LogAccelerateInterpolator;
@@ -161,9 +159,8 @@
     private final EmergencyAffordanceManager mEmergencyAffordanceManager;
     private final ScreenshotHelper mScreenshotHelper;
     private final ScreenRecordHelper mScreenRecordHelper;
-
-    private final Extension<GlobalActionsPanelPlugin> mPanelExtension;
-    private ActivityStarter mActivityStarter;
+    private final ActivityStarter mActivityStarter;
+    private GlobalActionsPanelPlugin mPanelPlugin;
 
     /**
      * @param context everything needs a context :(
@@ -209,10 +206,6 @@
 
         Dependency.get(ConfigurationController.class).addCallback(this);
 
-        mPanelExtension = Dependency.get(ExtensionController.class)
-            .newExtension(GlobalActionsPanelPlugin.class)
-            .withPlugin(GlobalActionsPanelPlugin.class)
-            .build();
         mActivityStarter = Dependency.get(ActivityStarter.class);
     }
 
@@ -221,9 +214,11 @@
      *
      * @param keyguardShowing True if keyguard is showing
      */
-    public void showDialog(boolean keyguardShowing, boolean isDeviceProvisioned) {
+    public void showDialog(boolean keyguardShowing, boolean isDeviceProvisioned,
+            GlobalActionsPanelPlugin panelPlugin) {
         mKeyguardShowing = keyguardShowing;
         mDeviceProvisioned = isDeviceProvisioned;
+        mPanelPlugin = panelPlugin;
         if (mDialog != null) {
             mDialog.dismiss();
             mDialog = null;
@@ -400,8 +395,8 @@
         mAdapter = new MyAdapter();
 
         GlobalActionsPanelPlugin.PanelViewController panelViewController =
-                mPanelExtension.get() != null
-                        ? mPanelExtension.get().onPanelShown(
+                mPanelPlugin != null
+                        ? mPanelPlugin.onPanelShown(
                                 new GlobalActionsPanelPlugin.Callbacks() {
                                     @Override
                                     public void dismissGlobalActionsMenu() {
@@ -1504,12 +1499,12 @@
         private final Context mContext;
         private final MyAdapter mAdapter;
         private MultiListLayout mGlobalActionsLayout;
-        private final Drawable mBackgroundDrawable;
+        private Drawable mBackgroundDrawable;
         private final ColorExtractor mColorExtractor;
         private final GlobalActionsPanelPlugin.PanelViewController mPanelController;
         private boolean mKeyguardShowing;
         private boolean mShowing;
-        private final float mScrimAlpha;
+        private float mScrimAlpha;
 
         ActionsDialog(Context context, MyAdapter adapter,
                 GlobalActionsPanelPlugin.PanelViewController plugin) {
@@ -1536,49 +1531,37 @@
                     | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
                     | WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED);
             window.setType(WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY);
-
-            initializeLayout();
-
             setTitle(R.string.global_actions);
 
             mPanelController = plugin;
-            View panelView = initializePanel();
-            if (panelView == null) {
-                mBackgroundDrawable = new GradientDrawable(context);
-                mScrimAlpha = ScrimController.GRADIENT_SCRIM_ALPHA;
-            } else {
-                mBackgroundDrawable = context.getDrawable(
-                        com.android.systemui.R.drawable.global_action_panel_scrim);
-                mScrimAlpha = 1f;
-                addContentView(
-                        panelView,
-                        new ViewGroup.LayoutParams(
-                                ViewGroup.LayoutParams.MATCH_PARENT,
-                                ViewGroup.LayoutParams.MATCH_PARENT));
-            }
-            window.setBackgroundDrawable(mBackgroundDrawable);
+            initializeLayout();
         }
 
-        private View initializePanel() {
-            if (isPanelEnabled(mContext) && mPanelController != null) {
-                View panelView = mPanelController.getPanelContent();
-                if (panelView != null) {
-                    FrameLayout panelContainer = new FrameLayout(mContext);
-                    FrameLayout.LayoutParams panelParams =
-                            new FrameLayout.LayoutParams(
-                                    FrameLayout.LayoutParams.MATCH_PARENT,
-                                    FrameLayout.LayoutParams.WRAP_CONTENT);
-                    panelContainer.addView(panelView, panelParams);
-                    return panelContainer;
-                }
+        private boolean initializePanel() {
+            if (!isPanelEnabled(mContext) || mPanelController == null) {
+                return false;
             }
-            return null;
+            View panelView = mPanelController.getPanelContent();
+            if (panelView == null) {
+                return false;
+            }
+            FrameLayout panelContainer = new FrameLayout(mContext);
+            FrameLayout.LayoutParams panelParams =
+                    new FrameLayout.LayoutParams(
+                            FrameLayout.LayoutParams.MATCH_PARENT,
+                            FrameLayout.LayoutParams.WRAP_CONTENT);
+            panelContainer.addView(panelView, panelParams);
+            addContentView(
+                    panelContainer,
+                    new ViewGroup.LayoutParams(
+                            ViewGroup.LayoutParams.MATCH_PARENT,
+                            ViewGroup.LayoutParams.MATCH_PARENT));
+            return true;
         }
 
         private void initializeLayout() {
             setContentView(getGlobalActionsLayoutId(mContext));
-            mGlobalActionsLayout = (MultiListLayout)
-                    findViewById(com.android.systemui.R.id.global_actions_view);
+            mGlobalActionsLayout = findViewById(com.android.systemui.R.id.global_actions_view);
             mGlobalActionsLayout.setOutsideTouchListener(view -> dismiss());
             mGlobalActionsLayout.setListViewAccessibilityDelegate(new View.AccessibilityDelegate() {
                 @Override
@@ -1591,8 +1574,18 @@
             });
             mGlobalActionsLayout.setRotationListener(this::onRotate);
             mGlobalActionsLayout.setAdapter(mAdapter);
-            mGlobalActionsLayout.setSnapToEdge(isPanelEnabled(mContext)
-                    && mPanelController != null);
+
+            boolean panelEnabled = initializePanel();
+            if (!panelEnabled) {
+                mBackgroundDrawable = new GradientDrawable(mContext);
+                mScrimAlpha = ScrimController.GRADIENT_SCRIM_ALPHA;
+            } else {
+                mBackgroundDrawable = mContext.getDrawable(
+                        com.android.systemui.R.drawable.global_action_panel_scrim);
+                mScrimAlpha = 1f;
+            }
+            mGlobalActionsLayout.setSnapToEdge(panelEnabled);
+            getWindow().setBackgroundDrawable(mBackgroundDrawable);
         }
 
         private int getGlobalActionsLayoutId(Context context) {
@@ -1748,7 +1741,8 @@
      */
     private static boolean isPanelEnabled(Context context) {
         return FeatureFlagUtils.isEnabled(
-                context, FeatureFlagUtils.GLOBAL_ACTIONS_PANEL_ENABLED);    }
+                context, FeatureFlagUtils.GLOBAL_ACTIONS_PANEL_ENABLED);
+    }
 
     /**
      * Determines whether the Global Actions menu should use a separated view for emergency actions.
diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsImpl.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsImpl.java
index 19a7cea..4cf58b7 100644
--- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsImpl.java
@@ -37,8 +37,10 @@
 import com.android.systemui.SysUiServiceProvider;
 import com.android.systemui.colorextraction.SysuiColorExtractor;
 import com.android.systemui.plugins.GlobalActions;
+import com.android.systemui.plugins.GlobalActionsPanelPlugin;
 import com.android.systemui.statusbar.CommandQueue;
 import com.android.systemui.statusbar.policy.DeviceProvisionedController;
+import com.android.systemui.statusbar.policy.ExtensionController;
 import com.android.systemui.statusbar.policy.KeyguardMonitor;
 
 public class GlobalActionsImpl implements GlobalActions, CommandQueue.Callbacks {
@@ -48,6 +50,7 @@
     private final Context mContext;
     private final KeyguardMonitor mKeyguardMonitor;
     private final DeviceProvisionedController mDeviceProvisionedController;
+    private final ExtensionController.Extension<GlobalActionsPanelPlugin> mPanelExtension;
     private GlobalActionsDialog mGlobalActions;
     private boolean mDisabled;
 
@@ -56,6 +59,10 @@
         mKeyguardMonitor = Dependency.get(KeyguardMonitor.class);
         mDeviceProvisionedController = Dependency.get(DeviceProvisionedController.class);
         SysUiServiceProvider.getComponent(context, CommandQueue.class).addCallback(this);
+        mPanelExtension = Dependency.get(ExtensionController.class)
+                .newExtension(GlobalActionsPanelPlugin.class)
+                .withPlugin(GlobalActionsPanelPlugin.class)
+                .build();
     }
 
     @Override
@@ -74,7 +81,8 @@
             mGlobalActions = new GlobalActionsDialog(mContext, manager);
         }
         mGlobalActions.showDialog(mKeyguardMonitor.isShowing(),
-                mDeviceProvisionedController.isDeviceProvisioned());
+                mDeviceProvisionedController.isDeviceProvisioned(),
+                mPanelExtension.get());
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/glwallpaper/ImageGLWallpaper.java b/packages/SystemUI/src/com/android/systemui/glwallpaper/ImageGLWallpaper.java
index a313336..21406e5 100644
--- a/packages/SystemUI/src/com/android/systemui/glwallpaper/ImageGLWallpaper.java
+++ b/packages/SystemUI/src/com/android/systemui/glwallpaper/ImageGLWallpaper.java
@@ -110,9 +110,10 @@
         mTextureBuffer.position(0);
     }
 
-    void setup() {
+    void setup(Bitmap bitmap) {
         setupAttributes();
         setupUniforms();
+        setupTexture(bitmap);
     }
 
     private void setupAttributes() {
@@ -159,7 +160,7 @@
         glDrawArrays(GL_TRIANGLES, 0, VERTICES.length / 2);
     }
 
-    void setupTexture(Bitmap bitmap) {
+    private void setupTexture(Bitmap bitmap) {
         final int[] tids = new int[1];
 
         if (bitmap == null) {
@@ -174,7 +175,7 @@
             return;
         }
 
-        // Bind a named texture to a texturing target.
+        // Bind a named texture to a target.
         glBindTexture(GL_TEXTURE_2D, tids[0]);
         // Load the bitmap data and copy it over into the texture object that is currently bound.
         GLUtils.texImage2D(GL_TEXTURE_2D, 0, bitmap, 0);
@@ -195,15 +196,8 @@
         glUniform1i(mUniTexture, 0);
     }
 
-    void adjustTextureCoordinates(Bitmap bitmap, int surfaceWidth, int surfaceHeight,
-            float xOffset, float yOffset) {
-        if (bitmap == null) {
-            Log.d(TAG, "adjustTextureCoordinates: invalid bitmap");
-            return;
-        }
-
-        int bitmapWidth = bitmap.getWidth();
-        int bitmapHeight = bitmap.getHeight();
+    void adjustTextureCoordinates(int bitmapWidth, int bitmapHeight,
+            int surfaceWidth, int surfaceHeight, float xOffset, float yOffset) {
         float ratioW = 1f;
         float ratioH = 1f;
         float rX = 0f;
diff --git a/packages/SystemUI/src/com/android/systemui/glwallpaper/ImageWallpaperRenderer.java b/packages/SystemUI/src/com/android/systemui/glwallpaper/ImageWallpaperRenderer.java
index 9df6ba5..464cbe3 100644
--- a/packages/SystemUI/src/com/android/systemui/glwallpaper/ImageWallpaperRenderer.java
+++ b/packages/SystemUI/src/com/android/systemui/glwallpaper/ImageWallpaperRenderer.java
@@ -58,6 +58,10 @@
     private int mWidth = 0;
     private int mHeight = 0;
 
+    private Bitmap mBitmap;
+    private int mBitmapWidth = 0;
+    private int mBitmapHeight = 0;
+
     public ImageWallpaperRenderer(Context context, ImageGLView glView) {
         mWallpaperManager = context.getSystemService(WallpaperManager.class);
         if (mWallpaperManager == null) {
@@ -71,8 +75,12 @@
         mGLView = glView;
 
         if (mWallpaperManager != null) {
+            mBitmap = mWallpaperManager.getBitmap();
+            mBitmapWidth = mBitmap.getWidth();
+            mBitmapHeight = mBitmap.getHeight();
             // Compute per85 as transition threshold, this is an async work.
-            mImageProcessHelper.startComputingPercentile85(mWallpaperManager.getBitmap());
+            mImageProcessHelper.startComputingPercentile85(mBitmap);
+            mWallpaperManager.forgetLoadedWallpaper();
         }
     }
 
@@ -81,8 +89,8 @@
         glClearColor(0f, 0f, 0f, 1.0f);
         mProgram.useGLProgram(
                 R.raw.image_wallpaper_vertex_shader, R.raw.image_wallpaper_fragment_shader);
-        mWallpaper.setup();
-        mWallpaper.setupTexture(mWallpaperManager.getBitmap());
+        mWallpaper.setup(mBitmap);
+        mBitmap = null;
     }
 
     @Override
@@ -94,8 +102,8 @@
         }
         mWidth = width;
         mHeight = height;
-        mWallpaper.adjustTextureCoordinates(mWallpaperManager.getBitmap(),
-                width, height, mXOffset, mYOffset);
+        mWallpaper.adjustTextureCoordinates(
+                mBitmapWidth, mBitmapHeight, width, height, mXOffset, mYOffset);
     }
 
     @Override
@@ -132,13 +140,7 @@
 
     @Override
     public void onOffsetsChanged(float xOffset, float yOffset, Rect frame) {
-        if (frame == null || mWallpaperManager == null
-                || (xOffset == mXOffset && yOffset == mYOffset)) {
-            return;
-        }
-
-        Bitmap bitmap = mWallpaperManager.getBitmap();
-        if (bitmap == null) {
+        if (frame == null || (xOffset == mXOffset && yOffset == mYOffset)) {
             return;
         }
 
@@ -151,7 +153,8 @@
             Log.d(TAG, "onOffsetsChanged: width=" + width + ", height=" + height
                     + ", xOffset=" + mXOffset + ", yOffset=" + mYOffset);
         }
-        mWallpaper.adjustTextureCoordinates(bitmap, width, height, mXOffset, mYOffset);
+        mWallpaper.adjustTextureCoordinates(
+                mBitmapWidth, mBitmapHeight, width, height, mXOffset, mYOffset);
         requestRender();
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index 0be9e25..676e594 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -2031,7 +2031,6 @@
     private void handleNotifyScreenTurnedOff() {
         synchronized (this) {
             if (DEBUG) Log.d(TAG, "handleNotifyScreenTurnedOff");
-            mStatusBarKeyguardViewManager.onScreenTurnedOff();
             mDrawnCallback = null;
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/privacy/OngoingPrivacyDialog.kt b/packages/SystemUI/src/com/android/systemui/privacy/OngoingPrivacyDialog.kt
deleted file mode 100644
index cf17018..0000000
--- a/packages/SystemUI/src/com/android/systemui/privacy/OngoingPrivacyDialog.kt
+++ /dev/null
@@ -1,160 +0,0 @@
-/*
- * Copyright (C) 2018 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.privacy
-
-import android.app.AlertDialog
-import android.app.Dialog
-import android.content.Context
-import android.content.DialogInterface
-import android.content.Intent
-import android.content.pm.PackageManager
-import android.content.res.ColorStateList
-import android.os.UserHandle
-import android.provider.Settings
-import android.util.IconDrawableFactory
-import android.util.StatsLog
-import android.view.Gravity
-import android.view.LayoutInflater
-import android.view.View
-import android.widget.ImageView
-import android.widget.LinearLayout
-import android.widget.TextView
-import com.android.systemui.Dependency
-import com.android.systemui.R
-import com.android.systemui.plugins.ActivityStarter
-import java.util.concurrent.TimeUnit
-
-class OngoingPrivacyDialog constructor(
-    private val context: Context,
-    private val dialogBuilder: PrivacyDialogBuilder
-) {
-
-    private val iconSize = context.resources.getDimensionPixelSize(
-            R.dimen.ongoing_appops_dialog_icon_size)
-    private val iconColor = context.resources.getColor(
-            com.android.internal.R.color.text_color_primary, context.theme)
-    private val iconMargin = context.resources.getDimensionPixelSize(
-            R.dimen.ongoing_appops_dialog_icon_margin)
-    private val iconFactory = IconDrawableFactory.newInstance(context, true)
-    private var dismissDialog: (() -> Unit)? = null
-    private val appsAndTypes = dialogBuilder.appsAndTypes
-            .sortedWith(compareBy({ -it.second.size }, // Sort by number of AppOps
-            { it.second.min() },
-            { it.first }))
-
-    fun createDialog(): Dialog {
-        val builder = AlertDialog.Builder(context).apply {
-            setPositiveButton(R.string.ongoing_privacy_dialog_ok,
-                    object : DialogInterface.OnClickListener {
-                override fun onClick(dialog: DialogInterface?, which: Int) {
-                    StatsLog.write(StatsLog.PRIVACY_INDICATORS_INTERACTED,
-                            StatsLog.PRIVACY_INDICATORS_INTERACTED__TYPE__DIALOG_DISMISS)
-                }
-            })
-            setNeutralButton(R.string.ongoing_privacy_dialog_open_settings,
-                    object : DialogInterface.OnClickListener {
-                        val intent = Intent(Settings.ACTION_PRIVACY_SETTINGS).putExtra(
-                                Intent.EXTRA_DURATION_MILLIS, TimeUnit.MINUTES.toMillis(1))
-
-                        @Suppress("DEPRECATION")
-                        override fun onClick(dialog: DialogInterface?, which: Int) {
-                            StatsLog.write(StatsLog.PRIVACY_INDICATORS_INTERACTED, StatsLog
-                                    .PRIVACY_INDICATORS_INTERACTED__TYPE__DIALOG_PRIVACY_SETTINGS)
-                            Dependency.get(ActivityStarter::class.java)
-                                    .postStartActivityDismissingKeyguard(intent, 0)
-                        }
-                    })
-        }
-        builder.setView(getContentView())
-        val dialog = builder.create()
-        dismissDialog = dialog::dismiss
-        return dialog
-    }
-
-    fun getContentView(): View {
-        val layoutInflater = LayoutInflater.from(context)
-        val contentView = layoutInflater.inflate(R.layout.ongoing_privacy_dialog_content, null)
-
-        val title = contentView.findViewById(R.id.title) as TextView
-        val appsList = contentView.findViewById(R.id.items_container) as LinearLayout
-
-        title.setText(dialogBuilder.getDialogTitle())
-
-        val numItems = appsAndTypes.size
-        for (i in 0..(numItems - 1)) {
-            val item = appsAndTypes[i]
-            addAppItem(appsList, item.first, item.second, dialogBuilder.types.size > 1)
-        }
-        return contentView
-    }
-
-    @Suppress("DEPRECATION")
-    private fun addAppItem(
-        itemList: LinearLayout,
-        app: PrivacyApplication,
-        types: List<PrivacyType>,
-        showIcons: Boolean = true
-    ) {
-        val layoutInflater = LayoutInflater.from(context)
-        val item = layoutInflater.inflate(R.layout.ongoing_privacy_dialog_item, itemList, false)
-        val appIcon = item.findViewById(R.id.app_icon) as ImageView
-        val appName = item.findViewById(R.id.app_name) as TextView
-        val icons = item.findViewById(R.id.icons) as LinearLayout
-
-        val lp = LinearLayout.LayoutParams(iconSize, iconSize).apply {
-            gravity = Gravity.CENTER_VERTICAL
-            marginStart = iconMargin
-        }
-
-        app.icon.let {
-            appIcon.setImageDrawable(iconFactory.getShadowedIcon(it))
-        }
-
-        appName.text = app.applicationName
-        if (showIcons) {
-            dialogBuilder.generateIconsForApp(types).forEachIndexed { index, it ->
-                it.setBounds(0, 0, iconSize, iconSize)
-                val image = ImageView(context).apply {
-                    imageTintList = ColorStateList.valueOf(iconColor)
-                    setImageDrawable(it)
-                }
-                image.contentDescription = types[index].getName(context)
-                icons.addView(image, lp)
-            }
-            icons.visibility = View.VISIBLE
-        } else {
-            icons.visibility = View.GONE
-        }
-        try {
-            // Check if package exists
-            context.packageManager.getPackageInfo(app.packageName, 0)
-            item.setOnClickListener(object : View.OnClickListener {
-                val intent = Intent(Intent.ACTION_MANAGE_APP_PERMISSIONS)
-                        .putExtra(Intent.EXTRA_PACKAGE_NAME, app.packageName)
-                        .putExtra(Intent.EXTRA_USER, UserHandle.getUserHandleForUid(app.uid))
-                override fun onClick(v: View?) {
-                    StatsLog.write(StatsLog.PRIVACY_INDICATORS_INTERACTED,
-                            StatsLog.PRIVACY_INDICATORS_INTERACTED__TYPE__DIALOG_LINE_ITEM,
-                            app.packageName)
-                    Dependency.get(ActivityStarter::class.java)
-                            .postStartActivityDismissingKeyguard(intent, 0)
-                    dismissDialog?.invoke()
-                }
-            })
-        } catch (e: PackageManager.NameNotFoundException) {}
-
-        itemList.addView(item)
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSCarrier.java b/packages/SystemUI/src/com/android/systemui/qs/QSCarrier.java
index 3ff30c5..f19445c 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSCarrier.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSCarrier.java
@@ -89,16 +89,22 @@
                         .append(", ");
             }
             // TODO: show mobile data off/no internet text for 5 seconds before carrier text
-            if (TextUtils.equals(state.typeContentDescription,
-                    mContext.getString(R.string.data_connection_no_internet))
-                    || TextUtils.equals(state.typeContentDescription,
-                    mContext.getString(R.string.cell_data_off_content_description))) {
+            if (hasValidTypeContentDescription(state.typeContentDescription)) {
                 contentDescription.append(state.typeContentDescription);
             }
             mMobileSignal.setContentDescription(contentDescription);
         }
     }
 
+    private boolean hasValidTypeContentDescription(String typeContentDescription) {
+        return TextUtils.equals(typeContentDescription,
+                mContext.getString(R.string.data_connection_no_internet))
+                || TextUtils.equals(typeContentDescription,
+                mContext.getString(R.string.cell_data_off_content_description))
+                || TextUtils.equals(typeContentDescription,
+                mContext.getString(R.string.not_default_data_content_description));
+    }
+
     public void setCarrierText(CharSequence text) {
         mCarrierText.setText(text);
     }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
index 4862b9e..c897b9c 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
@@ -23,7 +23,6 @@
 import android.annotation.ColorInt;
 import android.app.ActivityManager;
 import android.app.AlarmManager;
-import android.app.Dialog;
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
@@ -62,7 +61,6 @@
 import com.android.systemui.plugins.DarkIconDispatcher;
 import com.android.systemui.plugins.DarkIconDispatcher.DarkReceiver;
 import com.android.systemui.privacy.OngoingPrivacyChip;
-import com.android.systemui.privacy.OngoingPrivacyDialog;
 import com.android.systemui.privacy.PrivacyDialogBuilder;
 import com.android.systemui.privacy.PrivacyItem;
 import com.android.systemui.privacy.PrivacyItemController;
@@ -71,7 +69,6 @@
 import com.android.systemui.statusbar.phone.StatusBarIconController;
 import com.android.systemui.statusbar.phone.StatusBarIconController.TintedIconManager;
 import com.android.systemui.statusbar.phone.StatusIconContainer;
-import com.android.systemui.statusbar.phone.SystemUIDialog;
 import com.android.systemui.statusbar.policy.Clock;
 import com.android.systemui.statusbar.policy.DateView;
 import com.android.systemui.statusbar.policy.NextAlarmController;
@@ -561,11 +558,8 @@
             StatsLog.write(StatsLog.PRIVACY_INDICATORS_INTERACTED,
                     StatsLog.PRIVACY_INDICATORS_INTERACTED__TYPE__CHIP_CLICKED);
             mUiHandler.post(() -> {
-                Dialog mDialog = new OngoingPrivacyDialog(mContext, builder).createDialog();
-                SystemUIDialog.setShowForAllUsers(mDialog, false);
-                SystemUIDialog.registerDismissListener(mDialog);
-                SystemUIDialog.setWindowOnTop(mDialog);
-                mActivityStarter.postQSRunnableDismissingKeyguard(() -> mDialog.show());
+                mActivityStarter.postStartActivityDismissingKeyguard(
+                        new Intent(Intent.ACTION_REVIEW_ONGOING_PERMISSION_USAGE), 0);
                 mHost.collapsePanels();
             });
         }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSFactoryImpl.java b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSFactoryImpl.java
index d26cee9..2956ad0 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSFactoryImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSFactoryImpl.java
@@ -41,7 +41,6 @@
 import com.android.systemui.qs.tiles.NfcTile;
 import com.android.systemui.qs.tiles.NightDisplayTile;
 import com.android.systemui.qs.tiles.RotationLockTile;
-import com.android.systemui.qs.tiles.SensorPrivacyTile;
 import com.android.systemui.qs.tiles.UserTile;
 import com.android.systemui.qs.tiles.WifiTile;
 import com.android.systemui.qs.tiles.WorkModeTile;
@@ -73,7 +72,6 @@
     private final Provider<DataSaverTile> mDataSaverTileProvider;
     private final Provider<NightDisplayTile> mNightDisplayTileProvider;
     private final Provider<NfcTile> mNfcTileProvider;
-    private final Provider<SensorPrivacyTile> mSensorPrivacyTileProvider;
     private final Provider<GarbageMonitor.MemoryTile> mMemoryTileProvider;
 
     private QSTileHost mHost;
@@ -96,7 +94,6 @@
             Provider<DataSaverTile> dataSaverTileProvider,
             Provider<NightDisplayTile> nightDisplayTileProvider,
             Provider<NfcTile> nfcTileProvider,
-            Provider<SensorPrivacyTile> sensorPrivacyTileProvider,
             Provider<GarbageMonitor.MemoryTile> memoryTileProvider) {
         mWifiTileProvider = wifiTileProvider;
         mBluetoothTileProvider = bluetoothTileProvider;
@@ -115,7 +112,6 @@
         mDataSaverTileProvider = dataSaverTileProvider;
         mNightDisplayTileProvider = nightDisplayTileProvider;
         mNfcTileProvider = nfcTileProvider;
-        mSensorPrivacyTileProvider = sensorPrivacyTileProvider;
         mMemoryTileProvider = memoryTileProvider;
     }
 
@@ -168,8 +164,6 @@
                 return mNightDisplayTileProvider.get();
             case "nfc":
                 return mNfcTileProvider.get();
-            case "sensorprivacy":
-                return mSensorPrivacyTileProvider.get();
         }
 
         // Intent tiles.
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/SensorPrivacyTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/SensorPrivacyTile.java
deleted file mode 100644
index 7ee37d5..0000000
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/SensorPrivacyTile.java
+++ /dev/null
@@ -1,131 +0,0 @@
-/*
- * Copyright (C) 2018 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.qs.tiles;
-
-import android.content.Intent;
-import android.hardware.SensorPrivacyManager;
-import android.service.quicksettings.Tile;
-import android.widget.Switch;
-
-import com.android.internal.logging.MetricsLogger;
-import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
-import com.android.systemui.R;
-import com.android.systemui.plugins.ActivityStarter;
-import com.android.systemui.plugins.qs.QSTile.BooleanState;
-import com.android.systemui.qs.QSHost;
-import com.android.systemui.qs.tileimpl.QSTileImpl;
-import com.android.systemui.statusbar.policy.KeyguardMonitor;
-
-import javax.inject.Inject;
-
-/** Quick settings tile: SensorPrivacy mode **/
-public class SensorPrivacyTile extends QSTileImpl<BooleanState> implements
-        SensorPrivacyManager.OnSensorPrivacyChangedListener {
-    private static final String TAG = "SensorPrivacy";
-    private final Icon mIcon =
-            ResourceIcon.get(R.drawable.ic_signal_sensors);
-    private final KeyguardMonitor mKeyguard;
-    private final SensorPrivacyManager mSensorPrivacyManager;
-    private final ActivityStarter mActivityStarter;
-
-    @Inject
-    public SensorPrivacyTile(QSHost host, SensorPrivacyManager sensorPrivacyManager,
-            KeyguardMonitor keyguardMonitor, ActivityStarter activityStarter) {
-        super(host);
-
-        mSensorPrivacyManager = sensorPrivacyManager;
-        mKeyguard = keyguardMonitor;
-        mActivityStarter = activityStarter;
-    }
-
-    @Override
-    public BooleanState newTileState() {
-        return new BooleanState();
-    }
-
-    @Override
-    public void handleClick() {
-        final boolean wasEnabled = mState.value;
-        // Don't allow disabling from the lockscreen.
-        if (wasEnabled && mKeyguard.isSecure() && mKeyguard.isShowing()) {
-            mActivityStarter.postQSRunnableDismissingKeyguard(() -> {
-                MetricsLogger.action(mContext, getMetricsCategory(), !wasEnabled);
-                setEnabled(!wasEnabled);
-            });
-            return;
-        }
-
-        MetricsLogger.action(mContext, getMetricsCategory(), !wasEnabled);
-        setEnabled(!wasEnabled);
-    }
-
-    private void setEnabled(boolean enabled) {
-        mSensorPrivacyManager.setSensorPrivacy(enabled);
-    }
-
-    @Override
-    public CharSequence getTileLabel() {
-        return mContext.getString(R.string.sensor_privacy_mode);
-    }
-
-    @Override
-    public Intent getLongClickIntent() {
-        return new Intent();
-    }
-
-    @Override
-    protected void handleUpdateState(BooleanState state, Object arg) {
-        final boolean enabled = arg instanceof Boolean ? (Boolean) arg
-                : mSensorPrivacyManager.isSensorPrivacyEnabled();
-        state.value = enabled;
-        state.label = mContext.getString(R.string.sensor_privacy_mode);
-        state.icon = mIcon;
-        state.state = enabled ? Tile.STATE_ACTIVE : Tile.STATE_INACTIVE;
-        state.contentDescription = state.label;
-        state.expandedAccessibilityClassName = Switch.class.getName();
-    }
-
-    @Override
-    public int getMetricsCategory() {
-        return MetricsEvent.QS_SENSOR_PRIVACY;
-    }
-
-    @Override
-    protected String composeChangeAnnouncement() {
-        if (mState.value) {
-            return mContext
-                    .getString(R.string.accessibility_quick_settings_sensor_privacy_changed_on);
-        } else {
-            return mContext
-                    .getString(R.string.accessibility_quick_settings_sensor_privacy_changed_off);
-        }
-    }
-
-    @Override
-    protected void handleSetListening(boolean listening) {
-        if (listening) {
-            mSensorPrivacyManager.addSensorPrivacyListener(this);
-        } else {
-            mSensorPrivacyManager.removeSensorPrivacyListener(this);
-        }
-    }
-
-    @Override
-    public void onSensorPrivacyChanged(boolean enabled) {
-        refreshState(enabled);
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/TriangleShape.java b/packages/SystemUI/src/com/android/systemui/recents/TriangleShape.java
index ef4e195..de8e6ea 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/TriangleShape.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/TriangleShape.java
@@ -50,6 +50,24 @@
         return new TriangleShape(triangularPath, width, height);
     }
 
+    /** Create an arrow TriangleShape that points to the left or the right */
+    public static TriangleShape createHorizontal(
+            float width, float height, boolean isPointingLeft) {
+        Path triangularPath = new Path();
+        if (isPointingLeft) {
+            triangularPath.moveTo(0, height / 2);
+            triangularPath.lineTo(width, height);
+            triangularPath.lineTo(width, 0);
+            triangularPath.close();
+        } else {
+            triangularPath.moveTo(0, height);
+            triangularPath.lineTo(width, height / 2);
+            triangularPath.lineTo(0, 0);
+            triangularPath.close();
+        }
+        return new TriangleShape(triangularPath, width, height);
+    }
+
     @Override
     public void getOutline(@NonNull Outline outline) {
         outline.setConvexPath(mTriangularPath);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
index 295abcb..2f99cf3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
@@ -596,7 +596,8 @@
     @Override
     public void appTransitionCancelled(int displayId) {
         synchronized (mLock) {
-            mHandler.obtainMessage(MSG_APP_TRANSITION_CANCELLED, displayId).sendToTarget();
+            mHandler.obtainMessage(MSG_APP_TRANSITION_CANCELLED, displayId, 0 /* unused */)
+                    .sendToTarget();
         }
     }
 
@@ -624,7 +625,8 @@
     @Override
     public void appTransitionFinished(int displayId) {
         synchronized (mLock) {
-            mHandler.obtainMessage(MSG_APP_TRANSITION_FINISHED, displayId).sendToTarget();
+            mHandler.obtainMessage(MSG_APP_TRANSITION_FINISHED, displayId, 0 /* unused */)
+                    .sendToTarget();
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardAffordanceView.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardAffordanceView.java
index 0a39549..2da6824 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardAffordanceView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardAffordanceView.java
@@ -492,13 +492,10 @@
             int currentAlpha = getImageAlpha();
             ValueAnimator animator = ValueAnimator.ofInt(currentAlpha, endAlpha);
             mAlphaAnimator = animator;
-            animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
-                @Override
-                public void onAnimationUpdate(ValueAnimator animation) {
-                    int alpha = (int) animation.getAnimatedValue();
-                    if (background != null) background.mutate().setAlpha(alpha);
-                    setImageAlpha(alpha);
-                }
+            animator.addUpdateListener(animation -> {
+                int alpha1 = (int) animation.getAnimatedValue();
+                if (background != null) background.mutate().setAlpha(alpha1);
+                setImageAlpha(alpha1);
             });
             animator.addListener(mAlphaEndListener);
             if (interpolator == null) {
@@ -520,6 +517,10 @@
         }
     }
 
+    public boolean isAnimatingAlpha() {
+        return mAlphaAnimator != null;
+    }
+
     private Animator.AnimatorListener getEndListener(final Runnable runnable) {
         return new AnimatorListenerAdapter() {
             boolean mCancelled;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NavigationBarController.java b/packages/SystemUI/src/com/android/systemui/statusbar/NavigationBarController.java
index 14dc272..2bb6e3e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NavigationBarController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NavigationBarController.java
@@ -32,6 +32,7 @@
 import android.view.View;
 import android.view.WindowManagerGlobal;
 
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.systemui.Dependency;
 import com.android.systemui.plugins.DarkIconDispatcher;
 import com.android.systemui.statusbar.CommandQueue.Callbacks;
@@ -58,7 +59,8 @@
     private final DisplayManager mDisplayManager;
 
     /** A displayId - nav bar maps. */
-    private SparseArray<NavigationBarFragment> mNavigationBars = new SparseArray<>();
+    @VisibleForTesting
+    SparseArray<NavigationBarFragment> mNavigationBars = new SparseArray<>();
 
     @Inject
     public NavigationBarController(Context context, @Named(MAIN_HANDLER_NAME) Handler handler) {
@@ -101,7 +103,8 @@
      *
      * @param display the display to add navigation bar on.
      */
-    private void createNavigationBar(Display display) {
+    @VisibleForTesting
+    void createNavigationBar(Display display) {
         if (display == null) {
             return;
         }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinator.kt
index ccb8d9b..3433fa8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinator.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinator.kt
@@ -17,6 +17,7 @@
 package com.android.systemui.statusbar.notification
 
 import android.animation.ObjectAnimator
+import android.content.Context
 import android.util.FloatProperty
 import com.android.systemui.Interpolators
 import com.android.systemui.plugins.statusbar.StatusBarStateController
@@ -25,12 +26,14 @@
 import com.android.systemui.statusbar.notification.collection.NotificationEntry
 import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout
 import com.android.systemui.statusbar.notification.stack.StackStateAnimator
+import com.android.systemui.statusbar.phone.DozeParameters
 
 import javax.inject.Inject
 import javax.inject.Singleton
 
 @Singleton
 class NotificationWakeUpCoordinator @Inject constructor(
+        private val mContext: Context,
         private val mAmbientPulseManager: AmbientPulseManager,
         private val mStatusBarStateController: StatusBarStateController)
     : AmbientPulseManager.OnAmbientChangedListener, StatusBarStateController.StateListener {
@@ -59,10 +62,12 @@
     private var mLinearVisibilityAmount = 0.0f
     private var mWakingUp = false
     private val mEntrySetToClearWhenFinished = mutableSetOf<NotificationEntry>()
+    private val mDozeParameters: DozeParameters;
 
     init {
         mAmbientPulseManager.addListener(this)
         mStatusBarStateController.addCallback(this)
+        mDozeParameters = DozeParameters.getInstance(mContext)
     }
 
     fun setStackScroller(stackScroller: NotificationStackScrollLayout) {
@@ -194,7 +199,7 @@
     }
 
     override fun onAmbientStateChanged(entry: NotificationEntry, isPulsing: Boolean) {
-        var animate = true
+        var animate = mDozeParameters.getAlwaysOn() && !mDozeParameters.getDisplayNeedsBlanking()
         if (!isPulsing) {
             if (mLinearDozeAmount != 0.0f) {
                 if (entry.isRowDismissed) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
index d7baeee..9630727c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
@@ -2432,7 +2432,7 @@
     protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
         int intrinsicBefore = getIntrinsicHeight();
         super.onLayout(changed, left, top, right, bottom);
-        if (intrinsicBefore != getIntrinsicHeight()) {
+        if (intrinsicBefore != getIntrinsicHeight() && intrinsicBefore != 0) {
             notifyHeightChanged(true  /* needsAnimation */);
         }
         if (mMenuRow.getMenuView() != null) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflater.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflater.java
index b4dd114..09f513d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflater.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflater.java
@@ -679,16 +679,25 @@
         if (runningInflations.isEmpty()) {
             if ((reInflateFlags & FLAG_CONTENT_VIEW_CONTRACTED) != 0) {
                 if (result.inflatedContentView != null) {
+                    // New view case
                     privateLayout.setContractedChild(result.inflatedContentView);
+                    cachedContentViews.put(FLAG_CONTENT_VIEW_CONTRACTED, result.newContentView);
+                } else if (cachedContentViews.get(FLAG_CONTENT_VIEW_CONTRACTED) != null) {
+                    // Reinflation case. Only update if it's still cached (i.e. view has not been
+                    // freed while inflating).
+                    cachedContentViews.put(FLAG_CONTENT_VIEW_CONTRACTED, result.newContentView);
                 }
-                cachedContentViews.put(FLAG_CONTENT_VIEW_CONTRACTED, result.newContentView);
             }
 
             if ((reInflateFlags & FLAG_CONTENT_VIEW_EXPANDED) != 0) {
                 if (result.inflatedExpandedView != null) {
                     privateLayout.setExpandedChild(result.inflatedExpandedView);
+                    cachedContentViews.put(FLAG_CONTENT_VIEW_EXPANDED, result.newExpandedView);
                 } else if (result.newExpandedView == null) {
                     privateLayout.setExpandedChild(null);
+                    cachedContentViews.put(FLAG_CONTENT_VIEW_EXPANDED, null);
+                } else if (cachedContentViews.get(FLAG_CONTENT_VIEW_EXPANDED) != null) {
+                    cachedContentViews.put(FLAG_CONTENT_VIEW_EXPANDED, result.newExpandedView);
                 }
                 if (result.newExpandedView != null) {
                     privateLayout.setExpandedInflatedSmartReplies(
@@ -696,15 +705,18 @@
                 } else {
                     privateLayout.setExpandedInflatedSmartReplies(null);
                 }
-                cachedContentViews.put(FLAG_CONTENT_VIEW_EXPANDED, result.newExpandedView);
                 row.setExpandable(result.newExpandedView != null);
             }
 
             if ((reInflateFlags & FLAG_CONTENT_VIEW_HEADS_UP) != 0) {
                 if (result.inflatedHeadsUpView != null) {
                     privateLayout.setHeadsUpChild(result.inflatedHeadsUpView);
+                    cachedContentViews.put(FLAG_CONTENT_VIEW_HEADS_UP, result.newHeadsUpView);
                 } else if (result.newHeadsUpView == null) {
                     privateLayout.setHeadsUpChild(null);
+                    cachedContentViews.put(FLAG_CONTENT_VIEW_HEADS_UP, null);
+                } else if (cachedContentViews.get(FLAG_CONTENT_VIEW_HEADS_UP) != null) {
+                    cachedContentViews.put(FLAG_CONTENT_VIEW_HEADS_UP, result.newHeadsUpView);
                 }
                 if (result.newHeadsUpView != null) {
                     privateLayout.setHeadsUpInflatedSmartReplies(
@@ -712,14 +724,15 @@
                 } else {
                     privateLayout.setHeadsUpInflatedSmartReplies(null);
                 }
-                cachedContentViews.put(FLAG_CONTENT_VIEW_HEADS_UP, result.newHeadsUpView);
             }
 
             if ((reInflateFlags & FLAG_CONTENT_VIEW_PUBLIC) != 0) {
                 if (result.inflatedPublicView != null) {
                     publicLayout.setContractedChild(result.inflatedPublicView);
+                    cachedContentViews.put(FLAG_CONTENT_VIEW_PUBLIC, result.newPublicView);
+                } else if (cachedContentViews.get(FLAG_CONTENT_VIEW_PUBLIC) != null) {
+                    cachedContentViews.put(FLAG_CONTENT_VIEW_PUBLIC, result.newPublicView);
                 }
-                cachedContentViews.put(FLAG_CONTENT_VIEW_PUBLIC, result.newPublicView);
             }
 
             if ((reInflateFlags & FLAG_CONTENT_VIEW_AMBIENT) != 0) {
@@ -730,8 +743,10 @@
                             ? publicLayout : privateLayout;
                     newParent.setAmbientChild(result.inflatedAmbientView);
                     otherParent.setAmbientChild(null);
+                    cachedContentViews.put(FLAG_CONTENT_VIEW_AMBIENT, result.newAmbientView);
+                } else if (cachedContentViews.get(FLAG_CONTENT_VIEW_AMBIENT) != null) {
+                    cachedContentViews.put(FLAG_CONTENT_VIEW_AMBIENT, result.newAmbientView);
                 }
-                cachedContentViews.put(FLAG_CONTENT_VIEW_AMBIENT, result.newAmbientView);
             }
             entry.headsUpStatusBarText = result.headsUpStatusBarText;
             entry.headsUpStatusBarTextPublic = result.headsUpStatusBarTextPublic;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoHideController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoHideController.java
index 2bbc53c..fdf8cce 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoHideController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoHideController.java
@@ -28,6 +28,7 @@
 import android.view.MotionEvent;
 import android.view.View;
 
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.systemui.Dependency;
 import com.android.systemui.SysUiServiceProvider;
 import com.android.systemui.statusbar.CommandQueue;
@@ -48,8 +49,10 @@
     private StatusBar mStatusBar;
     private NavigationBarFragment mNavigationBar;
 
-    private int mDisplayId;
-    private int mSystemUiVisibility;
+    @VisibleForTesting
+    int mDisplayId;
+    @VisibleForTesting
+    int mSystemUiVisibility;
     // last value sent to window manager
     private int mLastDispatchedSystemUiVisibility = ~View.SYSTEM_UI_FLAG_VISIBLE;
 
@@ -123,7 +126,8 @@
         }
     }
 
-    private void notifySystemUiVisibilityChanged(int vis) {
+    @VisibleForTesting
+    void notifySystemUiVisibilityChanged(int vis) {
         try {
             if (mLastDispatchedSystemUiVisibility != vis) {
                 mWindowManagerService.statusBarVisibilityChanged(mDisplayId, vis);
@@ -213,11 +217,12 @@
         return mask;
     }
 
-    private boolean hasNavigationBar() {
+    boolean hasNavigationBar() {
         return mNavigationBar != null;
     }
 
-    private boolean hasStatusBar() {
+    @VisibleForTesting
+    boolean hasStatusBar() {
         return mStatusBar != null;
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java
index 410eeae..5a7df1f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java
@@ -303,7 +303,6 @@
             case MODE_SHOW_BOUNCER:
                 Trace.beginSection("MODE_UNLOCK or MODE_SHOW_BOUNCER");
                 if (!wasDeviceInteractive) {
-                    mStatusBarKeyguardViewManager.notifyDeviceWakeUpRequested();
                     mPendingShowBouncer = true;
                 } else {
                     showBouncer();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
index 6fe23fb..847f3ff 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
@@ -831,6 +831,15 @@
         }
     }
 
+    /**
+     * Sets the alpha of the indication areas and affordances, excluding the lock icon.
+     */
+    public void setAffordanceAlpha(float alpha) {
+        mLeftAffordanceView.setAlpha(alpha);
+        mRightAffordanceView.setAlpha(alpha);
+        mIndicationArea.setAlpha(alpha);
+    }
+
     private class DefaultLeftButton implements IntentButton {
 
         private IconState mIconState = new IconState();
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 7d13679..fe3a455 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
@@ -88,6 +88,7 @@
     private int mBouncerPromptReason;
     private boolean mIsAnimatingAway;
     private boolean mIsScrimmed;
+    private ViewGroup mLockIconContainer;
 
     public KeyguardBouncer(Context context, ViewMediatorCallback callback,
             LockPatternUtils lockPatternUtils, ViewGroup container,
@@ -136,7 +137,7 @@
         if (resetSecuritySelection) {
             // showPrimarySecurityScreen() updates the current security method. This is needed in
             // case we are already showing and the current security method changed.
-            mKeyguardView.showPrimarySecurityScreen();
+            showPrimarySecurityScreen();
         }
         if (mRoot.getVisibility() == View.VISIBLE || mShowingSoon) {
             return;
@@ -171,6 +172,10 @@
         return isShowing() && mIsScrimmed;
     }
 
+    public ViewGroup getLockIconContainer() {
+        return mRoot == null || mRoot.getVisibility() != View.VISIBLE ? null : mLockIconContainer;
+    }
+
     /**
      * This method must be called at the end of the bouncer animation when
      * the translation is performed manually by the user, otherwise FalsingManager
@@ -339,11 +344,20 @@
         boolean wasInitialized = mRoot != null;
         ensureView();
         if (wasInitialized) {
-            mKeyguardView.showPrimarySecurityScreen();
+            showPrimarySecurityScreen();
         }
         mBouncerPromptReason = mCallback.getBouncerPromptReason();
     }
 
+    private void showPrimarySecurityScreen() {
+        mKeyguardView.showPrimarySecurityScreen();
+        KeyguardSecurityView keyguardSecurityView = mKeyguardView.getCurrentSecurityView();
+        if (keyguardSecurityView != null) {
+            mLockIconContainer = ((ViewGroup) keyguardSecurityView)
+                    .findViewById(R.id.lock_icon_container);
+        }
+    }
+
     /**
      * Current notification panel expansion
      * @param fraction 0 when notification panel is collapsed and 1 when expanded.
@@ -408,6 +422,8 @@
         mStatusBarHeight = mRoot.getResources().getDimensionPixelOffset(
                 com.android.systemui.R.dimen.status_bar_height);
         mRoot.setVisibility(View.INVISIBLE);
+        mRoot.addOnLayoutChangeListener((v, left, top, right, bottom, oldLeft, oldTop, oldRight,
+                oldBottom) -> mExpansionCallback.onLayout());
         mRoot.setAccessibilityPaneTitle(mKeyguardView.getAccessibilityTitleForCurrentMode());
 
         final WindowInsets rootInsets = mRoot.getRootWindowInsets();
@@ -488,5 +504,6 @@
         void onFullyShown();
         void onStartingToHide();
         void onFullyHidden();
+        void onLayout();
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBackAction.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBackAction.java
index 7a42b03..1478a07 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBackAction.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBackAction.java
@@ -20,7 +20,6 @@
 import android.hardware.input.InputManager;
 import android.os.Handler;
 import android.os.SystemClock;
-import android.view.HapticFeedbackConstants;
 import android.view.InputDevice;
 import android.view.KeyCharacterMap;
 import android.view.KeyEvent;
@@ -103,7 +102,6 @@
     private void performBack() {
         sendEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_BACK);
         sendEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_BACK);
-        mNavigationBarView.performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY);
     }
 
     private boolean shouldExecuteBackOnUp() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarEdgePanel.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarEdgePanel.java
index fcf5893..4c7fdb0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarEdgePanel.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarEdgePanel.java
@@ -22,6 +22,7 @@
 import android.graphics.Canvas;
 import android.graphics.Paint;
 import android.graphics.PixelFormat;
+import android.os.SystemClock;
 import android.util.FloatProperty;
 import android.util.MathUtils;
 import android.view.Gravity;
@@ -31,6 +32,7 @@
 import android.view.WindowManager;
 
 import com.android.systemui.R;
+import com.android.systemui.shared.system.QuickStepContract;
 
 public class NavigationBarEdgePanel extends View {
     private static final String TAG = "NavigationBarEdgePanel";
@@ -48,6 +50,7 @@
     private static final float START_POINTING_RATIO = 0.3f;
     private static final float POINTEDNESS_BEFORE_SNAP_RATIO = 0.4f;
     private static final int ANIM_DURATION_MS = 150;
+    private static final long HAPTIC_TIMEOUT_MS = 200;
 
     private final Paint mPaint = new Paint();
     private final Paint mProtectionPaint = new Paint();
@@ -65,6 +68,8 @@
     private float mStartY;
     private float mStartX;
 
+    private boolean mDragSlopPassed;
+    private long mLastSlopHapticTime;
     private boolean mGestureDetected;
     private boolean mArrowsPointLeft;
     private float mGestureLength;
@@ -169,6 +174,7 @@
     public boolean onTouchEvent(MotionEvent event) {
         switch (event.getActionMasked()) {
             case MotionEvent.ACTION_DOWN : {
+                mDragSlopPassed = false;
                 show(event.getX(), event.getY());
                 break;
             }
@@ -263,6 +269,13 @@
     private void handleNewSwipePoint(float x) {
         float dist = MathUtils.abs(x - mStartX);
 
+        // Apply a haptic on drag slop passed
+        if (!mDragSlopPassed && dist > QuickStepContract.getQuickStepDragSlopPx()) {
+            mDragSlopPassed = true;
+            performHapticFeedback(HapticFeedbackConstants.CLOCK_TICK);
+            mLastSlopHapticTime = SystemClock.uptimeMillis();
+        }
+
         setDragProgress(MathUtils.constrainedMap(
                 0, 1.0f,
                 0, mGestureLength * TRACK_LENGTH_MULTIPLIER,
@@ -286,7 +299,10 @@
             }
         } else {
             if (!mGestureDetected) {
-                performHapticFeedback(HapticFeedbackConstants.CLOCK_TICK);
+                // Prevent another haptic if it was just used
+                if (SystemClock.uptimeMillis() - mLastSlopHapticTime > HAPTIC_TIMEOUT_MS) {
+                    performHapticFeedback(HapticFeedbackConstants.CLOCK_TICK);
+                }
                 mGestureDetected = true;
 
                 mLegAnimator.setFloatValues(1f);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
index 0978901..ea30451 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
@@ -159,7 +159,8 @@
 
     private OverviewProxyService mOverviewProxyService;
 
-    private int mDisplayId;
+    @VisibleForTesting
+    public int mDisplayId;
     private boolean mIsOnDefaultDisplay;
     public boolean mHomeBlockedThisTouch;
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
index 18612c3..ef82b34 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
@@ -182,7 +182,6 @@
     private NavigationBackAction mBackAction;
     private QuickSwitchAction mQuickSwitchAction;
     private NavigationAssistantAction mAssistantAction;
-    private NavigationNotificationPanelAction mNotificationPanelAction;
 
     private NavigationBarEdgePanel mLeftEdgePanel;
     private NavigationBarEdgePanel mRightEdgePanel;
@@ -475,10 +474,6 @@
             mAssistantAction = new NavigationAssistantAction(this, mOverviewProxyService,
                     assistManager);
         }
-        if (mNotificationPanelAction == null) {
-            mNotificationPanelAction = new NavigationNotificationPanelAction(this,
-                    mOverviewProxyService, panel);
-        }
         if (mGestureHelper instanceof QuickStepController) {
             ((QuickStepController) mGestureHelper).setComponents(this);
             updateNavigationGestures();
@@ -517,8 +512,6 @@
                 return mQuickSwitchAction;
             case NavigationPrototypeController.ACTION_ASSISTANT:
                 return mAssistantAction;
-            case NavigationPrototypeController.ACTION_EXPAND_NOTIFICATION:
-                return mNotificationPanelAction;
             case NavigationPrototypeController.ACTION_NOTHING:
                 return null;
             default:
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationNotificationPanelAction.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationNotificationPanelAction.java
deleted file mode 100644
index 6c7870d..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationNotificationPanelAction.java
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.statusbar.phone;
-
-import android.annotation.NonNull;
-import android.view.MotionEvent;
-
-import com.android.systemui.recents.OverviewProxyService;
-
-/**
- * Triggers notification panel to be expanded when executed
- */
-public class NavigationNotificationPanelAction extends NavigationGestureAction {
-    private final NotificationPanelView mPanelView;
-
-    public NavigationNotificationPanelAction(@NonNull NavigationBarView navigationBarView,
-            @NonNull OverviewProxyService service, @NonNull NotificationPanelView panelView) {
-        super(navigationBarView, service);
-        mPanelView = panelView;
-    }
-
-    @Override
-    public boolean isEnabled() {
-        return true;
-    }
-
-    @Override
-    public boolean disableProxyEvents() {
-        return true;
-    }
-
-    @Override
-    public void onGestureStart(MotionEvent event) {
-        mPanelView.expand(true);
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationPrototypeController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationPrototypeController.java
index 31579c2..979de07 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationPrototypeController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationPrototypeController.java
@@ -47,7 +47,7 @@
 
     @Retention(RetentionPolicy.SOURCE)
     @IntDef({ACTION_DEFAULT, ACTION_QUICKSTEP, ACTION_QUICKSCRUB, ACTION_BACK,
-            ACTION_QUICKSWITCH, ACTION_NOTHING, ACTION_ASSISTANT, ACTION_EXPAND_NOTIFICATION})
+            ACTION_QUICKSWITCH, ACTION_NOTHING, ACTION_ASSISTANT})
     @interface GestureAction {}
     static final int ACTION_DEFAULT = 0;
     static final int ACTION_QUICKSTEP = 1;
@@ -56,7 +56,6 @@
     static final int ACTION_QUICKSWITCH = 4;
     static final int ACTION_NOTHING = 5;
     static final int ACTION_ASSISTANT = 6;
-    static final int ACTION_EXPAND_NOTIFICATION = 7;
 
     private OnPrototypeChangedListener mListener;
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
index babee53..253bdfb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -192,7 +192,6 @@
     protected int mQsMinExpansionHeight;
     protected int mQsMaxExpansionHeight;
     private int mQsPeekHeight;
-    private int mBouncerTop;
     private boolean mStackScrollerOverscrolling;
     private boolean mQsExpansionFromOverscroll;
     private float mLastOverscroll;
@@ -325,6 +324,7 @@
     private final ShadeController mShadeController =
             Dependency.get(ShadeController.class);
     private int mDisplayId;
+    private KeyguardBouncer mBouncer;
 
     /**
      * Cache the resource id of the theme to avoid unnecessary work in onThemeChanged.
@@ -690,11 +690,6 @@
         return count;
     }
 
-    public void setBouncerTop(int bouncerTop) {
-        mBouncerTop = bouncerTop;
-        positionClockAndNotifications();
-    }
-
     private void updateClock() {
         if (!mKeyguardStatusViewAnimating) {
             mKeyguardStatusView.setAlpha(mClockPositionResult.clockAlpha);
@@ -1741,7 +1736,6 @@
         }
         updateExpandedHeight(expandedHeight);
         updateHeader();
-        updateUnlockIcon();
         updateNotificationTranslucency();
         updatePanelExpanded();
         if (DEBUG) {
@@ -1834,19 +1828,6 @@
         return mNotificationStackScroller.getCurrentOverScrolledPixels(true /* top */);
     }
 
-    private void updateUnlockIcon() {
-        if (mBarState == StatusBarState.KEYGUARD
-                || mBarState == StatusBarState.SHADE_LOCKED) {
-            boolean active = getMaxPanelHeight() - getExpandedHeight() > mUnlockMoveDistance;
-            KeyguardAffordanceView lockIcon = mKeyguardBottomArea.getLockIcon();
-            if (active != mUnlockIconActive && mTracking) {
-                lockIcon.setImageAlpha(lockIcon.getRestingAlpha(), true, 150,
-                        Interpolators.FAST_OUT_LINEAR_IN, null);
-            }
-            mUnlockIconActive = active;
-        }
-    }
-
     /**
      * Hides the header when notifications are colliding with it.
      */
@@ -1913,7 +1894,7 @@
                         ? 0 : KeyguardBouncer.ALPHA_EXPANSION_THRESHOLD, 1f,
                 0f, 1f, getExpandedFraction());
         float alpha = Math.min(expansionAlpha, 1 - getQsExpansionFraction());
-        mKeyguardBottomArea.setAlpha(alpha);
+        mKeyguardBottomArea.setAffordanceAlpha(alpha);
         mKeyguardBottomArea.setImportantForAccessibility(alpha == 0f
                 ? IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS
                 : IMPORTANT_FOR_ACCESSIBILITY_AUTO);
@@ -2061,11 +2042,6 @@
                 mAffordanceHelper.reset(true);
             }
         }
-        if (!expand && (mBarState == StatusBarState.KEYGUARD
-                || mBarState == StatusBarState.SHADE_LOCKED)) {
-            KeyguardAffordanceView lockIcon = mKeyguardBottomArea.getLockIcon();
-            lockIcon.setImageAlpha(0.0f, true, 100, Interpolators.FAST_OUT_LINEAR_IN, null);
-        }
     }
 
     @Override
@@ -2215,22 +2191,6 @@
             return;
         }
         super.startUnlockHintAnimation();
-        startHighlightIconAnimation(getCenterIcon());
-    }
-
-    /**
-     * Starts the highlight (making it fully opaque) animation on an icon.
-     */
-    private void startHighlightIconAnimation(final KeyguardAffordanceView icon) {
-        icon.setImageAlpha(1.0f, true, KeyguardAffordanceHelper.HINT_PHASE1_DURATION,
-                Interpolators.FAST_OUT_SLOW_IN, new Runnable() {
-                    @Override
-                    public void run() {
-                        icon.setImageAlpha(icon.getRestingAlpha(),
-                                true /* animate */, KeyguardAffordanceHelper.HINT_PHASE1_DURATION,
-                                Interpolators.FAST_OUT_SLOW_IN, null);
-                    }
-                });
     }
 
     @Override
@@ -2969,6 +2929,7 @@
     public void onBouncerPreHideAnimation() {
         setKeyguardStatusViewVisibility(mBarState, true /* keyguardFadingAway */,
                 false /* goingToFullShade */);
+        updateLockIcon();
     }
 
     @Override
@@ -3058,4 +3019,54 @@
     public void showTransientIndication(int id) {
         mKeyguardBottomArea.showTransientIndication(id);
     }
+
+    /**
+     * Sets the reference to the {@link KeyguardBouncer}.
+     */
+    public void setBouncer(KeyguardBouncer bouncer) {
+        mBouncer = bouncer;
+        updateLockIcon();
+    }
+
+    public void updateLockIcon() {
+        if (mBouncer == null) {
+            return;
+        }
+
+        ViewGroup bouncerContainer = mBouncer.getLockIconContainer();
+        LockIcon lockIcon = mKeyguardBottomArea.getLockIcon();
+
+        if (mBouncer.isAnimatingAway()) {
+            if (!lockIcon.isAnimatingAlpha() && lockIcon.getAlpha() != 0) {
+                lockIcon.setImageAlpha(0, true /* animate */);
+            }
+            // Let's not re-apply the translation if the bouncer is animating, its
+            // animation also includes translation and transition would be jarring.
+            return;
+        }
+
+        float translation = 0;
+        if (bouncerContainer != null) {
+            float bottomAreaContainerY = getCommonTop(lockIcon);
+            float bouncerLockY = getCommonTop(bouncerContainer);
+            if (bouncerLockY < bottomAreaContainerY) {
+                translation = bouncerLockY - bottomAreaContainerY;
+            }
+        }
+        lockIcon.setTranslationY(translation);
+
+        if (lockIcon.getAlpha() != 1) {
+            lockIcon.setImageAlpha(1, false /* animate */);
+        }
+    }
+
+    private static float getCommonTop(View view) {
+        float y = view.getTop();
+        ViewGroup parent = (ViewGroup) view.getParent();
+        while (!(parent instanceof StatusBarWindowView)) {
+            y += parent.getY();
+            parent = (ViewGroup) parent.getParent();
+        }
+        return y;
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
index 2495d22..99345d2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
@@ -1115,6 +1115,7 @@
 
         View[] viewsToAnimate = {
                 mKeyguardBottomArea.getIndicationArea(),
+                mKeyguardBottomArea.getLockIcon(),
                 mStatusBar.getAmbientIndicationContainer()};
         for (View v : viewsToAnimate) {
             if (v == null) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
index 4a86484..b7a7873 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
@@ -60,6 +60,7 @@
 import com.android.systemui.statusbar.policy.NextAlarmController;
 import com.android.systemui.statusbar.policy.RotationLockController;
 import com.android.systemui.statusbar.policy.RotationLockController.RotationLockControllerCallback;
+import com.android.systemui.statusbar.policy.SensorPrivacyController;
 import com.android.systemui.statusbar.policy.UserInfoController;
 import com.android.systemui.statusbar.policy.ZenModeController;
 
@@ -100,6 +101,7 @@
     private final String mSlotLocation;
     private final String mSlotMicrophone;
     private final String mSlotCamera;
+    private final String mSlotSensorsOff;
 
     private final Context mContext;
     private final Handler mHandler = new Handler();
@@ -118,6 +120,7 @@
     private final LocationController mLocationController;
     private final PrivacyItemController mPrivacyItemController;
     private final UiOffloadThread mUiOffloadThread = Dependency.get(UiOffloadThread.class);
+    private final SensorPrivacyController mSensorPrivacyController;
 
     // Assume it's all good unless we hear otherwise.  We don't always seem
     // to get broadcasts that it *is* there.
@@ -149,6 +152,7 @@
         mKeyguardMonitor = Dependency.get(KeyguardMonitor.class);
         mLocationController = Dependency.get(LocationController.class);
         mPrivacyItemController = Dependency.get(PrivacyItemController.class);
+        mSensorPrivacyController = Dependency.get(SensorPrivacyController.class);
 
         mSlotCast = context.getString(com.android.internal.R.string.status_bar_cast);
         mSlotHotspot = context.getString(com.android.internal.R.string.status_bar_hotspot);
@@ -165,6 +169,7 @@
         mSlotLocation = context.getString(com.android.internal.R.string.status_bar_location);
         mSlotMicrophone = context.getString(com.android.internal.R.string.status_bar_microphone);
         mSlotCamera = context.getString(com.android.internal.R.string.status_bar_camera);
+        mSlotSensorsOff = context.getString(com.android.internal.R.string.status_bar_sensors_off);
 
         // listen for broadcasts
         IntentFilter filter = new IntentFilter();
@@ -232,6 +237,11 @@
                 mContext.getString(R.string.accessibility_location_active));
         mIconController.setIconVisibility(mSlotLocation, false);
 
+        // sensors off
+        mIconController.setIcon(mSlotSensorsOff, R.drawable.stat_sys_sensors_off, null);
+        mIconController.setIconVisibility(mSlotSensorsOff,
+                mSensorPrivacyController.isSensorPrivacyEnabled());
+
         mRotationLockController.addCallback(this);
         mBluetooth.addCallback(this);
         mProvisionedController.addCallback(this);
@@ -242,6 +252,7 @@
         mDataSaver.addCallback(this);
         mKeyguardMonitor.addCallback(this);
         mPrivacyItemController.addCallback(this);
+        mSensorPrivacyController.addCallback(mSensorPrivacyListener);
 
         SysUiServiceProvider.getComponent(mContext, CommandQueue.class).addCallback(this);
     }
@@ -514,6 +525,16 @@
                 }
             };
 
+    private final SensorPrivacyController.OnSensorPrivacyChangedListener mSensorPrivacyListener =
+            new SensorPrivacyController.OnSensorPrivacyChangedListener() {
+                @Override
+                public void onSensorPrivacyChanged(boolean enabled) {
+                    mHandler.post(() -> {
+                        mIconController.setIconVisibility(mSlotSensorsOff, enabled);
+                    });
+                }
+            };
+
     @Override
     public void appTransitionStarting(int displayId, long startTime, long duration,
             boolean forced) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
index 8db0822..319a504 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -122,6 +122,7 @@
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.internal.statusbar.IStatusBarService;
 import com.android.internal.statusbar.StatusBarIcon;
+import com.android.internal.widget.LockPatternUtils;
 import com.android.keyguard.KeyguardUpdateMonitor;
 import com.android.keyguard.KeyguardUpdateMonitorCallback;
 import com.android.keyguard.ViewMediatorCallback;
@@ -215,7 +216,6 @@
 import com.android.systemui.statusbar.policy.ExtensionController;
 import com.android.systemui.statusbar.policy.HeadsUpManager;
 import com.android.systemui.statusbar.policy.KeyguardMonitor;
-import com.android.systemui.statusbar.policy.KeyguardMonitorImpl;
 import com.android.systemui.statusbar.policy.KeyguardUserSwitcher;
 import com.android.systemui.statusbar.policy.NetworkController;
 import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener;
@@ -533,8 +533,7 @@
     private KeyguardUserSwitcher mKeyguardUserSwitcher;
     protected UserSwitcherController mUserSwitcherController;
     private NetworkController mNetworkController;
-    private KeyguardMonitorImpl mKeyguardMonitor
-            = (KeyguardMonitorImpl) Dependency.get(KeyguardMonitor.class);
+    private KeyguardMonitor mKeyguardMonitor = Dependency.get(KeyguardMonitor.class);
     private BatteryController mBatteryController;
     protected boolean mPanelExpanded;
     private UiModeManager mUiModeManager;
@@ -882,7 +881,6 @@
                         mNotificationPanel.getLockIcon());
         mNotificationPanel.setKeyguardIndicationController(mKeyguardIndicationController);
 
-
         mAmbientIndicationContainer = mStatusBarWindow.findViewById(
                 R.id.ambient_indication_container);
 
@@ -1058,8 +1056,21 @@
         mNotificationShelf.setOnActivatedListener(mPresenter);
         mRemoteInputManager.getController().addCallback(mStatusBarWindowController);
 
-        mNotificationActivityStarter = new StatusBarNotificationActivityStarter(
-                mContext, mNotificationPanel, mPresenter, mHeadsUpManager, mActivityLaunchAnimator);
+        final StatusBarRemoteInputCallback mStatusBarRemoteInputCallback =
+                (StatusBarRemoteInputCallback) Dependency.get(
+                        NotificationRemoteInputManager.Callback.class);
+        final ShadeController shadeController = Dependency.get(ShadeController.class);
+        final ActivityStarter activityStarter = Dependency.get(ActivityStarter.class);
+
+        mNotificationActivityStarter = new StatusBarNotificationActivityStarter(mContext,
+                mCommandQueue, mAssistManager, mNotificationPanel, mPresenter, mEntryManager,
+                mHeadsUpManager, activityStarter, mActivityLaunchAnimator,
+                mBarService, mStatusBarStateController, mKeyguardManager, mDreamManager,
+                mRemoteInputManager, mStatusBarRemoteInputCallback, mGroupManager,
+                mLockscreenUserManager, shadeController, mKeyguardMonitor,
+                mNotificationInterruptionStateProvider, mMetricsLogger,
+                new LockPatternUtils(mContext));
+
         mGutsManager.setNotificationActivityStarter(mNotificationActivityStarter);
 
         mEntryManager.setRowBinder(rowBinder);
@@ -1098,7 +1109,6 @@
             where.getLocationInWindow(mTmpInt2);
             mWakeUpTouchLocation = new PointF(mTmpInt2[0] + where.getWidth() / 2,
                     mTmpInt2[1] + where.getHeight() / 2);
-            mStatusBarKeyguardViewManager.notifyDeviceWakeUpRequested();
             mFalsingManager.onScreenOnFromTouch();
         }
     }
@@ -1220,6 +1230,7 @@
         mKeyguardViewMediatorCallback = keyguardViewMediator.getViewMediatorCallback();
         mLightBarController.setBiometricUnlockController(mBiometricUnlockController);
         mMediaManager.setBiometricUnlockController(mBiometricUnlockController);
+        mNotificationPanel.setBouncer(mStatusBarKeyguardViewManager.getBouncer());
         Dependency.get(KeyguardDismissUtil.class).setDismissHandler(this::executeWhenUnlocked);
         Trace.endSection();
     }
@@ -2993,7 +3004,7 @@
 
     private void updatePanelExpansionForKeyguard() {
         if (mState == StatusBarState.KEYGUARD && mBiometricUnlockController.getMode()
-                != BiometricUnlockController.MODE_WAKE_AND_UNLOCK) {
+                != BiometricUnlockController.MODE_WAKE_AND_UNLOCK && !mBouncerShowing) {
             instantExpandNotificationsPanel();
         } else if (mState == StatusBarState.FULLSCREEN_USER_SWITCHER) {
             instantCollapseNotificationPanel();
@@ -3551,6 +3562,9 @@
         }
     }
 
+    /**
+     * Propagation of the bouncer state, indicating that it's fully visible.
+     */
     public void setBouncerShowing(boolean bouncerShowing) {
         mBouncerShowing = bouncerShowing;
         if (mStatusBarView != null) mStatusBarView.setBouncerShowing(bouncerShowing);
@@ -3608,10 +3622,13 @@
             mWakeUpCoordinator.setWakingUp(true);
             mAmbientPulseManager.releaseAllImmediately();
             mVisualStabilityManager.setScreenOn(true);
-            updateNotificationPanelTouchState();
             updateVisibleToUser();
             updateIsKeyguard();
             mDozeServiceHost.stopDozing();
+            // This is intentionally below the stopDozing call above, since it avoids that we're
+            // unnecessarily animating the wakeUp transition. Animations should only be enabled
+            // once we fully woke up.
+            updateNotificationPanelTouchState();
             mPulseExpansionHandler.onStartedWakingUp();
         }
 
@@ -3724,7 +3741,6 @@
             PowerManager pm = mContext.getSystemService(PowerManager.class);
             pm.wakeUp(SystemClock.uptimeMillis(), PowerManager.WAKE_REASON_CAMERA_LAUNCH,
                     "com.android.systemui:CAMERA_GESTURE");
-            mStatusBarKeyguardViewManager.notifyDeviceWakeUpRequested();
         }
         vibrateForCameraGesture();
         if (!mStatusBarKeyguardViewManager.isShowing()) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
index 5014783..4412851 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
@@ -85,6 +85,7 @@
         @Override
         public void onFullyShown() {
             updateStates();
+            mStatusBar.wakeUpIfDozing(SystemClock.uptimeMillis(), mContainer, "BOUNCER_VISIBLE");
         }
 
         @Override
@@ -96,6 +97,11 @@
         public void onFullyHidden() {
             updateStates();
         }
+
+        @Override
+        public void onLayout() {
+            mNotificationPanelView.updateLockIcon();
+        }
     };
 
     protected LockPatternUtils mLockPatternUtils;
@@ -166,16 +172,10 @@
         mBouncer = SystemUIFactory.getInstance().createKeyguardBouncer(mContext,
                 mViewMediatorCallback, mLockPatternUtils, container, dismissCallbackRegistry,
                 mExpansionCallback);
-        mContainer.addOnLayoutChangeListener(this::onContainerLayout);
         mNotificationPanelView = notificationPanelView;
         notificationPanelView.setExpansionListener(this::onPanelExpansionChanged);
     }
 
-    private void onContainerLayout(View v, int left, int top, int right, int bottom,
-            int oldLeft, int oldTop, int oldRight, int oldBottom) {
-        mNotificationPanelView.setBouncerTop(mBouncer.getTop());
-    }
-
     @VisibleForTesting
     void onPanelExpansionChanged(float expansion, boolean tracking) {
         // We don't want to translate the bounce when:
@@ -198,6 +198,7 @@
                 mBouncer.show(false /* resetSecuritySelection */, false /* scrimmed */);
             }
         }
+        mNotificationPanelView.updateLockIcon();
     }
 
     /**
@@ -351,14 +352,6 @@
         }
     }
 
-    public void onScreenTurnedOff() {
-        // TODO: remove
-    }
-
-    public void notifyDeviceWakeUpRequested() {
-        // TODO: remove
-    }
-
     public void setNeedsInput(boolean needsInput) {
         mStatusBarWindowController.setKeyguardNeedsInput(needsInput);
     }
@@ -795,6 +788,10 @@
         setDozing(isDozing);
     }
 
+    public KeyguardBouncer getBouncer() {
+        return mBouncer;
+    }
+
     private static class DismissWithActionRequest {
         final OnDismissAction dismissAction;
         final Runnable cancelAction;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java
index 74c0018..7e45507 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java
@@ -17,7 +17,6 @@
 package com.android.systemui.statusbar.phone;
 
 import static com.android.systemui.Dependency.MAIN_HANDLER;
-import static com.android.systemui.SysUiServiceProvider.getComponent;
 import static com.android.systemui.statusbar.phone.StatusBar.getActivityOptions;
 
 import android.app.ActivityManager;
@@ -32,9 +31,7 @@
 import android.os.AsyncTask;
 import android.os.Looper;
 import android.os.RemoteException;
-import android.os.ServiceManager;
 import android.os.UserHandle;
-import android.service.dreams.DreamService;
 import android.service.dreams.IDreamManager;
 import android.service.notification.StatusBarNotification;
 import android.text.TextUtils;
@@ -78,27 +75,18 @@
     private static final String TAG = "NotificationClickHandler";
     protected static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
 
-    private final AssistManager mAssistManager = Dependency.get(AssistManager.class);
-    private final NotificationGroupManager mGroupManager =
-            Dependency.get(NotificationGroupManager.class);
-    private final StatusBarRemoteInputCallback mStatusBarRemoteInputCallback =
-            (StatusBarRemoteInputCallback) Dependency.get(
-                    NotificationRemoteInputManager.Callback.class);
-    private final NotificationRemoteInputManager mRemoteInputManager =
-            Dependency.get(NotificationRemoteInputManager.class);
-    private final NotificationLockscreenUserManager mLockscreenUserManager =
-            Dependency.get(NotificationLockscreenUserManager.class);
-    private final ShadeController mShadeController = Dependency.get(ShadeController.class);
-    private final KeyguardMonitor mKeyguardMonitor = Dependency.get(KeyguardMonitor.class);
-    private final ActivityStarter mActivityStarter = Dependency.get(ActivityStarter.class);
-    private final NotificationEntryManager mEntryManager =
-            Dependency.get(NotificationEntryManager.class);
-    private final StatusBarStateController mStatusBarStateController =
-            Dependency.get(StatusBarStateController.class);
-    private final NotificationInterruptionStateProvider mNotificationInterruptionStateProvider =
-            Dependency.get(NotificationInterruptionStateProvider.class);
-    private final MetricsLogger mMetricsLogger = Dependency.get(MetricsLogger.class);
-
+    private final AssistManager mAssistManager;
+    private final NotificationGroupManager mGroupManager;
+    private final StatusBarRemoteInputCallback mStatusBarRemoteInputCallback;
+    private final NotificationRemoteInputManager mRemoteInputManager;
+    private final NotificationLockscreenUserManager mLockscreenUserManager;
+    private final ShadeController mShadeController;
+    private final KeyguardMonitor mKeyguardMonitor;
+    private final ActivityStarter mActivityStarter;
+    private final NotificationEntryManager mEntryManager;
+    private final StatusBarStateController mStatusBarStateController;
+    private final NotificationInterruptionStateProvider mNotificationInterruptionStateProvider;
+    private final MetricsLogger mMetricsLogger;
     private final Context mContext;
     private final NotificationPanelView mNotificationPanel;
     private final NotificationPresenter mPresenter;
@@ -113,29 +101,55 @@
     private boolean mIsCollapsingToShowActivityOverLockscreen;
 
     public StatusBarNotificationActivityStarter(Context context,
+            CommandQueue commandQueue,
+            AssistManager assistManager,
             NotificationPanelView panel,
             NotificationPresenter presenter,
+            NotificationEntryManager entryManager,
             HeadsUpManagerPhone headsUpManager,
-            ActivityLaunchAnimator activityLaunchAnimator) {
+            ActivityStarter activityStarter,
+            ActivityLaunchAnimator activityLaunchAnimator,
+            IStatusBarService statusBarService,
+            StatusBarStateController statusBarStateController,
+            KeyguardManager keyguardManager,
+            IDreamManager dreamManager,
+            NotificationRemoteInputManager remoteInputManager,
+            StatusBarRemoteInputCallback remoteInputCallback,
+            NotificationGroupManager groupManager,
+            NotificationLockscreenUserManager lockscreenUserManager,
+            ShadeController shadeController,
+            KeyguardMonitor keyguardMonitor,
+            NotificationInterruptionStateProvider notificationInterruptionStateProvider,
+            MetricsLogger metricsLogger,
+            LockPatternUtils lockPatternUtils) {
         mContext = context;
         mNotificationPanel = panel;
         mPresenter = presenter;
-        mLockPatternUtils = new LockPatternUtils(context);
         mHeadsUpManager = headsUpManager;
-        mKeyguardManager = context.getSystemService(KeyguardManager.class);
         mActivityLaunchAnimator = activityLaunchAnimator;
-        mBarService = IStatusBarService.Stub.asInterface(
-                ServiceManager.getService(Context.STATUS_BAR_SERVICE));
-        mCommandQueue = getComponent(context, CommandQueue.class);
-        mDreamManager = IDreamManager.Stub.asInterface(
-                ServiceManager.checkService(DreamService.DREAM_SERVICE));
-
+        mBarService = statusBarService;
+        mCommandQueue = commandQueue;
+        mKeyguardManager = keyguardManager;
+        mDreamManager = dreamManager;
+        mRemoteInputManager = remoteInputManager;
+        mLockscreenUserManager = lockscreenUserManager;
+        mShadeController = shadeController;
+        mKeyguardMonitor = keyguardMonitor;
+        mActivityStarter = activityStarter;
+        mEntryManager = entryManager;
+        mStatusBarStateController = statusBarStateController;
+        mNotificationInterruptionStateProvider = notificationInterruptionStateProvider;
+        mMetricsLogger = metricsLogger;
+        mAssistManager = assistManager;
+        mGroupManager = groupManager;
+        mLockPatternUtils = lockPatternUtils;
         mEntryManager.addNotificationEntryListener(new NotificationEntryListener() {
             @Override
             public void onPendingEntryAdded(NotificationEntry entry) {
                 handleFullScreenIntent(entry);
             }
         });
+        mStatusBarRemoteInputCallback = remoteInputCallback;
     }
 
     /**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java
index d404982..1e05983 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java
@@ -17,6 +17,7 @@
 package com.android.systemui.statusbar.policy;
 
 import static android.view.Display.INVALID_DISPLAY;
+import static android.view.KeyEvent.KEYCODE_UNKNOWN;
 import static android.view.accessibility.AccessibilityNodeInfo.ACTION_CLICK;
 import static android.view.accessibility.AccessibilityNodeInfo.ACTION_LONG_CLICK;
 
@@ -65,7 +66,6 @@
     private int mTouchDownX;
     private int mTouchDownY;
     private boolean mIsVertical;
-    private boolean mSupportsLongpress = true;
     private AudioManager mAudioManager;
     private boolean mGestureAborted;
     private boolean mLongClicked;
@@ -82,7 +82,7 @@
                     // Just an old-fashioned ImageView
                     performLongClick();
                     mLongClicked = true;
-                } else if (mSupportsLongpress) {
+                } else {
                     sendEvent(KeyEvent.ACTION_DOWN, KeyEvent.FLAG_LONG_PRESS);
                     sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_LONG_CLICKED);
                     mLongClicked = true;
@@ -101,9 +101,8 @@
         TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.KeyButtonView,
                 defStyle, 0);
 
-        mCode = a.getInteger(R.styleable.KeyButtonView_keyCode, 0);
+        mCode = a.getInteger(R.styleable.KeyButtonView_keyCode, KEYCODE_UNKNOWN);
 
-        mSupportsLongpress = a.getBoolean(R.styleable.KeyButtonView_keyRepeat, true);
         mPlaySounds = a.getBoolean(R.styleable.KeyButtonView_playSound, true);
 
         TypedValue value = new TypedValue();
@@ -124,7 +123,7 @@
 
     @Override
     public boolean isClickable() {
-        return mCode != 0 || super.isClickable();
+        return mCode != KEYCODE_UNKNOWN || super.isClickable();
     }
 
     public void setCode(int code) {
@@ -163,9 +162,9 @@
     @Override
     public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
         super.onInitializeAccessibilityNodeInfo(info);
-        if (mCode != 0) {
+        if (mCode != KEYCODE_UNKNOWN) {
             info.addAction(new AccessibilityNodeInfo.AccessibilityAction(ACTION_CLICK, null));
-            if (mSupportsLongpress || isLongClickable()) {
+            if (isLongClickable()) {
                 info.addAction(
                         new AccessibilityNodeInfo.AccessibilityAction(ACTION_LONG_CLICK, null));
             }
@@ -182,13 +181,13 @@
 
     @Override
     public boolean performAccessibilityActionInternal(int action, Bundle arguments) {
-        if (action == ACTION_CLICK && mCode != 0) {
+        if (action == ACTION_CLICK && mCode != KEYCODE_UNKNOWN) {
             sendEvent(KeyEvent.ACTION_DOWN, 0, SystemClock.uptimeMillis());
             sendEvent(KeyEvent.ACTION_UP, 0);
             sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED);
             playSoundEffect(SoundEffectConstants.CLICK);
             return true;
-        } else if (action == ACTION_LONG_CLICK && mCode != 0) {
+        } else if (action == ACTION_LONG_CLICK && mCode != KEYCODE_UNKNOWN) {
             sendEvent(KeyEvent.ACTION_DOWN, KeyEvent.FLAG_LONG_PRESS);
             sendEvent(KeyEvent.ACTION_UP, 0);
             sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_LONG_CLICKED);
@@ -197,6 +196,7 @@
         return super.performAccessibilityActionInternal(action, arguments);
     }
 
+    @Override
     public boolean onTouchEvent(MotionEvent ev) {
         final boolean showSwipeUI = mOverviewProxyService.shouldShowSwipeUpUI();
         final int action = ev.getAction();
@@ -218,7 +218,7 @@
                 // Use raw X and Y to detect gestures in case a parent changes the x and y values
                 mTouchDownX = (int) ev.getRawX();
                 mTouchDownY = (int) ev.getRawY();
-                if (mCode != 0) {
+                if (mCode != KEYCODE_UNKNOWN) {
                     sendEvent(KeyEvent.ACTION_DOWN, 0, mDownTime);
                 } else {
                     // Provide the same haptic feedback that the system offers for virtual keys.
@@ -249,7 +249,7 @@
                 break;
             case MotionEvent.ACTION_CANCEL:
                 setPressed(false);
-                if (mCode != 0) {
+                if (mCode != KEYCODE_UNKNOWN) {
                     sendEvent(KeyEvent.ACTION_UP, KeyEvent.FLAG_CANCELED);
                 }
                 removeCallbacks(mCheckLongPress);
@@ -269,7 +269,7 @@
                     // and it feels weird to sometimes get a release haptic and other times not.
                     performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY_RELEASE);
                 }
-                if (mCode != 0) {
+                if (mCode != KEYCODE_UNKNOWN) {
                     if (doIt) {
                         sendEvent(KeyEvent.ACTION_UP, 0);
                         sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED);
@@ -299,7 +299,7 @@
         sendEvent(action, flags, SystemClock.uptimeMillis());
     }
 
-    void sendEvent(int action, int flags, long when) {
+    private void sendEvent(int action, int flags, long when) {
         mMetricsLogger.write(new LogMaker(MetricsEvent.ACTION_NAV_BUTTON_EVENT)
                 .setType(MetricsEvent.TYPE_ACTION)
                 .setSubtype(mCode)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardMonitor.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardMonitor.java
index aba2377..01498e6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardMonitor.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardMonitor.java
@@ -29,6 +29,25 @@
     long getKeyguardFadingAwayDelay();
     long calculateGoingToFullShadeDelay();
 
+    default boolean isDeviceInteractive() {
+        return false;
+    }
+
+    default void setLaunchTransitionFadingAway(boolean b) {
+    }
+
+    default void notifyKeyguardGoingAway(boolean b) {
+    }
+
+    default void notifyKeyguardFadingAway(long delay, long fadeoutDuration) {
+    }
+
+    default void notifyKeyguardDoneFading() {
+    }
+
+    default void notifyKeyguardState(boolean showing, boolean methodSecure, boolean occluded) {
+    }
+
     interface Callback {
         void onKeyguardShowingChanged();
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
index d3164a0..5bd394f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
@@ -256,7 +256,8 @@
                 level++;
             }
             boolean dataDisabled = mCurrentState.userSetup
-                    && mCurrentState.iconGroup == TelephonyIcons.DATA_DISABLED;
+                    && (mCurrentState.iconGroup == TelephonyIcons.DATA_DISABLED
+                    || mCurrentState.iconGroup == TelephonyIcons.NOT_DEFAULT_DATA);
             boolean noInternet = mCurrentState.inetCondition == 0;
             boolean cutOut = dataDisabled || noInternet;
             return SignalDrawable.getState(level, getNumLevels(), cutOut);
@@ -285,7 +286,8 @@
         if (mCurrentState.inetCondition == 0) {
             dataContentDescription = mContext.getString(R.string.data_connection_no_internet);
         }
-        final boolean dataDisabled = mCurrentState.iconGroup == TelephonyIcons.DATA_DISABLED
+        final boolean dataDisabled = (mCurrentState.iconGroup == TelephonyIcons.DATA_DISABLED
+                || mCurrentState.iconGroup == TelephonyIcons.NOT_DEFAULT_DATA)
                 && mCurrentState.userSetup;
 
         // Show icon in QS when we are connected or data is disabled.
@@ -456,7 +458,12 @@
         if (isCarrierNetworkChangeActive()) {
             mCurrentState.iconGroup = TelephonyIcons.CARRIER_NETWORK_CHANGE;
         } else if (isDataDisabled() && !mConfig.alwaysShowDataRatIcon) {
-            mCurrentState.iconGroup = TelephonyIcons.DATA_DISABLED;
+            if (mSubscriptionInfo.getSubscriptionId()
+                    != mDefaults.getDefaultDataSubId()) {
+                mCurrentState.iconGroup = TelephonyIcons.NOT_DEFAULT_DATA;
+            } else {
+                mCurrentState.iconGroup = TelephonyIcons.DATA_DISABLED;
+            }
         }
         if (isEmergencyOnly() != mCurrentState.isEmergency) {
             mCurrentState.isEmergency = isEmergencyOnly();
@@ -474,8 +481,8 @@
     private MobileIconGroup getNr5GIconGroup() {
         if (mServiceState == null) return null;
 
-        int nrStatus = mServiceState.getNrStatus();
-        if (nrStatus == NetworkRegistrationInfo.NR_STATUS_CONNECTED) {
+        int nrState = mServiceState.getNrState();
+        if (nrState == NetworkRegistrationInfo.NR_STATE_CONNECTED) {
             // Check if the NR 5G is using millimeter wave and the icon is config.
             if (mServiceState.getNrFrequencyRange() == ServiceState.FREQUENCY_RANGE_MMWAVE) {
                 if (mConfig.nr5GIconMap.containsKey(Config.NR_CONNECTED_MMWAVE)) {
@@ -488,11 +495,11 @@
             if (mConfig.nr5GIconMap.containsKey(Config.NR_CONNECTED)) {
                 return mConfig.nr5GIconMap.get(Config.NR_CONNECTED);
             }
-        } else if (nrStatus == NetworkRegistrationInfo.NR_STATUS_NOT_RESTRICTED) {
+        } else if (nrState == NetworkRegistrationInfo.NR_STATE_NOT_RESTRICTED) {
             if (mConfig.nr5GIconMap.containsKey(Config.NR_NOT_RESTRICTED)) {
                 return mConfig.nr5GIconMap.get(Config.NR_NOT_RESTRICTED);
             }
-        } else if (nrStatus == NetworkRegistrationInfo.NR_STATUS_RESTRICTED) {
+        } else if (nrState == NetworkRegistrationInfo.NR_STATE_RESTRICTED) {
             if (mConfig.nr5GIconMap.containsKey(Config.NR_RESTRICTED)) {
                 return mConfig.nr5GIconMap.get(Config.NR_RESTRICTED);
             }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
index f4d6237..ef39912 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
@@ -987,6 +987,7 @@
                             datatype.equals("lte") ? TelephonyIcons.LTE :
                             datatype.equals("lte+") ? TelephonyIcons.LTE_PLUS :
                             datatype.equals("dis") ? TelephonyIcons.DATA_DISABLED :
+                            datatype.equals("not") ? TelephonyIcons.NOT_DEFAULT_DATA :
                             TelephonyIcons.UNKNOWN;
                 }
                 if (args.containsKey("roam")) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SensorPrivacyController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SensorPrivacyController.java
new file mode 100644
index 0000000..6d5ce60
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SensorPrivacyController.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.policy;
+
+/**
+ * Interface for classes to control sensor privacy state and notification.
+ */
+public interface SensorPrivacyController extends
+        CallbackController<SensorPrivacyController.OnSensorPrivacyChangedListener> {
+
+    /**
+     * Returns whether sensor privacy is enabled.
+     */
+    boolean isSensorPrivacyEnabled();
+
+    /**
+     * Interface for classes to receive callbacks when sensor privacy state changes.
+     */
+    interface OnSensorPrivacyChangedListener {
+        void onSensorPrivacyChanged(boolean enabled);
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SensorPrivacyControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SensorPrivacyControllerImpl.java
new file mode 100644
index 0000000..5db6693
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SensorPrivacyControllerImpl.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.policy;
+
+import android.content.Context;
+import android.hardware.SensorPrivacyManager;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
+/**
+ * Controls sensor privacy state and notification.
+ */
+@Singleton
+public class SensorPrivacyControllerImpl implements SensorPrivacyController,
+        SensorPrivacyManager.OnSensorPrivacyChangedListener {
+    private SensorPrivacyManager mSensorPrivacyManager;
+    private final List<OnSensorPrivacyChangedListener> mListeners;
+    private Object mLock = new Object();
+    private boolean mSensorPrivacyEnabled;
+
+    /**
+     * Public constructor.
+     */
+    @Inject
+    public SensorPrivacyControllerImpl(Context context) {
+        mSensorPrivacyManager = (SensorPrivacyManager) context.getSystemService(
+                Context.SENSOR_PRIVACY_SERVICE);
+        mSensorPrivacyEnabled = mSensorPrivacyManager.isSensorPrivacyEnabled();
+        mSensorPrivacyManager.addSensorPrivacyListener(this);
+        mListeners = new ArrayList<>(1);
+    }
+
+    /**
+     * Returns whether sensor privacy is enabled.
+     */
+    public boolean isSensorPrivacyEnabled() {
+        synchronized (mLock) {
+            return mSensorPrivacyEnabled;
+        }
+    }
+
+    /**
+     * Adds the provided listener for callbacks when sensor privacy state changes.
+     */
+    public void addCallback(OnSensorPrivacyChangedListener listener) {
+        synchronized (mLock) {
+            mListeners.add(listener);
+            notifyListenerLocked(listener);
+        }
+    }
+
+    /**
+     * Removes the provided listener from callbacks when sensor privacy state changes.
+     */
+    public void removeCallback(OnSensorPrivacyChangedListener listener) {
+        synchronized (mLock) {
+            mListeners.remove(listener);
+        }
+    }
+
+    /**
+     * Callback invoked by the SensorPrivacyService when sensor privacy state changes.
+     */
+    public void onSensorPrivacyChanged(boolean enabled) {
+        synchronized (mLock) {
+            mSensorPrivacyEnabled = enabled;
+            for (OnSensorPrivacyChangedListener listener : mListeners) {
+                notifyListenerLocked(listener);
+            }
+        }
+    }
+
+    private void notifyListenerLocked(OnSensorPrivacyChangedListener listener) {
+        listener.onSensorPrivacyChanged(mSensorPrivacyEnabled);
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/TelephonyIcons.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/TelephonyIcons.java
index 7347f66..e151ca3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/TelephonyIcons.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/TelephonyIcons.java
@@ -245,6 +245,22 @@
             0,
             false);
 
+    static final MobileIconGroup NOT_DEFAULT_DATA = new MobileIconGroup(
+            "NotDefaultData",
+            null,
+            null,
+            AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH,
+            0, 0,
+            0,
+            0,
+            AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH[0],
+            R.string.not_default_data_content_description,
+            0,
+            false);
+
+    // When adding a new MobileIconGround, check if the dataContentDescription has to be filtered
+    // in QSCarrier#hasValidTypeContentDescription
+
     /** Mapping icon name(lower case) to the icon object. */
     static final Map<String, MobileIconGroup> ICON_NAME_TO_ICON;
     static {
@@ -265,6 +281,7 @@
         ICON_NAME_TO_ICON.put("5g", NR_5G);
         ICON_NAME_TO_ICON.put("5g_plus", NR_5G_PLUS);
         ICON_NAME_TO_ICON.put("datadisable", DATA_DISABLED);
+        ICON_NAME_TO_ICON.put("notdefaultdata", NOT_DEFAULT_DATA);
     }
 }
 
diff --git a/packages/SystemUI/src/com/android/systemui/volume/Events.java b/packages/SystemUI/src/com/android/systemui/volume/Events.java
index 6e740b8..2a84c5d 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/Events.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/Events.java
@@ -56,6 +56,7 @@
     public static final int EVENT_SHOW_USB_OVERHEAT_ALARM = 19; // (reason|int) (keyguard|bool)
     public static final int EVENT_DISMISS_USB_OVERHEAT_ALARM = 20; // (reason|int) (keyguard|bool)
     public static final int EVENT_ODI_CAPTIONS_CLICK = 21;
+    public static final int EVENT_ODI_CAPTIONS_TOOLTIP_CLICK = 22;
 
     private static final String[] EVENT_TAGS = {
             "show_dialog",
@@ -79,7 +80,8 @@
             "ringer_toggle",
             "show_usb_overheat_alarm",
             "dismiss_usb_overheat_alarm",
-            "odi_captions_click"
+            "odi_captions_click",
+            "odi_captions_tooltip_click"
     };
 
     public static final int DISMISS_REASON_UNKNOWN = 0;
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java
index 9192a25..2fa8889 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java
@@ -282,9 +282,9 @@
                 Settings.Secure.ODI_CAPTIONS_ENABLED, isEnabled ? 1 : 0);
     }
 
-    public void getCaptionsComponentState() {
+    public void getCaptionsComponentState(boolean fromTooltip) {
         if (mDestroyed) return;
-        mWorker.sendEmptyMessage(W.GET_CAPTIONS_COMPONENT_STATE);
+        mWorker.obtainMessage(W.GET_CAPTIONS_COMPONENT_STATE, fromTooltip).sendToTarget();
     }
 
     public void notifyVisible(boolean visible) {
@@ -382,13 +382,13 @@
         }
     }
 
-    private void onGetCaptionsComponentStateW() {
+    private void onGetCaptionsComponentStateW(boolean fromTooltip) {
         try {
             String componentNameString = mContext.getString(
                     com.android.internal.R.string.config_defaultSystemCaptionsService);
             if (TextUtils.isEmpty(componentNameString)) {
                 // component doesn't exist
-                mCallbacks.onCaptionComponentStateChanged(false);
+                mCallbacks.onCaptionComponentStateChanged(false, fromTooltip);
                 return;
             }
 
@@ -399,18 +399,18 @@
 
             ComponentName componentName = ComponentName.unflattenFromString(componentNameString);
             if (componentName == null) {
-                mCallbacks.onCaptionComponentStateChanged(false);
+                mCallbacks.onCaptionComponentStateChanged(false, fromTooltip);
                 return;
             }
 
             PackageManager packageManager = mContext.getPackageManager();
             mCallbacks.onCaptionComponentStateChanged(
                     packageManager.getComponentEnabledSetting(componentName)
-                    == PackageManager.COMPONENT_ENABLED_STATE_ENABLED);
+                    == PackageManager.COMPONENT_ENABLED_STATE_ENABLED, fromTooltip);
         } catch (Exception ex) {
             Log.e(TAG,
                     "isCaptionsServiceEnabled failed to check for captions component", ex);
-            mCallbacks.onCaptionComponentStateChanged(false);
+            mCallbacks.onCaptionComponentStateChanged(false, fromTooltip);
         }
     }
 
@@ -790,7 +790,8 @@
                 case NOTIFY_VISIBLE: onNotifyVisibleW(msg.arg1 != 0); break;
                 case USER_ACTIVITY: onUserActivityW(); break;
                 case SHOW_SAFETY_WARNING: onShowSafetyWarningW(msg.arg1); break;
-                case GET_CAPTIONS_COMPONENT_STATE: onGetCaptionsComponentStateW(); break;
+                case GET_CAPTIONS_COMPONENT_STATE:
+                    onGetCaptionsComponentStateW((Boolean) msg.obj); break;
                 case ACCESSIBILITY_MODE_CHANGED: onAccessibilityModeChanged((Boolean) msg.obj);
             }
         }
@@ -933,11 +934,13 @@
         }
 
         @Override
-        public void onCaptionComponentStateChanged(Boolean isComponentEnabled) {
+        public void onCaptionComponentStateChanged(
+                Boolean isComponentEnabled, Boolean fromTooltip) {
             boolean componentEnabled = isComponentEnabled == null ? false : isComponentEnabled;
             for (final Map.Entry<Callbacks, Handler> entry : mCallbackMap.entrySet()) {
                 entry.getValue().post(
-                        () -> entry.getKey().onCaptionComponentStateChanged(componentEnabled));
+                        () -> entry.getKey().onCaptionComponentStateChanged(
+                                componentEnabled, fromTooltip));
             }
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
index 398b309..cdda216 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
@@ -28,6 +28,7 @@
 import static android.view.View.ACCESSIBILITY_LIVE_REGION_POLITE;
 import static android.view.View.GONE;
 import static android.view.View.VISIBLE;
+import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
 
 import static com.android.systemui.volume.Events.DISMISS_REASON_ODI_CAPTIONS_CLICKED;
 import static com.android.systemui.volume.Events.DISMISS_REASON_SETTINGS_CLICKED;
@@ -64,11 +65,13 @@
 import android.util.Slog;
 import android.util.SparseBooleanArray;
 import android.view.ContextThemeWrapper;
+import android.view.Gravity;
 import android.view.MotionEvent;
 import android.view.View;
 import android.view.View.AccessibilityDelegate;
 import android.view.ViewGroup;
 import android.view.ViewPropertyAnimator;
+import android.view.ViewStub;
 import android.view.Window;
 import android.view.WindowManager;
 import android.view.accessibility.AccessibilityEvent;
@@ -113,7 +116,10 @@
 
     static final int DIALOG_TIMEOUT_MILLIS = 3000;
     static final int DIALOG_SAFETYWARNING_TIMEOUT_MILLIS = 5000;
+    static final int DIALOG_ODI_CAPTIONS_TOOLTIP_TIMEOUT_MILLIS = 5000;
     static final int DIALOG_HOVERING_TIMEOUT_MILLIS = 16000;
+    static final int DIALOG_SHOW_ANIMATION_DURATION = 300;
+    static final int DIALOG_HIDE_ANIMATION_DURATION = 250;
 
     private final Context mContext;
     private final H mHandler = new H();
@@ -152,15 +158,21 @@
     private boolean mHovering = false;
     private boolean mShowActiveStreamOnly;
     private boolean mConfigChanged = false;
+    private boolean mHasSeenODICaptionsTooltip;
+    private ViewStub mODICaptionsTooltipViewStub;
+    private View mODICaptionsTooltipView = null;
 
     public VolumeDialogImpl(Context context) {
-        mContext = new ContextThemeWrapper(context, com.android.systemui.R.style.qs_theme);
+        mContext =
+                new ContextThemeWrapper(context, com.android.systemui.R.style.volume_dialog_theme);
         mController = Dependency.get(VolumeDialogController.class);
         mKeyguard = (KeyguardManager) mContext.getSystemService(Context.KEYGUARD_SERVICE);
         mActivityManager = (ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE);
         mAccessibilityMgr = Dependency.get(AccessibilityManagerWrapper.class);
         mDeviceProvisionedController = Dependency.get(DeviceProvisionedController.class);
         mShowActiveStreamOnly = showActiveStreamOnly();
+        mHasSeenODICaptionsTooltip =
+                Prefs.getBoolean(context, Prefs.Key.HAS_SEEN_ODI_CAPTIONS_TOOLTIP, false);
     }
 
     public void init(int windowType, Callback callback) {
@@ -201,8 +213,9 @@
         lp.format = PixelFormat.TRANSLUCENT;
         lp.setTitle(VolumeDialogImpl.class.getSimpleName());
         lp.windowAnimations = -1;
+        lp.gravity = Gravity.RIGHT | Gravity.CENTER_VERTICAL;
         mWindow.setAttributes(lp);
-        mWindow.setLayout(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
+        mWindow.setLayout(WRAP_CONTENT, WRAP_CONTENT);
 
         mDialog.setContentView(R.layout.volume_dialog);
         mDialogView = mDialog.findViewById(R.id.volume_dialog);
@@ -213,12 +226,13 @@
             mDialogView.animate()
                     .alpha(1)
                     .translationX(0)
-                    .setDuration(300)
+                    .setDuration(DIALOG_SHOW_ANIMATION_DURATION)
                     .setInterpolator(new SystemUIInterpolators.LogDecelerateInterpolator())
                     .withEndAction(() -> {
                         if (!Prefs.getBoolean(mContext, Prefs.Key.TOUCHED_RINGER_TOGGLE, false)) {
                             if (mRingerIcon != null) {
-                                mRingerIcon.postOnAnimationDelayed(mSinglePress, 1500);
+                                mRingerIcon.postOnAnimationDelayed(
+                                        getSinglePressFor(mRingerIcon), 1500);
                             }
                         }
                     })
@@ -233,20 +247,23 @@
             return true;
         });
 
-        lp = mWindow.getAttributes();
-        lp.gravity = ((FrameLayout.LayoutParams) mDialogView.getLayoutParams()).gravity;
-        mWindow.setAttributes(lp);
-
         mDialogRowsView = mDialog.findViewById(R.id.volume_dialog_rows);
         mRinger = mDialog.findViewById(R.id.ringer);
         if (mRinger != null) {
             mRingerIcon = mRinger.findViewById(R.id.ringer_icon);
             mZenIcon = mRinger.findViewById(R.id.dnd_icon);
         }
+
         mODICaptionsView = mDialog.findViewById(R.id.odi_captions);
         if (mODICaptionsView != null) {
             mODICaptionsIcon = mODICaptionsView.findViewById(R.id.odi_captions_icon);
         }
+        mODICaptionsTooltipViewStub = mDialog.findViewById(R.id.odi_captions_tooltip_stub);
+        if (mHasSeenODICaptionsTooltip && mODICaptionsTooltipViewStub != null) {
+            mDialogView.removeView(mODICaptionsTooltipViewStub);
+            mODICaptionsTooltipViewStub = null;
+        }
+
         mSettingsView = mDialog.findViewById(R.id.settings_container);
         mSettingsIcon = mDialog.findViewById(R.id.settings);
 
@@ -495,10 +512,70 @@
             });
         }
 
-        mController.getCaptionsComponentState();
+        mController.getCaptionsComponentState(false);
     }
 
-    private void updateODICaptionsH(boolean isServiceComponentEnabled) {
+    private void checkODICaptionsTooltip(boolean fromDismiss) {
+        if (!mHasSeenODICaptionsTooltip && !fromDismiss && mODICaptionsTooltipViewStub != null) {
+            mController.getCaptionsComponentState(true);
+        } else {
+            if (mHasSeenODICaptionsTooltip && mODICaptionsTooltipView != null) {
+                hideCaptionsTooltip();
+            }
+        }
+    }
+
+    protected void showCaptionsTooltip() {
+        if (!mHasSeenODICaptionsTooltip && mODICaptionsTooltipViewStub != null) {
+            mODICaptionsTooltipView = mODICaptionsTooltipViewStub.inflate();
+            mODICaptionsTooltipView.findViewById(R.id.dismiss).setOnClickListener(v -> {
+                hideCaptionsTooltip();
+                Events.writeEvent(mContext, Events.EVENT_ODI_CAPTIONS_TOOLTIP_CLICK);
+            });
+            mODICaptionsTooltipViewStub = null;
+            rescheduleTimeoutH();
+        }
+
+        if (mODICaptionsTooltipView != null) {
+            mODICaptionsTooltipView.setAlpha(0.f);
+            mODICaptionsTooltipView.animate()
+                .alpha(1.f)
+                .setStartDelay(DIALOG_SHOW_ANIMATION_DURATION)
+                .withEndAction(() -> {
+                    if (D.BUG) Log.d(TAG, "tool:checkODICaptionsTooltip() putBoolean true");
+                    Prefs.putBoolean(mContext,
+                            Prefs.Key.HAS_SEEN_ODI_CAPTIONS_TOOLTIP, true);
+                    mHasSeenODICaptionsTooltip = true;
+                    if (mODICaptionsIcon != null) {
+                        mODICaptionsIcon
+                                .postOnAnimation(getSinglePressFor(mODICaptionsIcon));
+                    }
+                })
+                .start();
+        }
+    }
+
+    private void hideCaptionsTooltip() {
+        if (mODICaptionsTooltipView != null) {
+            mODICaptionsTooltipView.animate().cancel();
+            mODICaptionsTooltipView.setAlpha(1.f);
+            mODICaptionsTooltipView.animate()
+                    .alpha(0.f)
+                    .setStartDelay(0)
+                    .setDuration(DIALOG_HIDE_ANIMATION_DURATION)
+                    .start();
+        }
+    }
+
+    protected void tryToRemoveCaptionsTooltip() {
+        if (mHasSeenODICaptionsTooltip && mODICaptionsTooltipView != null) {
+            ViewGroup container = mDialog.findViewById(R.id.volume_dialog_container);
+            container.removeView(mODICaptionsTooltipView);
+            mODICaptionsTooltipView = null;
+        }
+    }
+
+    private void updateODICaptionsH(boolean isServiceComponentEnabled, boolean fromTooltip) {
         if (mODICaptionsView != null) {
             mODICaptionsView.setVisibility(isServiceComponentEnabled ? VISIBLE : GONE);
         }
@@ -506,6 +583,7 @@
         if (!isServiceComponentEnabled) return;
 
         updateCaptionsIcon();
+        if (fromTooltip) showCaptionsTooltip();
     }
 
     private void updateCaptionsIcon() {
@@ -602,7 +680,8 @@
         mDialog.show();
         Events.writeEvent(mContext, Events.EVENT_SHOW_DIALOG, reason, mKeyguard.isKeyguardLocked());
         mController.notifyVisible(true);
-        mController.getCaptionsComponentState();
+        mController.getCaptionsComponentState(false);
+        checkODICaptionsTooltip(false);
     }
 
     protected void rescheduleTimeoutH() {
@@ -625,11 +704,21 @@
                     AccessibilityManager.FLAG_CONTENT_TEXT
                             | AccessibilityManager.FLAG_CONTENT_CONTROLS);
         }
+        if (!mHasSeenODICaptionsTooltip && mODICaptionsTooltipView != null) {
+            return mAccessibilityMgr.getRecommendedTimeoutMillis(
+                    DIALOG_ODI_CAPTIONS_TOOLTIP_TIMEOUT_MILLIS,
+                    AccessibilityManager.FLAG_CONTENT_TEXT
+                            | AccessibilityManager.FLAG_CONTENT_CONTROLS);
+        }
         return mAccessibilityMgr.getRecommendedTimeoutMillis(DIALOG_TIMEOUT_MILLIS,
                 AccessibilityManager.FLAG_CONTENT_CONTROLS);
     }
 
     protected void dismissH(int reason) {
+        if (D.BUG) {
+            Log.d(TAG, "mDialog.dismiss() reason: " + Events.DISMISS_REASONS[reason]
+                    + " from: " + Debug.getCaller());
+        }
         mHandler.removeMessages(H.DISMISS);
         mHandler.removeMessages(H.SHOW);
         mDialogView.animate().cancel();
@@ -642,14 +731,15 @@
         mDialogView.setAlpha(1);
         ViewPropertyAnimator animator = mDialogView.animate()
                 .alpha(0)
-                .setDuration(250)
+                .setDuration(DIALOG_HIDE_ANIMATION_DURATION)
                 .setInterpolator(new SystemUIInterpolators.LogAccelerateInterpolator())
                 .withEndAction(() -> mHandler.postDelayed(() -> {
-                    if (D.BUG) Log.d(TAG, "mDialog.dismiss()");
                     mDialog.dismiss();
+                    tryToRemoveCaptionsTooltip();
                 }, 50));
         if (!isLandscape()) animator.translationX(mDialogView.getWidth() / 2);
         animator.start();
+        checkODICaptionsTooltip(true);
         mController.notifyVisible(false);
         synchronized (mSafetyWarningLock) {
             if (mSafetyWarning != null) {
@@ -822,6 +912,7 @@
     }
 
     protected void onStateChangedH(State state) {
+        if (D.BUG) Log.d(TAG, "onStateChangedH() state: " + state.toString());
         if (mState != null && state != null
                 && mState.ringerModeInternal != state.ringerModeInternal
                 && state.ringerModeInternal == AudioManager.RINGER_MODE_VIBRATE) {
@@ -847,7 +938,7 @@
             mActiveStream = state.activeStream;
             VolumeRow activeRow = getActiveRow();
             updateRowsH(activeRow);
-            rescheduleTimeoutH();
+            if (mShowing) rescheduleTimeoutH();
         }
         for (VolumeRow row : mRows) {
             updateVolumeRowH(row);
@@ -1114,24 +1205,22 @@
         }
     }
 
-    private Runnable mSinglePress = new Runnable() {
-        @Override
-        public void run() {
-            if (mRingerIcon != null) {
-                mRingerIcon.setPressed(true);
-                mRingerIcon.postOnAnimationDelayed(mSingleUnpress, 200);
+    private Runnable getSinglePressFor(ImageButton button) {
+        return () -> {
+            if (button != null) {
+                button.setPressed(true);
+                button.postOnAnimationDelayed(getSingleUnpressFor(button), 200);
             }
-        }
-    };
+        };
+    }
 
-    private Runnable mSingleUnpress = new Runnable() {
-        @Override
-        public void run() {
-            if (mRingerIcon != null) {
-                mRingerIcon.setPressed(false);
+    private Runnable getSingleUnpressFor(ImageButton button) {
+        return () -> {
+            if (button != null) {
+                button.setPressed(false);
             }
-        }
-    };
+        };
+    }
 
     private final VolumeDialogController.Callbacks mControllerCallbackH
             = new VolumeDialogController.Callbacks() {
@@ -1198,8 +1287,9 @@
         }
 
         @Override
-        public void onCaptionComponentStateChanged(Boolean isComponentEnabled) {
-            updateODICaptionsH(isComponentEnabled);
+        public void onCaptionComponentStateChanged(
+                Boolean isComponentEnabled, Boolean fromTooltip) {
+            updateODICaptionsH(isComponentEnabled, fromTooltip);
         }
     };
 
@@ -1232,7 +1322,7 @@
 
     private final class CustomDialog extends Dialog implements DialogInterface {
         public CustomDialog(Context context) {
-            super(context, com.android.systemui.R.style.qs_theme);
+            super(context, com.android.systemui.R.style.volume_dialog_theme);
         }
 
         @Override
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeToolTipView.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeToolTipView.java
new file mode 100644
index 0000000..1de5585
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeToolTipView.java
@@ -0,0 +1,76 @@
+/*
+ * 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.volume;
+
+import android.content.Context;
+import android.graphics.CornerPathEffect;
+import android.graphics.Paint;
+import android.graphics.drawable.ShapeDrawable;
+import android.util.AttributeSet;
+import android.util.TypedValue;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.LinearLayout;
+
+import androidx.core.content.ContextCompat;
+
+import com.android.systemui.R;
+import com.android.systemui.recents.TriangleShape;
+
+/**
+ * Tool tip view that draws an arrow that points to the volume dialog.
+ */
+public class VolumeToolTipView extends LinearLayout {
+    public VolumeToolTipView(Context context) {
+        super(context);
+    }
+
+    public VolumeToolTipView(Context context, AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    public VolumeToolTipView(Context context, AttributeSet attrs, int defStyleAttr) {
+        super(context, attrs, defStyleAttr);
+    }
+
+    public VolumeToolTipView(Context context, AttributeSet attrs, int defStyleAttr,
+            int defStyleRes) {
+        super(context, attrs, defStyleAttr, defStyleRes);
+    }
+
+    @Override
+    protected void onFinishInflate() {
+        super.onFinishInflate();
+        drawArrow();
+    }
+
+    private void drawArrow() {
+        View arrowView = findViewById(R.id.arrow);
+        ViewGroup.LayoutParams arrowLp = arrowView.getLayoutParams();
+        ShapeDrawable arrowDrawable = new ShapeDrawable(TriangleShape.createHorizontal(
+                arrowLp.width, arrowLp.height, false));
+        Paint arrowPaint = arrowDrawable.getPaint();
+        TypedValue typedValue = new TypedValue();
+        getContext().getTheme().resolveAttribute(android.R.attr.colorAccent, typedValue, true);
+        arrowPaint.setColor(ContextCompat.getColor(getContext(), typedValue.resourceId));
+        // The corner path effect won't be reflected in the shadow, but shouldn't be noticeable.
+        arrowPaint.setPathEffect(new CornerPathEffect(
+                getResources().getDimension(R.dimen.volume_tool_tip_arrow_corner_radius)));
+        arrowView.setBackground(arrowDrawable);
+
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchTest.java
index b0d1106..29505a2 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchTest.java
@@ -101,6 +101,8 @@
         // AND the plugin returns a view for the big clock
         ClockPlugin plugin = mock(ClockPlugin.class);
         when(plugin.getBigClockView()).thenReturn(mBigClock);
+        // AND in the keyguard state
+        mStateListener.onStateChanged(StatusBarState.KEYGUARD);
         // WHEN the plugin is connected
         mKeyguardClockSwitch.getClockChangedListener().onClockChanged(plugin);
         // THEN the big clock container is visible and it is the parent of the
@@ -166,6 +168,8 @@
         ClockPlugin plugin = mock(ClockPlugin.class);
         TextClock pluginView = new TextClock(getContext());
         when(plugin.getBigClockView()).thenReturn(pluginView);
+        // AND in the keyguard state
+        mStateListener.onStateChanged(StatusBarState.KEYGUARD);
         // WHEN the plugin is connected and then disconnected
         mKeyguardClockSwitch.getClockChangedListener().onClockChanged(plugin);
         mKeyguardClockSwitch.getClockChangedListener().onClockChanged(null);
@@ -245,21 +249,25 @@
     }
 
     @Test
-    public void onStateChanged_InvisibleInShade() {
+    public void onStateChanged_GoneInShade() {
         // GIVEN that the big clock container is visible
         mBigClockContainer.setVisibility(View.VISIBLE);
         mKeyguardClockSwitch.setBigClockContainer(mBigClockContainer);
         // WHEN transitioned to SHADE state
         mStateListener.onStateChanged(StatusBarState.SHADE);
-        // THEN the container is invisible.
-        assertThat(mBigClockContainer.getVisibility()).isEqualTo(View.INVISIBLE);
+        // THEN the container is gone.
+        assertThat(mBigClockContainer.getVisibility()).isEqualTo(View.GONE);
     }
 
     @Test
     public void onStateChanged_VisibleInKeyguard() {
-        // GIVEN that the big clock container is invisible
-        mBigClockContainer.setVisibility(View.INVISIBLE);
+        // GIVEN that the big clock container is gone
+        mBigClockContainer.setVisibility(View.GONE);
         mKeyguardClockSwitch.setBigClockContainer(mBigClockContainer);
+        // AND GIVEN that a plugin is active.
+        ClockPlugin plugin = mock(ClockPlugin.class);
+        when(plugin.getBigClockView()).thenReturn(mBigClock);
+        mKeyguardClockSwitch.getClockChangedListener().onClockChanged(plugin);
         // WHEN transitioned to KEYGUARD state
         mStateListener.onStateChanged(StatusBarState.KEYGUARD);
         // THEN the container is visible.
@@ -274,6 +282,8 @@
         ClockPlugin plugin = mock(ClockPlugin.class);
         when(plugin.getBigClockView()).thenReturn(mBigClock);
         mKeyguardClockSwitch.getClockChangedListener().onClockChanged(plugin);
+        // AND in the keyguard state
+        mStateListener.onStateChanged(StatusBarState.KEYGUARD);
         // WHEN the container is associated with the clock switch
         mKeyguardClockSwitch.setBigClockContainer(mBigClockContainer);
         // THEN the container remains visible.
@@ -281,20 +291,6 @@
     }
 
     @Test
-    public void setBigClockContainer_invisible() {
-        // GIVEN that the big clock container is invisible
-        mBigClockContainer.setVisibility(View.INVISIBLE);
-        // AND GIVEN that a plugin is active.
-        ClockPlugin plugin = mock(ClockPlugin.class);
-        when(plugin.getBigClockView()).thenReturn(mBigClock);
-        mKeyguardClockSwitch.getClockChangedListener().onClockChanged(plugin);
-        // WHEN the container is associated with the clock switch
-        mKeyguardClockSwitch.setBigClockContainer(mBigClockContainer);
-        // THEN the container remains invisible.
-        assertThat(mBigClockContainer.getVisibility()).isEqualTo(View.INVISIBLE);
-    }
-
-    @Test
     public void setBigClockContainer_gone() {
         // GIVEN that the big clock container is gone
         mBigClockContainer.setVisibility(View.GONE);
@@ -302,6 +298,8 @@
         ClockPlugin plugin = mock(ClockPlugin.class);
         when(plugin.getBigClockView()).thenReturn(mBigClock);
         mKeyguardClockSwitch.getClockChangedListener().onClockChanged(plugin);
+        // AND in the keyguard state
+        mStateListener.onStateChanged(StatusBarState.KEYGUARD);
         // WHEN the container is associated with the clock switch
         mKeyguardClockSwitch.setBigClockContainer(mBigClockContainer);
         // THEN the container is made visible.
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java
index 4e9d892..63b6673 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java
@@ -44,6 +44,7 @@
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
 import com.android.systemui.statusbar.phone.DozeParameters;
 import com.android.systemui.statusbar.phone.StatusBarWindowController;
+import com.android.systemui.statusbar.policy.ConfigurationController;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -66,6 +67,9 @@
     private IActivityManager mActivityManager;
     @Mock
     private DozeParameters mDozeParameters;
+    @Mock
+    private ConfigurationController mConfigurationController;
+
     private FrameLayout mStatusBarView;
     @Captor
     private ArgumentCaptor<NotificationEntryListener> mEntryListenerCaptor;
@@ -97,6 +101,7 @@
         mStatusBarView = new FrameLayout(mContext);
         mDependency.injectTestDependency(NotificationEntryManager.class, mNotificationEntryManager);
 
+
         // Bubbles get added to status bar window view
         mStatusBarWindowController = new StatusBarWindowController(mContext, mWindowManager,
                 mActivityManager, mDozeParameters);
@@ -115,7 +120,7 @@
 
         mBubbleData = new BubbleData();
         mBubbleController = new TestableBubbleController(mContext, mStatusBarWindowController,
-                mBubbleData);
+                mBubbleData, mConfigurationController);
         mBubbleController.setBubbleStateChangeListener(mBubbleStateChangeListener);
         mBubbleController.setExpandListener(mBubbleExpandListener);
 
@@ -331,8 +336,9 @@
     static class TestableBubbleController extends BubbleController {
         // Let's assume surfaces can be synchronized immediately.
         TestableBubbleController(Context context,
-                StatusBarWindowController statusBarWindowController, BubbleData data) {
-            super(context, statusBarWindowController, data, Runnable::run);
+                StatusBarWindowController statusBarWindowController, BubbleData data,
+                ConfigurationController configurationController) {
+            super(context, statusBarWindowController, data, Runnable::run, configurationController);
         }
 
         @Override
diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java
index 8941182..1ac6bef 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java
@@ -18,6 +18,7 @@
 
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
@@ -136,13 +137,14 @@
     @Test
     public void testOnSensor_whenDockedWithNearAndDoubleTapScreen_shouldWakeUp() {
         doReturn(true).when(mDockManagerFake).isDocked();
+        doReturn(true).when(mParameters).getDisplayNeedsBlanking();
         mSensors.getMockProximitySensor().sendProximityResult(false /* far */);
 
         mTriggers.onSensor(DozeLog.REASON_SENSOR_DOUBLE_TAP,
                 false /* sensorPerformedProxCheck */, 50 /* screenX */, 50 /* screenY */,
                 null /* rawValues */);
 
+        verify(mHost).setAodDimmingScrim(eq(255));
         verify(mMachine).wakeUp();
     }
-
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/SensorPrivacyTileTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/SensorPrivacyTileTest.java
deleted file mode 100644
index 6386c4c..0000000
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/SensorPrivacyTileTest.java
+++ /dev/null
@@ -1,119 +0,0 @@
-/*
- * Copyright (C) 2018 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.qs.tiles;
-
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import android.hardware.SensorPrivacyManager;
-import android.testing.AndroidTestingRunner;
-import android.testing.TestableLooper;
-
-import androidx.test.filters.SmallTest;
-
-import com.android.systemui.Dependency;
-import com.android.systemui.SysuiTestCase;
-import com.android.systemui.plugins.ActivityStarter;
-import com.android.systemui.qs.QSTileHost;
-import com.android.systemui.statusbar.policy.KeyguardMonitor;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-
-@RunWith(AndroidTestingRunner.class)
-@TestableLooper.RunWithLooper
-@SmallTest
-public class SensorPrivacyTileTest extends SysuiTestCase {
-
-    @Mock
-    private KeyguardMonitor mKeyguard;
-    @Mock
-    private QSTileHost mHost;
-    @Mock
-    SensorPrivacyManager mSensorPrivacyManager;
-
-    private TestableLooper mTestableLooper;
-
-    private SensorPrivacyTile mSensorPrivacyTile;
-
-    @Before
-    public void setUp() throws Exception {
-        MockitoAnnotations.initMocks(this);
-
-        mTestableLooper = TestableLooper.get(this);
-        mDependency.injectTestDependency(Dependency.BG_LOOPER, mTestableLooper.getLooper());
-        mKeyguard = mDependency.injectMockDependency(KeyguardMonitor.class);
-
-        mSensorPrivacyManager = mDependency.injectMockDependency(SensorPrivacyManager.class);
-
-        when(mHost.getContext()).thenReturn(mContext);
-
-        mSensorPrivacyTile = new SensorPrivacyTile(mHost, mSensorPrivacyManager, mKeyguard,
-                mock(ActivityStarter.class));
-    }
-
-    @Test
-    public void testSensorPrivacyListenerAdded_handleListeningTrue() {
-        // To prevent access to privacy related features from apps with WRITE_SECURE_SETTINGS the
-        // sensor privacy state is not stored in Settings; to receive notification apps must add
-        // themselves as a listener with the SensorPrivacyManager. This test verifies when
-        // setListening is called with a value of true the tile adds itself as a listener.
-        mSensorPrivacyTile.handleSetListening(true);
-        mTestableLooper.processAllMessages();
-        verify(mSensorPrivacyManager).addSensorPrivacyListener(mSensorPrivacyTile);
-    }
-
-    @Test
-    public void testSensorPrivacyListenerRemoved_handleListeningFalse() {
-        // Similar to the test above verifies that the tile removes itself as a listener when
-        // setListening is called with a value of false.
-        mSensorPrivacyTile.handleSetListening(false);
-        mTestableLooper.processAllMessages();
-        verify(mSensorPrivacyManager).removeSensorPrivacyListener((mSensorPrivacyTile));
-    }
-
-    @Test
-    public void testSensorPrivacyEnabled_handleClick() {
-        // Verifies when the SensorPrivacy tile is clicked it invokes the SensorPrivacyManager to
-        // set sensor privacy.
-        mSensorPrivacyTile.getState().value = false;
-        mSensorPrivacyTile.handleClick();
-        mTestableLooper.processAllMessages();
-        verify(mSensorPrivacyManager).setSensorPrivacy(true);
-
-        mSensorPrivacyTile.getState().value = true;
-        mSensorPrivacyTile.handleClick();
-        mTestableLooper.processAllMessages();
-        verify(mSensorPrivacyManager).setSensorPrivacy(false);
-    }
-
-    @Test
-    public void testSensorPrivacyNotDisabled_keyguard() {
-        // Verifies when the device is locked that sensor privacy cannot be disabled
-        when(mKeyguard.isSecure()).thenReturn(true);
-        when(mKeyguard.isShowing()).thenReturn(true);
-        mSensorPrivacyTile.getState().value = true;
-        mSensorPrivacyTile.handleClick();
-        mTestableLooper.processAllMessages();
-        verify(mSensorPrivacyManager, never()).setSensorPrivacy(false);
-    }
-}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java
index dd26368..c2f55e2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java
@@ -41,6 +41,7 @@
 
     private CommandQueue mCommandQueue;
     private Callbacks mCallbacks;
+    private static final int SECONDARY_DISPLAY = 1;
 
     @Before
     public void setup() {
@@ -68,7 +69,6 @@
         verify(mCallbacks).removeIcon(eq(slot));
     }
 
-    // TODO(b/117478341): add test case for multi-display
     @Test
     public void testDisable() {
         int state1 = 14;
@@ -79,6 +79,15 @@
     }
 
     @Test
+    public void testDisableForSecondaryDisplay() {
+        int state1 = 14;
+        int state2 = 42;
+        mCommandQueue.disable(SECONDARY_DISPLAY, state1, state2);
+        waitForIdleSync();
+        verify(mCallbacks).disable(eq(SECONDARY_DISPLAY), eq(state1), eq(state2), eq(true));
+    }
+
+    @Test
     public void testExpandNotifications() {
         mCommandQueue.animateExpandNotificationsPanel();
         waitForIdleSync();
@@ -100,7 +109,6 @@
         verify(mCallbacks).animateExpandSettingsPanel(eq(panel));
     }
 
-    // TODO(b/117478341): add test case for multi-display
     @Test
     public void testSetSystemUiVisibility() {
         Rect r = new Rect();
@@ -110,7 +118,15 @@
                 eq(null), eq(r));
     }
 
-    // TODO(b/117478341): add test case for multi-display
+    @Test
+    public void testSetSystemUiVisibilityForSecondaryDisplay() {
+        Rect r = new Rect();
+        mCommandQueue.setSystemUiVisibility(SECONDARY_DISPLAY, 1, 2, 3, 4, null, r);
+        waitForIdleSync();
+        verify(mCallbacks).setSystemUiVisibility(eq(SECONDARY_DISPLAY), eq(1), eq(2), eq(3), eq(4),
+                eq(null), eq(r));
+    }
+
     @Test
     public void testTopAppWindowChanged() {
         mCommandQueue.topAppWindowChanged(DEFAULT_DISPLAY, true);
@@ -118,7 +134,13 @@
         verify(mCallbacks).topAppWindowChanged(eq(DEFAULT_DISPLAY), eq(true));
     }
 
-    // TODO(b/117478341): add test case for multi-display
+    @Test
+    public void testTopAppWindowChangedForSecondaryDisplay() {
+        mCommandQueue.topAppWindowChanged(SECONDARY_DISPLAY, true);
+        waitForIdleSync();
+        verify(mCallbacks).topAppWindowChanged(eq(SECONDARY_DISPLAY), eq(true));
+    }
+
     @Test
     public void testShowImeButton() {
         mCommandQueue.setImeWindowStatus(DEFAULT_DISPLAY, null, 1, 2, true);
@@ -128,6 +150,14 @@
     }
 
     @Test
+    public void testShowImeButtonForSecondaryDisplay() {
+        mCommandQueue.setImeWindowStatus(SECONDARY_DISPLAY, null, 1, 2, true);
+        waitForIdleSync();
+        verify(mCallbacks).setImeWindowStatus(
+                eq(SECONDARY_DISPLAY), eq(null), eq(1), eq(2), eq(true));
+    }
+
+    @Test
     public void testShowRecentApps() {
         mCommandQueue.showRecentApps(true);
         waitForIdleSync();
@@ -176,7 +206,6 @@
         verify(mCallbacks).toggleKeyboardShortcutsMenu(eq(1));
     }
 
-    // TODO(b/117478341): add test case for multi-display
     @Test
     public void testSetWindowState() {
         mCommandQueue.setWindowState(DEFAULT_DISPLAY, 1, 2);
@@ -185,13 +214,19 @@
     }
 
     @Test
+    public void testSetWindowStateForSecondaryDisplay() {
+        mCommandQueue.setWindowState(SECONDARY_DISPLAY, 1, 2);
+        waitForIdleSync();
+        verify(mCallbacks).setWindowState(eq(SECONDARY_DISPLAY), eq(1), eq(2));
+    }
+
+    @Test
     public void testScreenPinRequest() {
         mCommandQueue.showScreenPinningRequest(1);
         waitForIdleSync();
         verify(mCallbacks).showScreenPinningRequest(eq(1));
     }
 
-    // TODO(b/117478341): add test case for multi-display
     @Test
     public void testAppTransitionPending() {
         mCommandQueue.appTransitionPending(DEFAULT_DISPLAY);
@@ -199,7 +234,13 @@
         verify(mCallbacks).appTransitionPending(eq(DEFAULT_DISPLAY), eq(false));
     }
 
-    // TODO(b/117478341): add test case for multi-display
+    @Test
+    public void testAppTransitionPendingForSecondaryDisplay() {
+        mCommandQueue.appTransitionPending(SECONDARY_DISPLAY);
+        waitForIdleSync();
+        verify(mCallbacks).appTransitionPending(eq(SECONDARY_DISPLAY), eq(false));
+    }
+
     @Test
     public void testAppTransitionCancelled() {
         mCommandQueue.appTransitionCancelled(DEFAULT_DISPLAY);
@@ -207,7 +248,13 @@
         verify(mCallbacks).appTransitionCancelled(eq(DEFAULT_DISPLAY));
     }
 
-    // TODO(b/117478341): add test case for multi-display
+    @Test
+    public void testAppTransitionCancelledForSecondaryDisplay() {
+        mCommandQueue.appTransitionCancelled(SECONDARY_DISPLAY);
+        waitForIdleSync();
+        verify(mCallbacks).appTransitionCancelled(eq(SECONDARY_DISPLAY));
+    }
+
     @Test
     public void testAppTransitionStarting() {
         mCommandQueue.appTransitionStarting(DEFAULT_DISPLAY, 1, 2);
@@ -216,7 +263,14 @@
                 eq(DEFAULT_DISPLAY), eq(1L), eq(2L), eq(false));
     }
 
-    // TODO(b/117478341): add test case for multi-display
+    @Test
+    public void testAppTransitionStartingForSecondaryDisplay() {
+        mCommandQueue.appTransitionStarting(SECONDARY_DISPLAY, 1, 2);
+        waitForIdleSync();
+        verify(mCallbacks).appTransitionStarting(
+                eq(SECONDARY_DISPLAY), eq(1L), eq(2L), eq(false));
+    }
+
     @Test
     public void testAppTransitionFinished() {
         mCommandQueue.appTransitionFinished(DEFAULT_DISPLAY);
@@ -225,6 +279,13 @@
     }
 
     @Test
+    public void testAppTransitionFinishedForSecondaryDisplay() {
+        mCommandQueue.appTransitionFinished(SECONDARY_DISPLAY);
+        waitForIdleSync();
+        verify(mCallbacks).appTransitionFinished(eq(SECONDARY_DISPLAY));
+    }
+
+    @Test
     public void testAssistDisclosure() {
         mCommandQueue.showAssistDisclosure();
         waitForIdleSync();
@@ -290,4 +351,25 @@
         waitForIdleSync();
         verify(mCallbacks).handleSystemKey(eq(1));
     }
+
+    @Test
+    public void testOnDisplayReady() {
+        mCommandQueue.onDisplayReady(DEFAULT_DISPLAY);
+        waitForIdleSync();
+        verify(mCallbacks).onDisplayReady(eq(DEFAULT_DISPLAY));
+    }
+
+    @Test
+    public void testOnDisplayReadyForSecondaryDisplay() {
+        mCommandQueue.onDisplayReady(SECONDARY_DISPLAY);
+        waitForIdleSync();
+        verify(mCallbacks).onDisplayReady(eq(SECONDARY_DISPLAY));
+    }
+
+    @Test
+    public void testOnDisplayRemoved() {
+        mCommandQueue.onDisplayRemoved(SECONDARY_DISPLAY);
+        waitForIdleSync();
+        verify(mCallbacks).onDisplayRemoved(eq(SECONDARY_DISPLAY));
+    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NavigationBarControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NavigationBarControllerTest.java
new file mode 100644
index 0000000..34a726d
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NavigationBarControllerTest.java
@@ -0,0 +1,243 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar;
+
+import static android.view.Display.DEFAULT_DISPLAY;
+import static android.view.Display.INVALID_DISPLAY;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyLong;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.hardware.display.DisplayManager;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper.RunWithLooper;
+import android.util.SparseArray;
+import android.view.Display;
+import android.view.WindowManager;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.systemui.Dependency;
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.statusbar.phone.NavigationBarFragment;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/** atest NavigationBarControllerTest */
+@RunWith(AndroidTestingRunner.class)
+@RunWithLooper
+@SmallTest
+public class NavigationBarControllerTest extends SysuiTestCase {
+
+    private NavigationBarController mNavigationBarController;
+    private Display mDisplay;
+    private NavigationBarFragment mDefaultNavBar;
+    private NavigationBarFragment mSecondaryNavBar;
+
+    private static final int SECONDARY_DISPLAY = 1;
+
+    @Before
+    public void setUp() {
+        mContext.putComponent(CommandQueue.class, mock(CommandQueue.class));
+        mNavigationBarController = spy(
+                new NavigationBarController(mContext, Dependency.get(Dependency.MAIN_HANDLER)));
+        initializeNavigationBars();
+    }
+
+    private void initializeNavigationBars() {
+        mNavigationBarController.mNavigationBars = mock(SparseArray.class);
+        mDefaultNavBar = mock(NavigationBarFragment.class);
+        mDefaultNavBar.mDisplayId = DEFAULT_DISPLAY;
+        doReturn(mDefaultNavBar)
+                .when(mNavigationBarController.mNavigationBars).get(DEFAULT_DISPLAY);
+
+        mSecondaryNavBar = mock(NavigationBarFragment.class);
+        mSecondaryNavBar.mDisplayId = SECONDARY_DISPLAY;
+        doReturn(mSecondaryNavBar)
+                .when(mNavigationBarController.mNavigationBars).get(SECONDARY_DISPLAY);
+    }
+
+    @After
+    public void tearDown() {
+        mNavigationBarController = null;
+        mDisplay = null;
+        mDefaultNavBar = null;
+        mSecondaryNavBar = null;
+    }
+
+    @Test
+    public void testCreateNavigationBarsIncludeDefaultTrue() {
+        initializeDisplayManager();
+        doNothing().when(mNavigationBarController).createNavigationBar(any());
+
+        mNavigationBarController.createNavigationBars(true);
+
+        verify(mNavigationBarController).createNavigationBar(any(Display.class));
+    }
+
+    @Test
+    public void testCreateNavigationBarsIncludeDefaultFalse() {
+        initializeDisplayManager();
+        doNothing().when(mNavigationBarController).createNavigationBar(any());
+
+        mNavigationBarController.createNavigationBars(false);
+
+        verify(mNavigationBarController, never()).createNavigationBar(any());
+    }
+
+    private void initializeDisplayManager() {
+        DisplayManager displayManager = mock(DisplayManager.class);
+        mDisplay = mContext.getSystemService(WindowManager.class).getDefaultDisplay();
+        Display[] displays = {mDisplay};
+        when(displayManager.getDisplays()).thenReturn(displays);
+        mContext.addMockSystemService(Context.DISPLAY_SERVICE, displayManager);
+    }
+
+    // Tests if NPE occurs when call checkNavBarModes() with invalid display.
+    @Test
+    public void testCheckNavBarModesWithInvalidDisplay() {
+        mNavigationBarController.checkNavBarModes(INVALID_DISPLAY);
+    }
+
+    @Test
+    public void testCheckNavBarModesWithDefaultDisplay() {
+        doNothing().when(mDefaultNavBar).checkNavBarModes();
+
+        mNavigationBarController.checkNavBarModes(DEFAULT_DISPLAY);
+
+        verify(mDefaultNavBar).checkNavBarModes();
+    }
+
+    @Test
+    public void testCheckNavBarModesWithSecondaryDisplay() {
+        doNothing().when(mSecondaryNavBar).checkNavBarModes();
+
+        mNavigationBarController.checkNavBarModes(SECONDARY_DISPLAY);
+
+        verify(mSecondaryNavBar).checkNavBarModes();
+    }
+
+    // Tests if NPE occurs when call finishBarAnimations() with invalid display.
+    @Test
+    public void testFinishBarAnimationsWithInvalidDisplay() {
+        mNavigationBarController.finishBarAnimations(INVALID_DISPLAY);
+    }
+
+    @Test
+    public void testFinishBarAnimationsWithDefaultDisplay() {
+        doNothing().when(mDefaultNavBar).finishBarAnimations();
+
+        mNavigationBarController.finishBarAnimations(DEFAULT_DISPLAY);
+
+        verify(mDefaultNavBar).finishBarAnimations();
+    }
+
+    @Test
+    public void testFinishBarAnimationsWithSecondaryDisplay() {
+        doNothing().when(mSecondaryNavBar).finishBarAnimations();
+
+        mNavigationBarController.finishBarAnimations(SECONDARY_DISPLAY);
+
+        verify(mSecondaryNavBar).finishBarAnimations();
+    }
+
+    // Tests if NPE occurs when call touchAutoDim() with invalid display.
+    @Test
+    public void testTouchAutoDimWithInvalidDisplay() {
+        mNavigationBarController.touchAutoDim(INVALID_DISPLAY);
+    }
+
+    @Test
+    public void testTouchAutoDimWithDefaultDisplay() {
+        doNothing().when(mDefaultNavBar).touchAutoDim();
+
+        mNavigationBarController.touchAutoDim(DEFAULT_DISPLAY);
+
+        verify(mDefaultNavBar).touchAutoDim();
+    }
+
+    @Test
+    public void testTouchAutoDimWithSecondaryDisplay() {
+        doNothing().when(mSecondaryNavBar).touchAutoDim();
+
+        mNavigationBarController.touchAutoDim(SECONDARY_DISPLAY);
+
+        verify(mSecondaryNavBar).touchAutoDim();
+    }
+
+    // Tests if NPE occurs when call transitionTo() with invalid display.
+    @Test
+    public void testTransitionToWithInvalidDisplay() {
+        mNavigationBarController.transitionTo(INVALID_DISPLAY, 3, true);
+    }
+
+    @Test
+    public void testTransitionToWithDefaultDisplay() {
+        doNothing().when(mDefaultNavBar).transitionTo(anyInt(), anyBoolean());
+
+        mNavigationBarController.transitionTo(DEFAULT_DISPLAY, 3, true);
+
+        verify(mDefaultNavBar).transitionTo(eq(3), eq(true));
+    }
+
+    @Test
+    public void testTransitionToWithSecondaryDisplay() {
+        doNothing().when(mSecondaryNavBar).transitionTo(anyInt(), anyBoolean());
+
+        mNavigationBarController.transitionTo(SECONDARY_DISPLAY, 3, true);
+
+        verify(mSecondaryNavBar).transitionTo(eq(3), eq(true));
+    }
+
+    // Tests if NPE occurs when call disableAnimationsDuringHide() with invalid display.
+    @Test
+    public void testDisableAnimationsDuringHideWithInvalidDisplay() {
+        mNavigationBarController.disableAnimationsDuringHide(INVALID_DISPLAY, 500L);
+    }
+
+    @Test
+    public void testDisableAnimationsDuringHideWithDefaultDisplay() {
+        doNothing().when(mDefaultNavBar).disableAnimationsDuringHide(anyLong());
+
+        mNavigationBarController.disableAnimationsDuringHide(DEFAULT_DISPLAY, 500L);
+
+        verify(mDefaultNavBar).disableAnimationsDuringHide(eq(500L));
+    }
+
+    @Test
+    public void testDisableAnimationsDuringHideWithSecondaryDisplay() {
+        doNothing().when(mSecondaryNavBar).disableAnimationsDuringHide(anyLong());
+
+        mNavigationBarController.disableAnimationsDuringHide(SECONDARY_DISPLAY, 500L);
+
+        verify(mSecondaryNavBar).disableAnimationsDuringHide(eq(500L));
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationTestHelper.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationTestHelper.java
index de15505..5a1f24a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationTestHelper.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationTestHelper.java
@@ -313,7 +313,7 @@
                 .setIntent(bubbleIntent)
                 .setDeleteIntent(deleteIntent)
                 .setTitle("bubble title")
-                .setIcon(Icon.createWithResource(mContext, 1))
+                .setIcon(Icon.createWithResource(mContext, R.drawable.android))
                 .setDesiredHeight(314)
                 .build();
     }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/AutoHideControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/AutoHideControllerTest.java
new file mode 100644
index 0000000..1b34a75
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/AutoHideControllerTest.java
@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.phone;
+
+import static android.view.Display.DEFAULT_DISPLAY;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+import android.graphics.Rect;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper.RunWithLooper;
+import android.view.View;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.systemui.Dependency;
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.statusbar.CommandQueue;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/** atest AutoHideControllerTest */
+@RunWith(AndroidTestingRunner.class)
+@RunWithLooper
+@SmallTest
+public class AutoHideControllerTest extends SysuiTestCase {
+
+    private AutoHideController mAutoHideController;
+
+    private static final int FULL_MASK = 0xffffffff;
+
+    @Before
+    public void setUp() {
+        mContext.putComponent(CommandQueue.class, mock(CommandQueue.class));
+        mAutoHideController =
+                spy(new AutoHideController(mContext, Dependency.get(Dependency.MAIN_HANDLER)));
+        mAutoHideController.mDisplayId = DEFAULT_DISPLAY;
+        mAutoHideController.mSystemUiVisibility = View.VISIBLE;
+    }
+
+    @After
+    public void tearDown() {
+        mAutoHideController = null;
+    }
+
+    @Test
+    public void testSetSystemUiVisibilityEarlyReturnWithDifferentDisplay() {
+        mAutoHideController.setSystemUiVisibility(1, 1, 2, 3, 4, null, new Rect());
+
+        verify(mAutoHideController, never()).notifySystemUiVisibilityChanged(anyInt());
+    }
+
+    @Test
+    public void testSetSystemUiVisibilityEarlyReturnWithSameVisibility() {
+        mAutoHideController
+                .setSystemUiVisibility(DEFAULT_DISPLAY, View.VISIBLE, 2, 3, 4, null, new Rect());
+
+        verify(mAutoHideController, never()).notifySystemUiVisibilityChanged(anyInt());
+    }
+
+    // Test if status bar unhide status doesn't change without status bar.
+    @Test
+    public void testSetSystemUiVisibilityWithoutStatusBar() {
+        doReturn(false).when(mAutoHideController).hasStatusBar();
+        int expectedStatus = View.STATUS_BAR_UNHIDE;
+        mAutoHideController.mSystemUiVisibility =
+                View.SYSTEM_UI_FLAG_FULLSCREEN | View.STATUS_BAR_UNHIDE;
+
+        mAutoHideController.setSystemUiVisibility(
+                DEFAULT_DISPLAY, expectedStatus, 2, 3, FULL_MASK, null, new Rect());
+
+        assertEquals("System UI visibility should not be changed",
+                expectedStatus, mAutoHideController.mSystemUiVisibility);
+        verify(mAutoHideController, times(1)).notifySystemUiVisibilityChanged(eq(expectedStatus));
+    }
+
+    @Test
+    public void testSetSystemUiVisibilityWithVisChanged() {
+        doReturn(true).when(mAutoHideController).hasStatusBar();
+        doReturn(true).when(mAutoHideController).hasNavigationBar();
+        mAutoHideController.mSystemUiVisibility = View.SYSTEM_UI_FLAG_FULLSCREEN
+                | View.STATUS_BAR_UNHIDE
+                | View.NAVIGATION_BAR_UNHIDE;
+
+        mAutoHideController.setSystemUiVisibility(
+                DEFAULT_DISPLAY, View.STATUS_BAR_UNHIDE | View.NAVIGATION_BAR_UNHIDE,
+                2, 3, FULL_MASK, null, new Rect());
+
+        int expectedStatus = View.VISIBLE;
+        assertEquals(expectedStatus, mAutoHideController.mSystemUiVisibility);
+        verify(mAutoHideController).notifySystemUiVisibilityChanged(eq(expectedStatus));
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java
index db8357a..6889c57 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java
@@ -71,7 +71,7 @@
         mDependency.injectMockDependency(ConfigurationController.class);
         mDependency.injectMockDependency(ZenModeController.class);
         NotificationWakeUpCoordinator coordinator =
-                new NotificationWakeUpCoordinator(
+                new NotificationWakeUpCoordinator(mContext,
                         new AmbientPulseManager(mContext),
                         new StatusBarStateControllerImpl());
         PulseExpansionHandler expansionHandler = new PulseExpansionHandler(mContext, coordinator);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
index 1ded6c9..5f7f422 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
@@ -29,6 +29,7 @@
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.clearInvocations;
 import static org.mockito.Mockito.doAnswer;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
@@ -75,7 +76,6 @@
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.UiOffloadThread;
 import com.android.systemui.appops.AppOpsController;
-import com.android.systemui.appops.AppOpsControllerImpl;
 import com.android.systemui.assist.AssistManager;
 import com.android.systemui.bubbles.BubbleController;
 import com.android.systemui.classifier.FalsingManager;
@@ -112,7 +112,6 @@
 import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout;
 import com.android.systemui.statusbar.policy.DeviceProvisionedController;
 import com.android.systemui.statusbar.policy.KeyguardMonitor;
-import com.android.systemui.statusbar.policy.KeyguardMonitorImpl;
 import com.android.systemui.statusbar.policy.UserSwitcherController;
 
 import org.junit.Before;
@@ -161,7 +160,6 @@
     @Mock private NotificationPresenter mNotificationPresenter;
     @Mock
     private NotificationEntryListener mEntryListener;
-    @Mock private BubbleController mBubbleController;
     @Mock
     private NotificationFilter mNotificationFilter;
     @Mock
@@ -192,8 +190,8 @@
                 mViewHierarchyManager);
         mDependency.injectTestDependency(VisualStabilityManager.class, mVisualStabilityManager);
         mDependency.injectTestDependency(NotificationListener.class, mNotificationListener);
-        mDependency.injectTestDependency(KeyguardMonitor.class, mock(KeyguardMonitorImpl.class));
-        mDependency.injectTestDependency(AppOpsController.class, mock(AppOpsControllerImpl.class));
+        mDependency.injectTestDependency(KeyguardMonitor.class, mock(KeyguardMonitor.class));
+        mDependency.injectTestDependency(AppOpsController.class, mock(AppOpsController.class));
         mDependency.injectTestDependency(StatusBarStateController.class, mStatusBarStateController);
         mDependency.injectTestDependency(DeviceProvisionedController.class,
                 mDeviceProvisionedController);
@@ -722,12 +720,25 @@
     public void testOnStartedWakingUp_isNotDozing() {
         mStatusBar.setBarStateForTest(StatusBarState.KEYGUARD);
         when(mStatusBarStateController.isKeyguardRequested()).thenReturn(true);
-
         mStatusBar.mDozeServiceHost.startDozing();
         verify(mStatusBarStateController).setIsDozing(eq(true));
+        clearInvocations(mNotificationPanelView);
 
         mStatusBar.mWakefulnessObserver.onStartedWakingUp();
         verify(mStatusBarStateController).setIsDozing(eq(false));
+        verify(mNotificationPanelView).expand(eq(false));
+    }
+
+    @Test
+    public void testOnStartedWakingUp_doesNotDismissBouncer_whenPulsing() {
+        mStatusBar.setBarStateForTest(StatusBarState.KEYGUARD);
+        when(mStatusBarStateController.isKeyguardRequested()).thenReturn(true);
+        mStatusBar.mDozeServiceHost.startDozing();
+        clearInvocations(mNotificationPanelView);
+
+        mStatusBar.setBouncerShowing(true);
+        mStatusBar.mWakefulnessObserver.onStartedWakingUp();
+        verify(mNotificationPanelView, never()).expand(anyBoolean());
     }
 
     static class TestableStatusBar extends StatusBar {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java
index c1f8885..5cafc02 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java
@@ -45,11 +45,13 @@
 import android.telephony.SubscriptionManager;
 import android.telephony.TelephonyManager;
 import android.testing.TestableLooper;
+import android.testing.TestableResources;
 import android.util.Log;
 
 import com.android.internal.telephony.cdma.EriInfo;
 import com.android.settingslib.graph.SignalDrawable;
 import com.android.settingslib.net.DataUsageController;
+import com.android.systemui.R;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.statusbar.policy.DeviceProvisionedController.DeviceProvisionedListener;
 import com.android.systemui.statusbar.policy.NetworkController.IconState;
@@ -76,6 +78,8 @@
     protected static final int DEFAULT_QS_SIGNAL_STRENGTH = DEFAULT_LEVEL;
     protected static final int DEFAULT_ICON = TelephonyIcons.ICON_3G;
     protected static final int DEFAULT_QS_ICON = TelephonyIcons.ICON_3G;
+    protected static final String NO_DATA_STRING = "Data disabled";
+    protected static final String NOT_DEFAULT_DATA_STRING = "Not default data";
 
     protected NetworkControllerImpl mNetworkController;
     protected MobileSignalController mMobileSignalController;
@@ -113,6 +117,10 @@
     @Before
     public void setUp() throws Exception {
         Settings.Global.putInt(mContext.getContentResolver(), Global.AIRPLANE_MODE_ON, 0);
+        TestableResources res = mContext.getOrCreateTestableResources();
+        res.addOverride(R.string.cell_data_off_content_description, NO_DATA_STRING);
+        res.addOverride(R.string.not_default_data_content_description, NOT_DEFAULT_DATA_STRING);
+
         mMockWm = mock(WifiManager.class);
         mMockTm = mock(TelephonyManager.class);
         mMockSm = mock(SubscriptionManager.class);
@@ -392,12 +400,21 @@
     protected void verifyLastMobileDataIndicators(boolean visible, int icon, int typeIcon,
             boolean qsVisible, int qsIcon, int qsTypeIcon, boolean dataIn, boolean dataOut,
             boolean cutOut) {
+        verifyLastMobileDataIndicators(
+                visible, icon, typeIcon, qsVisible, qsIcon, qsTypeIcon, dataIn, dataOut, cutOut,
+                null);
+    }
+
+    protected void verifyLastMobileDataIndicators(boolean visible, int icon, int typeIcon,
+            boolean qsVisible, int qsIcon, int qsTypeIcon, boolean dataIn, boolean dataOut,
+            boolean cutOut, String typeContentDescription) {
         ArgumentCaptor<IconState> iconArg = ArgumentCaptor.forClass(IconState.class);
         ArgumentCaptor<Integer> typeIconArg = ArgumentCaptor.forClass(Integer.class);
         ArgumentCaptor<IconState> qsIconArg = ArgumentCaptor.forClass(IconState.class);
         ArgumentCaptor<Integer> qsTypeIconArg = ArgumentCaptor.forClass(Integer.class);
         ArgumentCaptor<Boolean> dataInArg = ArgumentCaptor.forClass(Boolean.class);
         ArgumentCaptor<Boolean> dataOutArg = ArgumentCaptor.forClass(Boolean.class);
+        ArgumentCaptor<String> typeContentDescriptionArg = ArgumentCaptor.forClass(String.class);
 
         Mockito.verify(mCallbackHandler, Mockito.atLeastOnce()).setMobileDataIndicators(
                 iconArg.capture(),
@@ -406,7 +423,8 @@
                 qsTypeIconArg.capture(),
                 dataInArg.capture(),
                 dataOutArg.capture(),
-                anyString(), anyString(), anyBoolean(), anyInt(), anyBoolean());
+                typeContentDescriptionArg.capture(),
+                anyString(), anyBoolean(), anyInt(), anyBoolean());
 
         IconState iconState = iconArg.getValue();
 
@@ -424,6 +442,10 @@
                 (boolean) dataInArg.getValue());
         assertEquals("Data direction out in quick settings", dataOut,
                 (boolean) dataOutArg.getValue());
+        if (typeContentDescription != null) { // Only check if it was provided
+            assertEquals("Type content description", typeContentDescription,
+                    typeContentDescriptionArg.getValue());
+        }
     }
 
    protected void assertNetworkNameEquals(String expected) {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerDataTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerDataTest.java
index 5786796..68323c9 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerDataTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerDataTest.java
@@ -117,7 +117,7 @@
     }
 
     @Test
-    public void testNoInternetIcon() {
+    public void testNoInternetIcon_withDefaultSub() {
         setupNetworkController();
         when(mMockTm.getDataEnabled(mSubId)).thenReturn(false);
         setupDefaultSignal();
@@ -127,11 +127,11 @@
         // Verify that a SignalDrawable with a cut out is used to display data disabled.
         verifyLastMobileDataIndicators(true, DEFAULT_SIGNAL_STRENGTH, 0,
                 true, DEFAULT_QS_SIGNAL_STRENGTH, 0, false,
-                false, true);
+                false, true, NO_DATA_STRING);
     }
 
     @Test
-    public void testDataDisabledIcon() {
+    public void testDataDisabledIcon_withDefaultSub() {
         setupNetworkController();
         when(mMockTm.getDataEnabled(mSubId)).thenReturn(false);
         setupDefaultSignal();
@@ -141,7 +141,37 @@
         // Verify that a SignalDrawable with a cut out is used to display data disabled.
         verifyLastMobileDataIndicators(true, DEFAULT_SIGNAL_STRENGTH, 0,
                 true, DEFAULT_QS_SIGNAL_STRENGTH, 0, false,
-                false, true);
+                false, true, NO_DATA_STRING);
+    }
+
+    @Test
+    public void testNoInternetIcon_withoutDefaultSub() {
+        setupNetworkController();
+        when(mMockTm.getDataEnabled(mSubId)).thenReturn(false);
+        setupDefaultSignal();
+        setDefaultSubId(mSubId + 1);
+        updateDataConnectionState(TelephonyManager.DATA_CONNECTED, 0);
+        setConnectivityViaBroadcast(NetworkCapabilities.TRANSPORT_CELLULAR, false, false);
+
+        // Verify that a SignalDrawable with a cut out is used to display data disabled.
+        verifyLastMobileDataIndicators(true, DEFAULT_SIGNAL_STRENGTH, 0,
+                true, DEFAULT_QS_SIGNAL_STRENGTH, 0, false,
+                false, true, NOT_DEFAULT_DATA_STRING);
+    }
+
+    @Test
+    public void testDataDisabledIcon_withoutDefaultSub() {
+        setupNetworkController();
+        when(mMockTm.getDataEnabled(mSubId)).thenReturn(false);
+        setupDefaultSignal();
+        setDefaultSubId(mSubId + 1);
+        updateDataConnectionState(TelephonyManager.DATA_DISCONNECTED, 0);
+        setConnectivityViaBroadcast(NetworkCapabilities.TRANSPORT_CELLULAR, false, false);
+
+        // Verify that a SignalDrawable with a cut out is used to display data disabled.
+        verifyLastMobileDataIndicators(true, DEFAULT_SIGNAL_STRENGTH, 0,
+                true, DEFAULT_QS_SIGNAL_STRENGTH, 0, false,
+                false, true, NOT_DEFAULT_DATA_STRING);
     }
 
     @Test
@@ -151,7 +181,7 @@
         updateDataConnectionState(TelephonyManager.DATA_CONNECTED,
                 TelephonyManager.NETWORK_TYPE_LTE);
         ServiceState ss = Mockito.mock(ServiceState.class);
-        doReturn(NetworkRegistrationInfo.NR_STATUS_CONNECTED).when(ss).getNrStatus();
+        doReturn(NetworkRegistrationInfo.NR_STATE_CONNECTED).when(ss).getNrState();
         doReturn(ServiceState.FREQUENCY_RANGE_HIGH).when(ss).getNrFrequencyRange();
         mPhoneStateListener.onServiceStateChanged(ss);
 
@@ -165,7 +195,7 @@
         updateDataConnectionState(TelephonyManager.DATA_CONNECTED,
                 TelephonyManager.NETWORK_TYPE_LTE);
         ServiceState ss = Mockito.mock(ServiceState.class);
-        doReturn(NetworkRegistrationInfo.NR_STATUS_CONNECTED).when(ss).getNrStatus();
+        doReturn(NetworkRegistrationInfo.NR_STATE_CONNECTED).when(ss).getNrState();
         doReturn(ServiceState.FREQUENCY_RANGE_MMWAVE).when(ss).getNrFrequencyRange();
         mPhoneStateListener.onServiceStateChanged(ss);
 
@@ -179,7 +209,7 @@
         updateDataConnectionState(TelephonyManager.DATA_CONNECTED,
                 TelephonyManager.NETWORK_TYPE_LTE);
         ServiceState ss = Mockito.mock(ServiceState.class);
-        doReturn(NetworkRegistrationInfo.NR_STATUS_RESTRICTED).when(ss).getNrStatus();
+        doReturn(NetworkRegistrationInfo.NR_STATE_RESTRICTED).when(ss).getNrState();
         mPhoneStateListener.onServiceStateChanged(mServiceState);
 
         verifyDataIndicators(TelephonyIcons.ICON_LTE);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogImplTest.java
index 617c17e..f3cdbf7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogImplTest.java
@@ -118,6 +118,17 @@
     }
 
     @Test
+    public void testComputeTimeout_tooltip() {
+        Mockito.reset(mAccessibilityMgr);
+        mDialog.showCaptionsTooltip();
+        verify(mAccessibilityMgr).getRecommendedTimeoutMillis(
+                VolumeDialogImpl.DIALOG_ODI_CAPTIONS_TOOLTIP_TIMEOUT_MILLIS,
+                AccessibilityManager.FLAG_CONTENT_CONTROLS
+                | AccessibilityManager.FLAG_CONTENT_TEXT);
+    }
+
+
+    @Test
     public void testComputeTimeout_withHovering() {
         Mockito.reset(mAccessibilityMgr);
         View dialog = mDialog.getDialogView();
@@ -146,6 +157,16 @@
                         | AccessibilityManager.FLAG_CONTENT_CONTROLS);
     }
 
+    @Test
+    public void testComputeTimeout_standard() {
+        Mockito.reset(mAccessibilityMgr);
+        mDialog.tryToRemoveCaptionsTooltip();
+        mDialog.rescheduleTimeoutH();
+        verify(mAccessibilityMgr).getRecommendedTimeoutMillis(
+                VolumeDialogImpl.DIALOG_TIMEOUT_MILLIS,
+                AccessibilityManager.FLAG_CONTENT_CONTROLS);
+    }
+
 /*
     @Test
     public void testContentDescriptions() {
diff --git a/proto/src/metrics_constants/metrics_constants.proto b/proto/src/metrics_constants/metrics_constants.proto
index f106228..7447331 100644
--- a/proto/src/metrics_constants/metrics_constants.proto
+++ b/proto/src/metrics_constants/metrics_constants.proto
@@ -7120,6 +7120,24 @@
     // Open: Settings > Special App Access > Do not disturb control for app
     ZEN_ACCESS_DETAIL = 1692;
 
+    // OPEN: Settings > Face > Remove face
+    // OS: Q
+    DIALOG_FACE_REMOVE = 1693;
+
+    // FIELD - Detailed reason in screen wake. One of WAKE_REASON_* in PowerManager.
+    // OS: Q
+    FIELD_SCREEN_WAKE_REASON = 1694;
+
+    // FIELD - Detailed reason in screen sleep. One of GO_TO_SLEEP_REASON_* in PowerManager.
+    // OS: Q
+    FIELD_SCREEN_SLEEP_REASON = 1695;
+
+    // UPDATE: The screen changed policy
+    //   SUBTYPE: The applied policy. One of the DISPLAY_POLICY_* constants in
+    //   DisplayManagerInternal.
+    // OS: Q
+    DISPLAY_POLICY = 1696;
+
     // ---- End Q Constants, all Q constants go above this line ----
     // Add new aosp constants above this line.
     // END OF AOSP CONSTANTS
diff --git a/proto/src/wifi.proto b/proto/src/wifi.proto
index 0d17f22..1bcc888 100644
--- a/proto/src/wifi.proto
+++ b/proto/src/wifi.proto
@@ -1880,6 +1880,33 @@
     PROBE_STATUS_FAILURE = 3;
   }
 
+  // Codes for cellular data network type
+  enum CellularDataNetworkType {
+    // Unknown network
+    NETWORK_TYPE_UNKNOWN = 0;
+
+    // GSM network
+    NETWORK_TYPE_GSM = 1;
+
+    // CDMA network
+    NETWORK_TYPE_CDMA = 2;
+
+    // CDMA EVDO network
+    NETWORK_TYPE_EVDO_0 = 3;
+
+    // WCDMA network
+    NETWORK_TYPE_UMTS = 4;
+
+    // TDSCDMA network
+    NETWORK_TYPE_TD_SCDMA = 5;
+
+    // LTE network
+    NETWORK_TYPE_LTE = 6;
+
+    // NR network
+    NETWORK_TYPE_NR = 7;
+  }
+
   // Absolute milliseconds from device boot when these stats were sampled
   optional int64 time_stamp_ms = 1;
 
@@ -1971,6 +1998,20 @@
   // Whether current entry is for the same BSSID on the same frequency compared
   // to last entry
   optional bool is_same_bssid_and_freq = 29;
+
+  // Cellular data network type currently in use on the device for data transmission
+  optional CellularDataNetworkType cellular_data_network_type = 30;
+
+  // Cellular signal strength in dBm, NR: CsiRsrp, LTE: Rsrp, WCDMA/TDSCDMA: Rscp,
+  // CDMA: Rssi, EVDO: Rssi, GSM: Rssi
+  optional int32 cellular_signal_strength_dbm = 31;
+
+  // Cellular signal strength in dB, NR: CsiSinr, LTE: Rsrq, WCDMA: EcNo, TDSCDMA: invalid,
+  // CDMA: Ecio, EVDO: SNR, GSM: invalid */
+  optional int32 cellular_signal_strength_db = 32;
+
+  // Whether the primary registered cell of current entry is same as that of previous entry
+  optional bool is_same_registered_cell = 33;
 }
 
 message WifiUsabilityStats {
diff --git a/services/Android.bp b/services/Android.bp
index 31385ed..567efac 100644
--- a/services/Android.bp
+++ b/services/Android.bp
@@ -26,7 +26,6 @@
         "services.contentsuggestions",
         "services.coverage",
         "services.devicepolicy",
-        "services.ipmemorystore",
         "services.midi",
         "services.net",
         "services.print",
diff --git a/services/accessibility/java/com/android/server/accessibility/TouchExplorer.java b/services/accessibility/java/com/android/server/accessibility/TouchExplorer.java
index 65e31f3..1e3f20e 100644
--- a/services/accessibility/java/com/android/server/accessibility/TouchExplorer.java
+++ b/services/accessibility/java/com/android/server/accessibility/TouchExplorer.java
@@ -809,13 +809,9 @@
 
         // Announce the end of the gesture recognition.
         sendAccessibilityEvent(AccessibilityEvent.TYPE_GESTURE_DETECTION_END);
+        // Don't announce the end of a the touch interaction if users didn't lift their fingers.
         if (interactionEnd) {
-            // Announce the end of a the touch interaction.
             sendAccessibilityEvent(AccessibilityEvent.TYPE_TOUCH_INTERACTION_END);
-        } else {
-            // If gesture detection is end, but user doesn't release the finger, announce the
-            // transition to exploration state.
-            sendAccessibilityEvent(AccessibilityEvent.TYPE_TOUCH_EXPLORATION_GESTURE_START);
         }
 
         mExitGestureDetectionModeDelayed.cancel();
@@ -1151,10 +1147,7 @@
         public void run() {
             // Announce the end of gesture recognition.
             sendAccessibilityEvent(AccessibilityEvent.TYPE_GESTURE_DETECTION_END);
-            // Clearing puts is in touch exploration state with a finger already
-            // down, so announce the transition to exploration state.
             clear();
-            sendAccessibilityEvent(AccessibilityEvent.TYPE_TOUCH_EXPLORATION_GESTURE_START);
         }
     }
 
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
index 6597312..c1c125d 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
@@ -569,6 +569,42 @@
         }
     }
 
+    // Called by Shell command
+    boolean isDefaultAugmentedServiceEnabled(@UserIdInt int userId) {
+        enforceCallingPermissionForManagement();
+
+        synchronized (mLock) {
+            final AutofillManagerServiceImpl service = getServiceForUserLocked(userId);
+            if (service != null) {
+                return service.mAugmentedAutofillResolver.isDefaultServiceEnabled(userId);
+            }
+        }
+        return false;
+    }
+
+    // Called by Shell command
+    boolean setDefaultAugmentedServiceEnabled(@UserIdInt int userId, boolean enabled) {
+        Slog.i(mTag, "setDefaultAugmentedServiceEnabled() for userId " + userId + ": " + enabled);
+        enforceCallingPermissionForManagement();
+
+        synchronized (mLock) {
+            final AutofillManagerServiceImpl service = getServiceForUserLocked(userId);
+            if (service != null) {
+                final boolean changed = service.mAugmentedAutofillResolver
+                        .setDefaultServiceEnabled(userId, enabled);
+                if (changed) {
+                    service.updateRemoteAugmentedAutofillService();
+                    return true;
+                } else {
+                    if (debug) {
+                        Slog.d(TAG, "setDefaultAugmentedServiceEnabled(): already " + enabled);
+                    }
+                }
+            }
+        }
+        return false;
+    }
+
     private void setLoggingLevelsLocked(boolean debug, boolean verbose) {
         com.android.server.autofill.Helper.sDebug = debug;
         android.view.autofill.Helper.sDebug = debug;
@@ -647,6 +683,14 @@
         send(receiver, value ? 1 : 0);
     }
 
+    private void send(@NonNull IResultReceiver receiver, int value1, int value2) {
+        try {
+            receiver.send(value1, SyncResultReceiver.bundleFor(value2));
+        } catch (RemoteException e) {
+            Slog.w(TAG, "Error async reporting result to client: " + e);
+        }
+    }
+
     @Nullable
     @VisibleForTesting
     static Map<String, String[]> getWhitelistedCompatModePackages(String setting) {
@@ -967,14 +1011,20 @@
             // TODO(b/113281366): add a callback method on AM to be notified when a task is finished
             // so we can clean up sessions kept alive
             final int taskId = mAm.getTaskIdForActivity(activityToken, false);
-            final int sessionId;
+            final long result;
             synchronized (mLock) {
                 final AutofillManagerServiceImpl service = getServiceForUserLocked(userId);
-                sessionId = service.startSessionLocked(activityToken, taskId, getCallingUid(),
+                result = service.startSessionLocked(activityToken, taskId, getCallingUid(),
                         appCallback, autofillId, bounds, value, hasCallback, componentName,
                         compatMode, mAllowInstantService, flags);
             }
-            send(receiver, sessionId);
+            final int sessionId = (int) result;
+            final int resultFlags = (int) (result >> 32);
+            if (resultFlags != 0) {
+                send(receiver, sessionId, resultFlags);
+            } else {
+                send(receiver, sessionId);
+            }
         }
 
         @Override
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
index 9612346..720d319 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
@@ -18,6 +18,7 @@
 
 import static android.service.autofill.FillRequest.FLAG_MANUAL_REQUEST;
 import static android.view.autofill.AutofillManager.ACTION_START_SESSION;
+import static android.view.autofill.AutofillManager.FLAG_SESSION_FOR_AUGMENTED_AUTOFILL_ONLY;
 import static android.view.autofill.AutofillManager.NO_SESSION;
 
 import static com.android.server.autofill.Helper.sDebug;
@@ -53,6 +54,7 @@
 import android.service.autofill.FieldClassification.Match;
 import android.service.autofill.FillEventHistory;
 import android.service.autofill.FillEventHistory.Event;
+import android.service.autofill.FillRequest;
 import android.service.autofill.FillResponse;
 import android.service.autofill.IAutoFillService;
 import android.service.autofill.UserData;
@@ -156,6 +158,7 @@
     /** When was {@link PruneTask} last executed? */
     private long mLastPrune = 0;
 
+    // TODO(b/128911469): move to AutofillManagerService
     /**
      * Object used to set the name of the augmented autofill service.
      */
@@ -221,7 +224,7 @@
                     session.removeSelfLocked();
                 }
             }
-            sendStateToClients(false);
+            sendStateToClients(/* resetClient= */ false);
         }
         updateRemoteAugmentedAutofillService();
         return enabledChanged;
@@ -278,8 +281,15 @@
         }
     }
 
+    /**
+     * Starts a new session.
+     *
+     * @return {@code long} whose right-most 32 bits represent the session id (which is always
+     * non-negative), and the left-most contains extra flags (currently either {@code 0} or
+     * {@link FillRequest#FLAG_SESSION_FOR_AUGMENTED_AUTOFILL_ONLY}).
+     */
     @GuardedBy("mLock")
-    int startSessionLocked(@NonNull IBinder activityToken, int taskId, int uid,
+    long startSessionLocked(@NonNull IBinder activityToken, int taskId, int uid,
             @NonNull IBinder appCallbackToken, @NonNull AutofillId autofillId,
             @NonNull Rect virtualBounds, @Nullable AutofillValue value, boolean hasCallback,
             @NonNull ComponentName componentName, boolean compatMode,
@@ -289,33 +299,48 @@
         }
 
         final String shortComponentName = componentName.toShortString();
+        boolean forAugmentedAutofillOnly = false;
 
         if (isAutofillDisabledLocked(componentName)) {
-            if (sDebug) {
-                Slog.d(TAG, "startSession(" + shortComponentName
-                        + "): ignored because disabled by service");
-            }
+            // Service disabled autofill; that means no session, unless the activity is whitelisted
+            // for augmented autofill
+            if (isWhitelistedForAugmentedAutofillLocked(componentName)) {
+                if (sDebug) {
+                    Slog.d(TAG, "startSession(" + shortComponentName + "): disabled by service but "
+                            + "whitelisted for augmented autofill");
+                }
+                forAugmentedAutofillOnly = true;
 
-            final IAutoFillManagerClient client = IAutoFillManagerClient.Stub
-                    .asInterface(appCallbackToken);
-            try {
-                client.setSessionFinished(AutofillManager.STATE_DISABLED_BY_SERVICE,
-                        /* autofillableIds= */ null);
-            } catch (RemoteException e) {
-                Slog.w(TAG, "Could not notify " + shortComponentName + " that it's disabled: " + e);
-            }
+            } else {
+                if (sDebug) {
+                    Slog.d(TAG, "startSession(" + shortComponentName + "): ignored because "
+                            + "disabled by service and not whitelisted for augmented autofill");
+                }
+                final IAutoFillManagerClient client = IAutoFillManagerClient.Stub
+                        .asInterface(appCallbackToken);
+                try {
+                    client.setSessionFinished(AutofillManager.STATE_DISABLED_BY_SERVICE,
+                            /* autofillableIds= */ null);
+                } catch (RemoteException e) {
+                    Slog.w(TAG,
+                            "Could not notify " + shortComponentName + " that it's disabled: " + e);
+                }
 
-            return NO_SESSION;
+                return NO_SESSION;
+            }
         }
 
-        if (sVerbose) Slog.v(TAG, "startSession(): token=" + activityToken + ", flags=" + flags);
+        if (sVerbose) {
+            Slog.v(TAG, "startSession(): token=" + activityToken + ", flags=" + flags
+                    + ", forAugmentedAutofillOnly=" + forAugmentedAutofillOnly);
+        }
 
         // Occasionally clean up abandoned sessions
         pruneAbandonedSessionsLocked();
 
         final Session newSession = createSessionByTokenLocked(activityToken, taskId, uid,
                 appCallbackToken, hasCallback, componentName, compatMode,
-                bindInstantServiceAllowed, flags);
+                bindInstantServiceAllowed, forAugmentedAutofillOnly, flags);
         if (newSession == null) {
             return NO_SESSION;
         }
@@ -324,12 +349,20 @@
                 "id=" + newSession.id + " uid=" + uid + " a=" + shortComponentName
                 + " s=" + mInfo.getServiceInfo().packageName
                 + " u=" + mUserId + " i=" + autofillId + " b=" + virtualBounds
-                + " hc=" + hasCallback + " f=" + flags;
+                + " hc=" + hasCallback + " f=" + flags + " aa=" + forAugmentedAutofillOnly;
         mMaster.logRequestLocked(historyItem);
 
         newSession.updateLocked(autofillId, virtualBounds, value, ACTION_START_SESSION, flags);
 
-        return newSession.id;
+        if (forAugmentedAutofillOnly) {
+            // Must embed the flag in the response, at the high-end side of the long.
+            // (session is always positive, so we don't have to worry about the signal bit)
+            final long extraFlags = ((long) FLAG_SESSION_FOR_AUGMENTED_AUTOFILL_ONLY) << 32;
+            final long result = extraFlags | newSession.id;
+            return result;
+        } else {
+            return newSession.id;
+        }
     }
 
     /**
@@ -435,7 +468,7 @@
     private Session createSessionByTokenLocked(@NonNull IBinder activityToken, int taskId, int uid,
             @NonNull IBinder appCallbackToken, boolean hasCallback,
             @NonNull ComponentName componentName, boolean compatMode,
-            boolean bindInstantServiceAllowed, int flags) {
+            boolean bindInstantServiceAllowed, boolean forAugmentedAutofillOnly, int flags) {
         // use random ids so that one app cannot know that another app creates sessions
         int sessionId;
         int tries = 0;
@@ -446,15 +479,17 @@
                 return null;
             }
 
-            sessionId = sRandom.nextInt();
-        } while (sessionId == NO_SESSION || mSessions.indexOfKey(sessionId) >= 0);
+            sessionId = Math.abs(sRandom.nextInt());
+        } while (sessionId == 0 || sessionId == NO_SESSION
+                || mSessions.indexOfKey(sessionId) >= 0);
 
         assertCallerLocked(componentName, compatMode);
 
         final Session newSession = new Session(this, mUi, getContext(), mHandler, mUserId, mLock,
                 sessionId, taskId, uid, activityToken, appCallbackToken, hasCallback,
                 mUiLatencyHistory, mWtfHistory, mInfo.getServiceInfo().getComponentName(),
-                componentName, compatMode, bindInstantServiceAllowed, flags);
+                componentName, compatMode, bindInstantServiceAllowed, forAugmentedAutofillOnly,
+                flags);
         mSessions.put(newSession.id, newSession);
 
         return newSession;
@@ -634,7 +669,7 @@
             remoteFillServices.valueAt(i).destroy();
         }
 
-        sendStateToClients(true);
+        sendStateToClients(/* resetclient=*/ true);
         if (mClients != null) {
             mClients.kill();
             mClients = null;
@@ -889,8 +924,6 @@
         } else {
             pw.println();
             mInfo.dump(prefix2, pw);
-            pw.print(prefix); pw.print("Service Label: "); pw.println(getServiceLabelLocked());
-            pw.print(prefix); pw.print("Target SDK: "); pw.println(getTargedSdkLocked());
         }
         pw.print(prefix); pw.print("Default component: "); pw.println(getContext()
                 .getString(R.string.config_defaultAutofillService));
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceShellCommand.java b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceShellCommand.java
index c562fb1..bbe37a5 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceShellCommand.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceShellCommand.java
@@ -109,6 +109,13 @@
                     + "implementation.");
             pw.println("    To reset, call with just the USER_ID argument.");
             pw.println("");
+            pw.println("  set default-augmented-service-enabled USER_ID [true|false]");
+            pw.println("    Enable / disable the default augmented autofill service for the user.");
+            pw.println("");
+            pw.println("  get default-augmented-service-enabled USER_ID");
+            pw.println("    Checks whether the default augmented autofill service is enabled for "
+                    + "the user.");
+            pw.println("");
             pw.println("  list sessions [--user USER_ID]");
             pw.println("    Lists all pending sessions.");
             pw.println("");
@@ -136,6 +143,8 @@
                 return getFullScreenMode(pw);
             case "bind-instant-service-allowed":
                 return getBindInstantService(pw);
+            case "default-augmented-service-enabled":
+                return getDefaultAugmentedServiceEnabled(pw);
             default:
                 pw.println("Invalid set: " + what);
                 return -1;
@@ -158,6 +167,8 @@
                 return setBindInstantService(pw);
             case "temporary-augmented-service":
                 return setTemporaryAugmentedService(pw);
+            case "default-augmented-service-enabled":
+                return setDefaultAugmentedServiceEnabled(pw);
             default:
                 pw.println("Invalid set: " + what);
                 return -1;
@@ -314,6 +325,23 @@
         return 0;
     }
 
+    private int getDefaultAugmentedServiceEnabled(PrintWriter pw) {
+        final int userId = getNextIntArgRequired();
+        final boolean enabled = mService.isDefaultAugmentedServiceEnabled(userId);
+        pw.println(enabled);
+        return 0;
+    }
+
+    private int setDefaultAugmentedServiceEnabled(PrintWriter pw) {
+        final int userId = getNextIntArgRequired();
+        final boolean enabled = Boolean.parseBoolean(getNextArgRequired());
+        final boolean changed = mService.setDefaultAugmentedServiceEnabled(userId, enabled);
+        if (!changed) {
+            pw.println("already " + enabled);
+        }
+        return 0;
+    }
+
     private int requestDestroy(PrintWriter pw) {
         if (!isNextArgSessions(pw)) {
             return -1;
diff --git a/services/autofill/java/com/android/server/autofill/RemoteAugmentedAutofillService.java b/services/autofill/java/com/android/server/autofill/RemoteAugmentedAutofillService.java
index aaba1ed..3c17ac3 100644
--- a/services/autofill/java/com/android/server/autofill/RemoteAugmentedAutofillService.java
+++ b/services/autofill/java/com/android/server/autofill/RemoteAugmentedAutofillService.java
@@ -16,6 +16,8 @@
 
 package com.android.server.autofill;
 
+import static com.android.server.autofill.Helper.sDebug;
+
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.UserIdInt;
@@ -26,6 +28,7 @@
 import android.content.pm.ServiceInfo;
 import android.os.Bundle;
 import android.os.IBinder;
+import android.os.ICancellationSignal;
 import android.os.RemoteException;
 import android.os.SystemClock;
 import android.service.autofill.augmented.AugmentedAutofillService;
@@ -142,6 +145,16 @@
         scheduleAsyncRequest((s) -> s.onDestroyAllFillWindowsRequest());
     }
 
+    private void dispatchOnFillTimeout(@NonNull ICancellationSignal cancellation) {
+        mHandler.post(() -> {
+            try {
+                cancellation.cancel();
+            } catch (RemoteException e) {
+                Slog.w(mTag, "Error calling cancellation signal: " + e);
+            }
+        });
+    }
+
     // TODO(b/123100811): inline into PendingAutofillRequest if it doesn't have any other subclass
     private abstract static class MyPendingRequest
             extends PendingRequest<RemoteAugmentedAutofillService, IAugmentedAutofillService> {
@@ -161,6 +174,7 @@
         private final int mTaskId;
         private final long mRequestTime = SystemClock.elapsedRealtime();
         private final @NonNull IFillCallback mCallback;
+        private ICancellationSignal mCancellation;
 
         protected PendingAutofillRequest(@NonNull RemoteAugmentedAutofillService service,
                 int sessionId, @NonNull IAutoFillManagerClient client, int taskId,
@@ -178,11 +192,55 @@
                     if (!finish()) return;
                     // NOTE: so far we don't need notify RemoteAugmentedAutofillServiceCallbacks
                 }
+
+                @Override
+                public void onCancellable(ICancellationSignal cancellation) {
+                    synchronized (mLock) {
+                        final boolean cancelled;
+                        synchronized (mLock) {
+                            mCancellation = cancellation;
+                            cancelled = isCancelledLocked();
+                        }
+                        if (cancelled) {
+                            try {
+                                cancellation.cancel();
+                            } catch (RemoteException e) {
+                                Slog.e(mTag, "Error requesting a cancellation", e);
+                            }
+                        }
+                    }
+                }
+
+                @Override
+                public boolean isCompleted() {
+                    return isRequestCompleted();
+                }
+
+                @Override
+                public void cancel() {
+                    synchronized (mLock) {
+                        final boolean cancelled = isCancelledLocked();
+                        final ICancellationSignal cancellation = mCancellation;
+                        if (!cancelled) {
+                            try {
+                                cancellation.cancel();
+                            } catch (RemoteException e) {
+                                Slog.e(mTag, "Error requesting a cancellation", e);
+                            }
+                        }
+                    }
+                }
             };
         }
 
         @Override
         public void run() {
+            synchronized (mLock) {
+                if (isCancelledLocked()) {
+                    if (sDebug) Slog.d(mTag, "run() called after canceled");
+                    return;
+                }
+            }
             final RemoteAugmentedAutofillService remoteService = getService();
             if (remoteService == null) return;
 
@@ -215,8 +273,33 @@
             Slog.w(TAG, "PendingAutofillRequest timed out (" + remoteService.mRequestTimeoutMs
                     + "ms) for " + remoteService);
             // NOTE: so far we don't need notify RemoteAugmentedAutofillServiceCallbacks
+            final ICancellationSignal cancellation;
+            synchronized (mLock) {
+                cancellation = mCancellation;
+            }
+            if (cancellation != null) {
+                remoteService.dispatchOnFillTimeout(cancellation);
+            }
             finish();
         }
+
+        @Override
+        public boolean cancel() {
+            if (!super.cancel()) return false;
+
+            final ICancellationSignal cancellation;
+            synchronized (mLock) {
+                cancellation = mCancellation;
+            }
+            if (cancellation != null) {
+                try {
+                    cancellation.cancel();
+                } catch (RemoteException e) {
+                    Slog.e(mTag, "Error cancelling a fill request", e);
+                }
+            }
+            return true;
+        }
     }
 
     public interface RemoteAugmentedAutofillServiceCallbacks
diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java
index ea47033..f08bab3 100644
--- a/services/autofill/java/com/android/server/autofill/Session.java
+++ b/services/autofill/java/com/android/server/autofill/Session.java
@@ -138,7 +138,11 @@
 
     private static AtomicInteger sIdCounter = new AtomicInteger();
 
-    /** ID of the session */
+    /**
+     * ID of the session.
+     *
+     * <p>It's always a positive number, to make it easier to embed it in a long.
+     */
     public final int id;
 
     /** uid the session is for */
@@ -277,6 +281,13 @@
     private ArraySet<AutofillId> mAugmentedAutofillableIds;
 
     /**
+     * When {@code true}, the session was created only to handle Augmented Autofill requests (i.e.,
+     * the session would not have existed otherwsie).
+     */
+    @GuardedBy("mLock")
+    private boolean mForAugmentedAutofillOnly;
+
+    /**
      * Receiver of assist data from the app's {@link Activity}.
      */
     private final IAssistDataReceiver mAssistReceiver = new IAssistDataReceiver.Stub() {
@@ -538,11 +549,12 @@
      */
     @GuardedBy("mLock")
     private void requestNewFillResponseLocked(int flags) {
-
-        if ((flags & FLAG_AUGMENTED_AUTOFILL_REQUEST) != 0) {
+        if (mForAugmentedAutofillOnly || (flags & FLAG_AUGMENTED_AUTOFILL_REQUEST) != 0) {
             // TODO(b/122858578): log metrics
             if (sVerbose) {
-                Slog.v(TAG, "requestNewFillResponse(): triggering augmented autofill instead");
+                Slog.v(TAG, "requestNewFillResponse(): triggering augmented autofill instead "
+                        + "(mForAugmentedAutofillOnly=" + mForAugmentedAutofillOnly
+                        + ", flags=" + flags + ")");
             }
             triggerAugmentedAutofillLocked();
             return;
@@ -564,8 +576,8 @@
         mRequestLogs.put(requestId, log);
 
         if (sVerbose) {
-            Slog.v(TAG, "Requesting structure for request #" + ordinal + " ,requestId="
-                    + requestId + ", flags=" + flags);
+            Slog.v(TAG, "Requesting structure for request #" + ordinal + " ,requestId=" + requestId
+                    + ", flags=" + flags);
         }
 
         // If the focus changes very quickly before the first request is returned each focus change
@@ -598,7 +610,10 @@
             @NonNull IBinder client, boolean hasCallback, @NonNull LocalLog uiLatencyHistory,
             @NonNull LocalLog wtfHistory, @NonNull ComponentName serviceComponentName,
             @NonNull ComponentName componentName, boolean compatMode,
-            boolean bindInstantServiceAllowed, int flags) {
+            boolean bindInstantServiceAllowed, boolean forAugmentedAutofillOnly, int flags) {
+        if (sessionId < 0) {
+            wtf(null, "Non-positive sessionId: %s", sessionId);
+        }
         id = sessionId;
         mFlags = flags;
         this.taskId = taskId;
@@ -616,6 +631,7 @@
         mWtfHistory = wtfHistory;
         mComponentName = componentName;
         mCompatMode = compatMode;
+        mForAugmentedAutofillOnly = forAugmentedAutofillOnly;
         setClientLocked(client);
 
         mMetricsLogger.write(newLogMaker(MetricsEvent.AUTOFILL_SESSION_STARTED)
@@ -727,14 +743,6 @@
         final long disableDuration = response.getDisableDuration();
         if (disableDuration > 0) {
             final int flags = response.getFlags();
-            if (sDebug) {
-                final StringBuilder message = new StringBuilder("Service disabled autofill for ")
-                        .append(mComponentName)
-                        .append(": flags=").append(flags)
-                        .append(", duration=");
-                TimeUtils.formatDuration(disableDuration, message);
-                Slog.d(TAG, message.toString());
-            }
             if ((flags & FillResponse.FLAG_DISABLE_ACTIVITY_ONLY) != 0) {
                 mService.disableAutofillForActivity(mComponentName, disableDuration,
                         id, mCompatMode);
@@ -742,6 +750,23 @@
                 mService.disableAutofillForApp(mComponentName.getPackageName(), disableDuration,
                         id, mCompatMode);
             }
+            // Although "standard" autofill is disabled, it might still trigger augmented autofill
+            if (triggerAugmentedAutofillLocked() != null) {
+                mForAugmentedAutofillOnly = true;
+                if (sDebug) {
+                    Slog.d(TAG, "Service disabled autofill for " + mComponentName
+                            + ", but session is kept for augmented autofill only");
+                }
+                return;
+            }
+            if (sDebug) {
+                final StringBuilder message = new StringBuilder("Service disabled autofill for ")
+                                .append(mComponentName)
+                                .append(": flags=").append(flags)
+                                .append(", duration=");
+                TimeUtils.formatDuration(disableDuration, message);
+                Slog.d(TAG, message.toString());
+            }
             sessionFinishedState = AutofillManager.STATE_DISABLED_BY_SERVICE;
         }
 
@@ -3005,6 +3030,9 @@
         pw.print(prefix); pw.print("mSaveOnAllViewsInvisible: "); pw.println(
                 mSaveOnAllViewsInvisible);
         pw.print(prefix); pw.print("mSelectedDatasetIds: "); pw.println(mSelectedDatasetIds);
+        if (mForAugmentedAutofillOnly) {
+            pw.print(prefix); pw.println("For Augmented Autofill Only");
+        }
         if (mAugmentedAutofillDestroyer != null) {
             pw.print(prefix); pw.println("has mAugmentedAutofillDestroyer");
         }
diff --git a/services/backup/java/com/android/server/backup/BackupManagerService.java b/services/backup/java/com/android/server/backup/BackupManagerService.java
index ffda581..7106664 100644
--- a/services/backup/java/com/android/server/backup/BackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/BackupManagerService.java
@@ -362,8 +362,8 @@
      * @param dataManagementIntent An {@link Intent} that can be passed to {@link
      *     Context#startActivity} in order to launch the transport's data-management UI. It may be
      *     {@code null} if the transport does not offer any user-facing data management UI.
-     * @param dataManagementLabel A {@link String} to be used as the label for the transport's data
-     *     management affordance. This MUST be {@code null} when dataManagementIntent is {@code
+     * @param dataManagementLabel A {@link CharSequence} to be used as the label for the transport's
+     *     data management affordance. This MUST be {@code null} when dataManagementIntent is {@code
      *     null} and MUST NOT be {@code null} when dataManagementIntent is not {@code null}.
      * @throws SecurityException If the UID of the calling process differs from the package UID of
      *     {@code transportComponent} or if the caller does NOT have BACKUP permission.
@@ -375,7 +375,7 @@
             @Nullable Intent configurationIntent,
             String currentDestinationString,
             @Nullable Intent dataManagementIntent,
-            String dataManagementLabel) {
+            CharSequence dataManagementLabel) {
         UserBackupManagerService userBackupManagerService =
                 getServiceForUserIfCallerHasPermission(userId, "updateTransportAttributes()");
 
@@ -521,7 +521,7 @@
      * transport.
      */
     @Nullable
-    public String getDataManagementLabel(@UserIdInt int userId, String transportName) {
+    public CharSequence getDataManagementLabel(@UserIdInt int userId, String transportName) {
         UserBackupManagerService userBackupManagerService =
                 getServiceForUserIfCallerHasPermission(userId, "getDataManagementLabel()");
 
diff --git a/services/backup/java/com/android/server/backup/Trampoline.java b/services/backup/java/com/android/server/backup/Trampoline.java
index 00cb6d3..8f0c5d8 100644
--- a/services/backup/java/com/android/server/backup/Trampoline.java
+++ b/services/backup/java/com/android/server/backup/Trampoline.java
@@ -630,8 +630,7 @@
             @Nullable Intent configurationIntent,
             String currentDestinationString,
             @Nullable Intent dataManagementIntent,
-            String dataManagementLabel) {
-
+            CharSequence dataManagementLabel) {
         if (isUserReadyForBackup(userId)) {
             mService.updateTransportAttributes(
                     userId,
@@ -710,19 +709,13 @@
     }
 
     @Override
-    public String getDataManagementLabelForUser(int userId, String transport)
+    public CharSequence getDataManagementLabelForUser(int userId, String transport)
             throws RemoteException {
         return isUserReadyForBackup(userId) ? mService.getDataManagementLabel(userId, transport)
                 : null;
     }
 
     @Override
-    public String getDataManagementLabel(String transport)
-            throws RemoteException {
-        return getDataManagementLabelForUser(binderGetCallingUserId(), transport);
-    }
-
-    @Override
     public IRestoreSession beginRestoreSessionForUser(
             int userId, String packageName, String transportID) throws RemoteException {
         return isUserReadyForBackup(userId) ? mService.beginRestoreSession(userId, packageName,
diff --git a/services/backup/java/com/android/server/backup/TransportManager.java b/services/backup/java/com/android/server/backup/TransportManager.java
index a7bada0..30ce4cf 100644
--- a/services/backup/java/com/android/server/backup/TransportManager.java
+++ b/services/backup/java/com/android/server/backup/TransportManager.java
@@ -284,7 +284,7 @@
      * @throws TransportNotRegisteredException if the transport is not registered.
      */
     @Nullable
-    public String getTransportDataManagementLabel(String transportName)
+    public CharSequence getTransportDataManagementLabel(String transportName)
             throws TransportNotRegisteredException {
         synchronized (mTransportLock) {
             return getRegisteredTransportDescriptionOrThrowLocked(transportName)
@@ -327,7 +327,7 @@
             @Nullable Intent configurationIntent,
             String currentDestinationString,
             @Nullable Intent dataManagementIntent,
-            @Nullable String dataManagementLabel) {
+            @Nullable CharSequence dataManagementLabel) {
         synchronized (mTransportLock) {
             TransportDescription description =
                     mRegisteredTransportsDescriptionMap.get(transportComponent);
@@ -678,7 +678,7 @@
                         transport.configurationIntent(),
                         transport.currentDestinationString(),
                         transport.dataManagementIntent(),
-                        transport.dataManagementLabel());
+                        transport.dataManagementIntentLabel());
         synchronized (mTransportLock) {
             mRegisteredTransportsDescriptionMap.put(transportComponent, description);
         }
@@ -707,7 +707,7 @@
         @Nullable private Intent configurationIntent;
         private String currentDestinationString;
         @Nullable private Intent dataManagementIntent;
-        @Nullable private String dataManagementLabel;
+        @Nullable private CharSequence dataManagementLabel;
 
         private TransportDescription(
                 String name,
@@ -715,7 +715,7 @@
                 @Nullable Intent configurationIntent,
                 String currentDestinationString,
                 @Nullable Intent dataManagementIntent,
-                @Nullable String dataManagementLabel) {
+                @Nullable CharSequence dataManagementLabel) {
             this.name = name;
             this.transportDirName = transportDirName;
             this.configurationIntent = configurationIntent;
diff --git a/services/backup/java/com/android/server/backup/UserBackupManagerService.java b/services/backup/java/com/android/server/backup/UserBackupManagerService.java
index 32e2cac..447bd8c 100644
--- a/services/backup/java/com/android/server/backup/UserBackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/UserBackupManagerService.java
@@ -2929,8 +2929,8 @@
      *     {@link Context#startActivity} in order to launch the transport's data-management UI. It
      *     may be {@code null} if the transport does not offer any user-facing data
      *     management UI.
-     * @param dataManagementLabel A {@link String} to be used as the label for the transport's data
-     *     management affordance. This MUST be {@code null} when dataManagementIntent is
+     * @param dataManagementLabel A {@link CharSequence} to be used as the label for the transport's
+     *     data management affordance. This MUST be {@code null} when dataManagementIntent is
      *     {@code null} and MUST NOT be {@code null} when dataManagementIntent is not {@code null}.
      * @throws SecurityException If the UID of the calling process differs from the package UID of
      *     {@code transportComponent} or if the caller does NOT have BACKUP permission.
@@ -2941,7 +2941,7 @@
             @Nullable Intent configurationIntent,
             String currentDestinationString,
             @Nullable Intent dataManagementIntent,
-            @Nullable String dataManagementLabel) {
+            @Nullable CharSequence dataManagementLabel) {
         updateTransportAttributes(
                 Binder.getCallingUid(),
                 transportComponent,
@@ -2960,7 +2960,7 @@
             @Nullable Intent configurationIntent,
             String currentDestinationString,
             @Nullable Intent dataManagementIntent,
-            @Nullable String dataManagementLabel) {
+            @Nullable CharSequence dataManagementLabel) {
         mContext.enforceCallingOrSelfPermission(
                 android.Manifest.permission.BACKUP, "updateTransportAttributes");
 
@@ -3159,12 +3159,12 @@
      * Supply the menu label for affordances that fire the manage-data intent for the given
      * transport.
      */
-    public String getDataManagementLabel(String transportName) {
+    public CharSequence getDataManagementLabel(String transportName) {
         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
                 "getDataManagementLabel");
 
         try {
-            String label = mTransportManager.getTransportDataManagementLabel(transportName);
+            CharSequence label = mTransportManager.getTransportDataManagementLabel(transportName);
             if (MORE_DEBUG) {
                 Slog.d(TAG, "getDataManagementLabel() returning " + label);
             }
diff --git a/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerServiceShellCommand.java b/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerServiceShellCommand.java
index 86ad52d..fc9754a 100644
--- a/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerServiceShellCommand.java
+++ b/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerServiceShellCommand.java
@@ -114,7 +114,7 @@
             case "temporary-service":
                 return setTemporaryService(pw);
             case "default-service-enabled":
-                return setDefaultServiceEnabled();
+                return setDefaultServiceEnabled(pw);
             default:
                 pw.println("Invalid set: " + what);
                 return -1;
@@ -159,10 +159,13 @@
         return 0;
     }
 
-    private int setDefaultServiceEnabled() {
+    private int setDefaultServiceEnabled(PrintWriter pw) {
         final int userId = getNextIntArgRequired();
-        final boolean enabled = Boolean.parseBoolean(getNextArg());
-        mService.setDefaultServiceEnabled(userId, enabled);
+        final boolean enabled = Boolean.parseBoolean(getNextArgRequired());
+        final boolean changed = mService.setDefaultServiceEnabled(userId, enabled);
+        if (!changed) {
+            pw.println("already " + enabled);
+        }
         return 0;
     }
 
diff --git a/services/contentcapture/java/com/android/server/contentcapture/ContentCapturePerUserService.java b/services/contentcapture/java/com/android/server/contentcapture/ContentCapturePerUserService.java
index c423f9c..d7d97b3 100644
--- a/services/contentcapture/java/com/android/server/contentcapture/ContentCapturePerUserService.java
+++ b/services/contentcapture/java/com/android/server/contentcapture/ContentCapturePerUserService.java
@@ -27,12 +27,10 @@
 import static com.android.server.wm.ActivityTaskManagerInternal.ASSIST_KEY_DATA;
 import static com.android.server.wm.ActivityTaskManagerInternal.ASSIST_KEY_STRUCTURE;
 
-import android.Manifest;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.UserIdInt;
 import android.app.ActivityManagerInternal;
-import android.app.AppGlobals;
 import android.app.assist.AssistContent;
 import android.app.assist.AssistStructure;
 import android.content.ComponentName;
@@ -44,12 +42,12 @@
 import android.os.Binder;
 import android.os.Bundle;
 import android.os.IBinder;
-import android.os.RemoteException;
 import android.os.UserHandle;
 import android.provider.Settings;
 import android.service.contentcapture.ActivityEvent;
 import android.service.contentcapture.ActivityEvent.ActivityEventType;
 import android.service.contentcapture.ContentCaptureService;
+import android.service.contentcapture.ContentCaptureServiceInfo;
 import android.service.contentcapture.IContentCaptureServiceCallback;
 import android.service.contentcapture.SnapshotData;
 import android.util.ArrayMap;
@@ -107,6 +105,9 @@
     @GuardedBy("mLock")
     private boolean mZombie;
 
+    @GuardedBy("mLock")
+    private ContentCaptureServiceInfo mInfo;
+
     // TODO(b/111276913): add mechanism to prune stale sessions, similar to Autofill's
 
     ContentCapturePerUserService(@NonNull ContentCaptureManagerService master,
@@ -144,33 +145,9 @@
     @Override // from PerUserSystemService
     protected ServiceInfo newServiceInfoLocked(@NonNull ComponentName serviceComponent)
             throws NameNotFoundException {
-
-        int flags = PackageManager.GET_META_DATA;
-        final boolean isTemp = isTemporaryServiceSetLocked();
-        if (!isTemp) {
-            flags |= PackageManager.MATCH_SYSTEM_ONLY;
-        }
-
-        ServiceInfo si;
-        try {
-            si = AppGlobals.getPackageManager().getServiceInfo(serviceComponent, flags, mUserId);
-        } catch (RemoteException e) {
-            Slog.w(TAG, "Could not get service for " + serviceComponent + ": " + e);
-            return null;
-        }
-        if (si == null) {
-            Slog.w(TAG, "Could not get serviceInfo for " + (isTemp ? " (temp)" : "(default system)")
-                    + " " + serviceComponent.flattenToShortString());
-            return null;
-        }
-        if (!Manifest.permission.BIND_CONTENT_CAPTURE_SERVICE.equals(si.permission)) {
-            Slog.w(TAG, "ContentCaptureService from '" + si.packageName
-                    + "' does not require permission "
-                    + Manifest.permission.BIND_CONTENT_CAPTURE_SERVICE);
-            throw new SecurityException("Service does not require permission "
-                    + Manifest.permission.BIND_CONTENT_CAPTURE_SERVICE);
-        }
-        return si;
+        mInfo = new ContentCaptureServiceInfo(getContext(), serviceComponent,
+                isTemporaryServiceSetLocked(), mUserId);
+        return mInfo.getServiceInfo();
     }
 
     @Override // from PerUserSystemService
@@ -490,9 +467,16 @@
     protected void dumpLocked(String prefix, PrintWriter pw) {
         super.dumpLocked(prefix, pw);
 
+        final String prefix2 = prefix + "  ";
+        pw.print(prefix); pw.print("Service Info: ");
+        if (mInfo == null) {
+            pw.println("N/A");
+        } else {
+            pw.println();
+            mInfo.dump(prefix2, pw);
+        }
         pw.print(prefix); pw.print("Zombie: "); pw.println(mZombie);
 
-        final String prefix2 = prefix + "  ";
         if (mRemoteService != null) {
             pw.print(prefix); pw.println("remote service:");
             mRemoteService.dump(prefix2, pw);
diff --git a/services/core/java/com/android/server/AlarmManagerService.java b/services/core/java/com/android/server/AlarmManagerService.java
index a400cc3..3d918fc 100644
--- a/services/core/java/com/android/server/AlarmManagerService.java
+++ b/services/core/java/com/android/server/AlarmManagerService.java
@@ -83,6 +83,7 @@
 import android.util.Slog;
 import android.util.SparseArray;
 import android.util.SparseBooleanArray;
+import android.util.SparseIntArray;
 import android.util.SparseLongArray;
 import android.util.StatsLog;
 import android.util.TimeUtils;
@@ -195,6 +196,7 @@
     private final Injector mInjector;
     int mBroadcastRefCount = 0;
     PowerManager.WakeLock mWakeLock;
+    SparseIntArray mAlarmsPerUid = new SparseIntArray();
     ArrayList<Alarm> mPendingNonWakeupAlarms = new ArrayList<>();
     ArrayList<InFlight> mInFlight = new ArrayList<>();
     private final ArrayList<AlarmManagerInternal.InFlightListener> mInFlightListeners =
@@ -393,6 +395,8 @@
         @VisibleForTesting
         static final String KEY_LISTENER_TIMEOUT = "listener_timeout";
         @VisibleForTesting
+        static final String KEY_MAX_ALARMS_PER_UID = "max_alarms_per_uid";
+        @VisibleForTesting
         static final String KEY_APP_STANDBY_QUOTAS_ENABLED = "app_standby_quotas_enabled";
         private static final String KEY_APP_STANDBY_WINDOW = "app_standby_window";
         @VisibleForTesting
@@ -420,6 +424,7 @@
         private static final long DEFAULT_ALLOW_WHILE_IDLE_LONG_TIME = 9*60*1000;
         private static final long DEFAULT_ALLOW_WHILE_IDLE_WHITELIST_DURATION = 10*1000;
         private static final long DEFAULT_LISTENER_TIMEOUT = 5 * 1000;
+        private static final int DEFAULT_MAX_ALARMS_PER_UID = 500;
         private static final boolean DEFAULT_APP_STANDBY_QUOTAS_ENABLED = true;
         private static final long DEFAULT_APP_STANDBY_WINDOW = 60 * 60 * 1000;  // 1 hr
         /**
@@ -461,6 +466,8 @@
 
         // Direct alarm listener callback timeout
         public long LISTENER_TIMEOUT = DEFAULT_LISTENER_TIMEOUT;
+        public int MAX_ALARMS_PER_UID = DEFAULT_MAX_ALARMS_PER_UID;
+
         public boolean APP_STANDBY_QUOTAS_ENABLED = DEFAULT_APP_STANDBY_QUOTAS_ENABLED;
 
         public long APP_STANDBY_WINDOW = DEFAULT_APP_STANDBY_WINDOW;
@@ -549,6 +556,15 @@
                     APP_STANDBY_QUOTAS[i] = mParser.getInt(KEYS_APP_STANDBY_QUOTAS[i],
                             Math.min(APP_STANDBY_QUOTAS[i - 1], DEFAULT_APP_STANDBY_QUOTAS[i]));
                 }
+
+                MAX_ALARMS_PER_UID = mParser.getInt(KEY_MAX_ALARMS_PER_UID,
+                        DEFAULT_MAX_ALARMS_PER_UID);
+                if (MAX_ALARMS_PER_UID < DEFAULT_MAX_ALARMS_PER_UID) {
+                    Slog.w(TAG, "Cannot set " + KEY_MAX_ALARMS_PER_UID + " lower than "
+                            + DEFAULT_MAX_ALARMS_PER_UID);
+                    MAX_ALARMS_PER_UID = DEFAULT_MAX_ALARMS_PER_UID;
+                }
+
                 updateAllowWhileIdleWhitelistDurationLocked();
             }
         }
@@ -590,6 +606,9 @@
             TimeUtils.formatDuration(ALLOW_WHILE_IDLE_WHITELIST_DURATION, pw);
             pw.println();
 
+            pw.print(KEY_MAX_ALARMS_PER_UID); pw.print("=");
+            pw.println(MAX_ALARMS_PER_UID);
+
             for (int i = 0; i < KEYS_APP_STANDBY_DELAY.length; i++) {
                 pw.print(KEYS_APP_STANDBY_DELAY[i]); pw.print("=");
                 TimeUtils.formatDuration(APP_STANDBY_MIN_DELAYS[i], pw);
@@ -671,12 +690,6 @@
 
         final ArrayList<Alarm> alarms = new ArrayList<Alarm>();
 
-        Batch() {
-            start = 0;
-            end = Long.MAX_VALUE;
-            flags = 0;
-        }
-
         Batch(Alarm seed) {
             start = seed.whenElapsed;
             end = clampPositive(seed.maxWhenElapsed);
@@ -728,11 +741,16 @@
             return newStart;
         }
 
+        /**
+         * Remove an alarm from this batch.
+         * <p> <b> Should be used only while re-ordering the alarm within the service </b> as it
+         * does not update {@link #mAlarmsPerUid}
+         */
         boolean remove(Alarm alarm) {
-            return remove(a -> (a == alarm));
+            return remove(a -> (a == alarm), true);
         }
 
-        boolean remove(Predicate<Alarm> predicate) {
+        boolean remove(Predicate<Alarm> predicate, boolean reOrdering) {
             boolean didRemove = false;
             long newStart = 0;  // recalculate endpoints as we go
             long newEnd = Long.MAX_VALUE;
@@ -741,6 +759,9 @@
                 Alarm alarm = alarms.get(i);
                 if (predicate.test(alarm)) {
                     alarms.remove(i);
+                    if (!reOrdering) {
+                        decrementAlarmCount(alarm.uid);
+                    }
                     didRemove = true;
                     if (alarm.alarmClock != null) {
                         mNextAlarmClockMayChange = true;
@@ -1734,6 +1755,15 @@
                         + " tElapsed=" + triggerElapsed + " maxElapsed=" + maxElapsed
                         + " interval=" + interval + " flags=0x" + Integer.toHexString(flags));
             }
+            if (mAlarmsPerUid.get(callingUid, 0) >= mConstants.MAX_ALARMS_PER_UID) {
+                final String errorMsg =
+                        "Maximum limit of concurrent alarms " + mConstants.MAX_ALARMS_PER_UID
+                                + " reached for uid: " + UserHandle.formatUid(callingUid)
+                                + ", callingPackage: " + callingPackage;
+                // STOPSHIP (b/128866264): Just to catch breakages. Remove before final release.
+                Slog.wtf(TAG, errorMsg);
+                throw new UnsupportedOperationException(errorMsg);
+            }
             setImplLocked(type, triggerAtTime, triggerElapsed, windowLength, maxElapsed,
                     interval, operation, directReceiver, listenerTag, flags, true, workSource,
                     alarmClock, callingUid, callingPackage);
@@ -1756,6 +1786,7 @@
         } catch (RemoteException e) {
         }
         removeLocked(operation, directReceiver);
+        incrementAlarmCount(a.uid);
         setImplLocked(a, false, doValidate);
     }
 
@@ -2197,7 +2228,6 @@
                             ? sdf.format(new Date(nowRTC - (nowELAPSED - time)))
                             : "-");
                 } while (i != mNextTickHistory);
-                pw.println();
             }
 
             SystemServiceManager ssm = LocalServices.getService(SystemServiceManager.class);
@@ -2305,6 +2335,18 @@
             if (!blocked) {
                 pw.println("    none");
             }
+            pw.println();
+            pw.print("  Pending alarms per uid: [");
+            for (int i = 0; i < mAlarmsPerUid.size(); i++) {
+                if (i > 0) {
+                    pw.print(", ");
+                }
+                UserHandle.formatUid(pw, mAlarmsPerUid.keyAt(i));
+                pw.print(":");
+                pw.print(mAlarmsPerUid.valueAt(i));
+            }
+            pw.println("]");
+            pw.println();
 
             mAppWakeupHistory.dump(pw, "  ", nowELAPSED);
 
@@ -3046,7 +3088,7 @@
         final Predicate<Alarm> whichAlarms = (Alarm a) -> a.matches(operation, directReceiver);
         for (int i = mAlarmBatches.size() - 1; i >= 0; i--) {
             Batch b = mAlarmBatches.get(i);
-            didRemove |= b.remove(whichAlarms);
+            didRemove |= b.remove(whichAlarms, false);
             if (b.size() == 0) {
                 mAlarmBatches.remove(i);
             }
@@ -3098,7 +3140,7 @@
         final Predicate<Alarm> whichAlarms = (Alarm a) -> a.uid == uid;
         for (int i = mAlarmBatches.size() - 1; i >= 0; i--) {
             Batch b = mAlarmBatches.get(i);
-            didRemove |= b.remove(whichAlarms);
+            didRemove |= b.remove(whichAlarms, false);
             if (b.size() == 0) {
                 mAlarmBatches.remove(i);
             }
@@ -3145,7 +3187,7 @@
         final boolean oldHasTick = haveBatchesTimeTickAlarm(mAlarmBatches);
         for (int i = mAlarmBatches.size() - 1; i >= 0; i--) {
             Batch b = mAlarmBatches.get(i);
-            didRemove |= b.remove(whichAlarms);
+            didRemove |= b.remove(whichAlarms, false);
             if (b.size() == 0) {
                 mAlarmBatches.remove(i);
             }
@@ -3183,6 +3225,7 @@
         }
     }
 
+    // Only called for ephemeral apps
     void removeForStoppedLocked(final int uid) {
         if (uid == Process.SYSTEM_UID) {
             Slog.wtf(TAG, "removeForStoppedLocked: Shouldn't for UID=" + uid);
@@ -3200,7 +3243,7 @@
         };
         for (int i = mAlarmBatches.size() - 1; i >= 0; i--) {
             Batch b = mAlarmBatches.get(i);
-            didRemove |= b.remove(whichAlarms);
+            didRemove |= b.remove(whichAlarms, false);
             if (b.size() == 0) {
                 mAlarmBatches.remove(i);
             }
@@ -3237,7 +3280,7 @@
                 (Alarm a) -> UserHandle.getUserId(a.creatorUid) == userHandle;
         for (int i = mAlarmBatches.size() - 1; i >= 0; i--) {
             Batch b = mAlarmBatches.get(i);
-            didRemove |= b.remove(whichAlarms);
+            didRemove |= b.remove(whichAlarms, false);
             if (b.size() == 0) {
                 mAlarmBatches.remove(i);
             }
@@ -3407,8 +3450,7 @@
         return mConstants.ALLOW_WHILE_IDLE_LONG_TIME;
     }
 
-    boolean triggerAlarmsLocked(ArrayList<Alarm> triggerList, final long nowELAPSED,
-            final long nowRTC) {
+    boolean triggerAlarmsLocked(ArrayList<Alarm> triggerList, final long nowELAPSED) {
         boolean hasWakeup = false;
         // batches are temporally sorted, so we need only pull from the
         // start of the list until we either empty it or hit a batch
@@ -3984,7 +4026,7 @@
                         }
 
                         mLastTrigger = nowELAPSED;
-                        boolean hasWakeup = triggerAlarmsLocked(triggerList, nowELAPSED, nowRTC);
+                        boolean hasWakeup = triggerAlarmsLocked(triggerList, nowELAPSED);
                         if (!hasWakeup && checkAllowNonWakeupDelayLocked(nowELAPSED)) {
                             // if there are no wakeup alarms and the screen is off, we can
                             // delay what we have so far until the future.
@@ -4108,9 +4150,8 @@
                 case ALARM_EVENT: {
                     ArrayList<Alarm> triggerList = new ArrayList<Alarm>();
                     synchronized (mLock) {
-                        final long nowRTC = mInjector.getCurrentTimeMillis();
                         final long nowELAPSED = mInjector.getElapsedRealtime();
-                        triggerAlarmsLocked(triggerList, nowELAPSED, nowRTC);
+                        triggerAlarmsLocked(triggerList, nowELAPSED);
                         updateNextAlarmClockLocked();
                     }
 
@@ -4719,7 +4760,7 @@
                 mAppWakeupHistory.recordAlarmForPackage(alarm.sourcePackage,
                         UserHandle.getUserId(alarm.creatorUid), nowELAPSED);
             }
-
+            decrementAlarmCount(alarm.uid);
             final BroadcastStats bs = inflight.mBroadcastStats;
             bs.count++;
             if (bs.nesting == 0) {
@@ -4747,6 +4788,27 @@
         }
     }
 
+    private void incrementAlarmCount(int uid) {
+        final int uidIndex = mAlarmsPerUid.indexOfKey(uid);
+        if (uidIndex >= 0) {
+            mAlarmsPerUid.setValueAt(uidIndex, mAlarmsPerUid.valueAt(uidIndex) + 1);
+        } else {
+            mAlarmsPerUid.put(uid, 1);
+        }
+    }
+
+    private void decrementAlarmCount(int uid) {
+        final int uidIndex = mAlarmsPerUid.indexOfKey(uid);
+        if (uidIndex >= 0) {
+            final int newCount = mAlarmsPerUid.valueAt(uidIndex) - 1;
+            if (newCount > 0) {
+                mAlarmsPerUid.setValueAt(uidIndex, newCount);
+            } else {
+                mAlarmsPerUid.removeAt(uidIndex);
+            }
+        }
+    }
+
     private class ShellCmd extends ShellCommand {
 
         IAlarmManager getBinderService() {
diff --git a/services/core/java/com/android/server/BatteryService.java b/services/core/java/com/android/server/BatteryService.java
index a85b69b..39f7f0f 100644
--- a/services/core/java/com/android/server/BatteryService.java
+++ b/services/core/java/com/android/server/BatteryService.java
@@ -127,6 +127,7 @@
     // discharge stats before the device dies.
     private int mCriticalBatteryLevel;
 
+    // TODO: Current args don't work since "--unplugged" flag was purposefully removed.
     private static final String[] DUMPSYS_ARGS = new String[] { "--checkin", "--unplugged" };
 
     private static final String DUMPSYS_DATA_PATH = "/data/system/";
@@ -734,6 +735,7 @@
         mLastBatteryLevelChangedSentMs = SystemClock.elapsedRealtime();
     }
 
+    // TODO: Current code doesn't work since "--unplugged" flag in BSS was purposefully removed.
     private void logBatteryStatsLocked() {
         IBinder batteryInfoService = ServiceManager.getService(BatteryStats.SERVICE_NAME);
         if (batteryInfoService == null) return;
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index b2ee686..ec5987e 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -2174,7 +2174,7 @@
             if (VDBG) log("identical MTU - not setting");
             return;
         }
-        if (LinkProperties.isValidMtu(mtu, newLp.hasGlobalIPv6Address()) == false) {
+        if (!LinkProperties.isValidMtu(mtu, newLp.hasGlobalIpv6Address())) {
             if (mtu != 0) loge("Unexpected mtu value: " + mtu + ", " + iface);
             return;
         }
@@ -2561,19 +2561,11 @@
 
                     final boolean partialConnectivity =
                             (msg.arg1 == NETWORK_TEST_RESULT_PARTIAL_CONNECTIVITY)
-                                    // If user accepts partial connectivity network, NetworkMonitor
-                                    // will skip https probing. It will make partial connectivity
-                                    // network becomes valid. But user still need to know this
-                                    // network is limited. So, it's needed to refer to
-                                    // acceptPartialConnectivity to add
-                                    // NET_CAPABILITY_PARTIAL_CONNECTIVITY into NetworkCapabilities
-                                    // of this network. So that user can see "Limited connection"
-                                    // in the settings.
                                     || (nai.networkMisc.acceptPartialConnectivity
                                             && nai.partialConnectivity);
                     // Once a network is determined to have partial connectivity, it cannot
                     // go back to full connectivity without a disconnect.
-                    final boolean partialConnectivityChange =
+                    final boolean partialConnectivityChanged =
                             (partialConnectivity && !nai.partialConnectivity);
 
                     final boolean valid = (msg.arg1 == NETWORK_TEST_RESULT_VALID);
@@ -2584,17 +2576,6 @@
                         nai.captivePortalLoginNotified = true;
                         showNetworkNotification(nai, NotificationType.LOGGED_IN);
                     }
-                    // If this network has just connected and partial connectivity has just been
-                    // detected, tell NetworkMonitor if the user accepted partial connectivity on a
-                    // previous connect.
-                    if ((msg.arg1 == NETWORK_TEST_RESULT_PARTIAL_CONNECTIVITY)
-                            && nai.networkMisc.acceptPartialConnectivity) {
-                        try {
-                            nai.networkMonitor().notifyAcceptPartialConnectivity();
-                        } catch (RemoteException e) {
-                            e.rethrowFromSystemServer();
-                        }
-                    }
 
                     final String redirectUrl = (msg.obj instanceof String) ? (String) msg.obj : "";
 
@@ -2624,7 +2605,7 @@
                             mNotifier.clearNotification(nai.network.netId,
                                     NotificationType.LOST_INTERNET);
                         }
-                    } else if (partialConnectivityChange) {
+                    } else if (partialConnectivityChanged) {
                         nai.partialConnectivity = partialConnectivity;
                         updateCapabilities(nai.getCurrentScore(), nai, nai.networkCapabilities);
                     }
@@ -3378,8 +3359,11 @@
             // Tear down the network.
             teardownUnneededNetwork(nai);
         } else {
+            // Inform NetworkMonitor that partial connectivity is acceptable. This will likely
+            // result in a partial connectivity result which will be processed by
+            // maybeHandleNetworkMonitorMessage.
             try {
-                nai.networkMonitor().notifyAcceptPartialConnectivity();
+                nai.networkMonitor().setAcceptPartialConnectivity();
             } catch (RemoteException e) {
                 e.rethrowFromSystemServer();
             }
@@ -3587,6 +3571,9 @@
         // because we're already prompting the user to sign in.
         if (nai == null || nai.everValidated || nai.everCaptivePortalDetected
                 || !nai.networkMisc.explicitlySelected || nai.networkMisc.acceptUnvalidated
+                // TODO: Once the value of acceptPartialConnectivity is moved to IpMemoryStore,
+                // we should reevaluate how to handle acceptPartialConnectivity when network just
+                // connected.
                 || nai.networkMisc.acceptPartialConnectivity) {
             return;
         }
@@ -6395,6 +6382,9 @@
             // NetworkMonitor seeing the correct LinkProperties when starting.
             // TODO: pass LinkProperties to the NetworkMonitor in the notifyNetworkConnected call.
             try {
+                if (networkAgent.networkMisc.acceptPartialConnectivity) {
+                    networkAgent.networkMonitor().setAcceptPartialConnectivity();
+                }
                 networkAgent.networkMonitor().notifyNetworkConnected();
             } catch (RemoteException e) {
                 e.rethrowFromSystemServer();
diff --git a/services/core/java/com/android/server/DeviceIdleController.java b/services/core/java/com/android/server/DeviceIdleController.java
index 3ab3c34..833faa6 100644
--- a/services/core/java/com/android/server/DeviceIdleController.java
+++ b/services/core/java/com/android/server/DeviceIdleController.java
@@ -115,7 +115,8 @@
  *
  * Test: atest com.android.server.DeviceIdleControllerTest
  *
- * Current idling state machine (as of Android 9 Pie). This can be visualized using Graphviz:
+ * Current idling state machine (as of Android Q). This can be visualized using Graphviz:
+   <pre>
 
    digraph {
      subgraph deep {
@@ -259,6 +260,7 @@
        ]
      }
    }
+   </pre>
  */
 public class DeviceIdleController extends SystemService
         implements AnyMotionDetector.DeviceIdleCallback {
diff --git a/services/core/java/com/android/server/DynamicAndroidService.java b/services/core/java/com/android/server/DynamicAndroidService.java
index 8488941..b02bfb1 100644
--- a/services/core/java/com/android/server/DynamicAndroidService.java
+++ b/services/core/java/com/android/server/DynamicAndroidService.java
@@ -25,6 +25,7 @@
 import android.os.IDynamicAndroidService;
 import android.os.RemoteException;
 import android.os.ServiceManager;
+import android.os.SystemProperties;
 import android.util.Slog;
 
 /**
@@ -34,6 +35,7 @@
 public class DynamicAndroidService extends IDynamicAndroidService.Stub implements DeathRecipient {
     private static final String TAG = "DynamicAndroidService";
     private static final String NO_SERVICE_ERROR = "no gsiservice";
+    private static final int GSID_ROUGH_TIMEOUT_MS = 8192;
 
     private Context mContext;
     private volatile IGsiService mGsiService;
@@ -66,12 +68,27 @@
 
     private IGsiService getGsiService() throws RemoteException {
         checkPermission();
-        synchronized (this) {
-            if (mGsiService == null) {
-                mGsiService = connect(this);
-            }
-            return mGsiService;
+        if (!"running".equals(SystemProperties.get("init.svc.gsid"))) {
+            SystemProperties.set("ctl.start", "gsid");
         }
+        for (int sleepMs = 64; sleepMs <= (GSID_ROUGH_TIMEOUT_MS << 1); sleepMs <<= 1) {
+            try {
+                Thread.sleep(sleepMs);
+            } catch (InterruptedException e) {
+                Slog.e(TAG, "Interrupted when waiting for GSID");
+                break;
+            }
+            if ("running".equals(SystemProperties.get("init.svc.gsid"))) {
+                synchronized (this) {
+                    if (mGsiService == null) {
+                        mGsiService = connect(this);
+                    }
+                    return mGsiService;
+                }
+            }
+        }
+        Slog.e(TAG, "Unable to start gsid");
+        return null;
     }
 
     private void checkPermission() {
diff --git a/services/core/java/com/android/server/LocationManagerService.java b/services/core/java/com/android/server/LocationManagerService.java
index c2a0611..b89223b 100644
--- a/services/core/java/com/android/server/LocationManagerService.java
+++ b/services/core/java/com/android/server/LocationManagerService.java
@@ -64,6 +64,7 @@
 import android.location.Location;
 import android.location.LocationManager;
 import android.location.LocationRequest;
+import android.location.LocationTime;
 import android.os.Binder;
 import android.os.Bundle;
 import android.os.Handler;
@@ -102,6 +103,7 @@
 import com.android.server.location.GeofenceProxy;
 import com.android.server.location.GnssBatchingProvider;
 import com.android.server.location.GnssLocationProvider;
+import com.android.server.location.GnssMeasurementCorrectionsProvider;
 import com.android.server.location.GnssMeasurementsProvider;
 import com.android.server.location.GnssNavigationMessageProvider;
 import com.android.server.location.GnssStatusListenerHelper;
@@ -195,6 +197,7 @@
     private PassiveProvider mPassiveProvider;  // track passive provider for special cases
     private LocationBlacklist mBlacklist;
     private GnssMeasurementsProvider mGnssMeasurementsProvider;
+    private GnssMeasurementCorrectionsProvider mGnssMeasurementCorrectionsProvider;
     private GnssNavigationMessageProvider mGnssNavigationMessageProvider;
     @GuardedBy("mLock")
     private String mLocationControllerExtraPackage;
@@ -309,9 +312,13 @@
                 AppOpsManager.WATCH_FOREGROUND_CHANGES,
                 new AppOpsManager.OnOpChangedInternalListener() {
                     public void onOpChanged(int op, String packageName) {
-                        synchronized (mLock) {
-                            onAppOpChangedLocked();
-                        }
+                        // onOpChanged invoked on ui thread, move to our thread to reduce risk of
+                        // blocking ui thread
+                        mHandler.post(() -> {
+                            synchronized (mLock) {
+                                onAppOpChangedLocked();
+                            }
+                        });
                     }
                 });
         mPackageManager.addOnPermissionsChangeListener(
@@ -501,6 +508,8 @@
         }
 
         if (broadcast) {
+            // needs to be sent to everyone because we don't know which user may have changed
+            // LOCATION_MODE state.
             mContext.sendBroadcastAsUser(
                     new Intent(LocationManager.MODE_CHANGED_ACTION),
                     UserHandle.ALL);
@@ -755,6 +764,8 @@
             mGnssStatusProvider = gnssProvider.getGnssStatusProvider();
             mNetInitiatedListener = gnssProvider.getNetInitiatedListener();
             mGnssMeasurementsProvider = gnssProvider.getGnssMeasurementsProvider();
+            mGnssMeasurementCorrectionsProvider =
+                    gnssProvider.getGnssMeasurementCorrectionsProvider();
             mGnssNavigationMessageProvider = gnssProvider.getGnssNavigationMessageProvider();
             mGpsGeofenceProxy = gnssProvider.getGpsGeofenceProxy();
         }
@@ -1212,6 +1223,13 @@
                             "-" + mName,
                             mCurrentUserId);
                 }
+
+                // needs to be sent to all users because whether or not a provider is enabled for
+                // a given user is complicated... we broadcast to everyone and let them figure it
+                // out via isProviderEnabled()
+                Intent intent = new Intent(LocationManager.PROVIDERS_CHANGED_ACTION);
+                intent.putExtra(LocationManager.EXTRA_PROVIDER_NAME, mName);
+                mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
             }
 
             if (useable == mUseable) {
@@ -1232,10 +1250,6 @@
             }
 
             updateProviderUseableLocked(this);
-
-            mContext.sendBroadcastAsUser(
-                    new Intent(LocationManager.PROVIDERS_CHANGED_ACTION),
-                    UserHandle.ALL);
         }
 
         @GuardedBy("mLock")
@@ -1811,12 +1825,7 @@
     @GuardedBy("mLock")
     private void removeProviderLocked(LocationProvider provider) {
         if (mProviders.remove(provider)) {
-            long identity = Binder.clearCallingIdentity();
-            try {
-                provider.onUseableChangedLocked(false);
-            } finally {
-                Binder.restoreCallingIdentity(identity);
-            }
+            provider.onUseableChangedLocked(false);
         }
     }
 
@@ -2095,7 +2104,9 @@
         WorkSource worksource = new WorkSource();
         ProviderRequest providerRequest = new ProviderRequest();
 
-        if (records != null && !records.isEmpty()) {
+        // if provider is not active, it should not respond to requests
+
+        if (mProviders.contains(provider) && records != null && !records.isEmpty()) {
             long backgroundThrottleInterval;
 
             long identity = Binder.clearCallingIdentity();
@@ -2685,6 +2696,19 @@
     }
 
     @Override
+    public LocationTime getGnssTimeMillis() {
+        synchronized (mLock) {
+            Location location = mLastLocation.get(LocationManager.GPS_PROVIDER);
+            if (location == null) {
+                return null;
+            }
+            long currentNanos = SystemClock.elapsedRealtimeNanos();
+            long deltaMs = (currentNanos - location.getElapsedRealtimeNanos()) / 1000000L;
+            return new LocationTime(location.getTime() + deltaMs, currentNanos);
+        }
+    }
+
+    @Override
     public boolean injectLocation(Location location) {
         mContext.enforceCallingPermission(android.Manifest.permission.LOCATION_HARDWARE,
                 "Location Hardware permission not granted to inject location");
@@ -2916,22 +2940,28 @@
         mContext.enforceCallingPermission(
                 android.Manifest.permission.LOCATION_HARDWARE,
                 "Location Hardware permission not granted to inject GNSS measurement corrections.");
-        if (!hasGnssPermissions(packageName) || mGnssMeasurementsProvider == null) {
+        if (!hasGnssPermissions(packageName)) {
             Slog.e(TAG, "Can not inject GNSS corrections due to no permission.");
-        } else {
-            mGnssMeasurementsProvider.injectGnssMeasurementCorrections(measurementCorrections);
+            return;
         }
+        if (mGnssMeasurementCorrectionsProvider == null) {
+            Slog.e(TAG, "Can not inject GNSS corrections. GNSS measurement corrections provider "
+                    + "not available.");
+            return;
+        }
+        mGnssMeasurementCorrectionsProvider.injectGnssMeasurementCorrections(
+                measurementCorrections);
     }
 
     @Override
-    public int getGnssCapabilities(String packageName) {
+    public long getGnssCapabilities(String packageName) {
         mContext.enforceCallingPermission(
                 android.Manifest.permission.LOCATION_HARDWARE,
-                "Location Hardware permission not granted to obrain GNSS chipset capabilities.");
-        if (!hasGnssPermissions(packageName) || mGnssMeasurementsProvider == null) {
+                "Location Hardware permission not granted to obtain GNSS chipset capabilities.");
+        if (!hasGnssPermissions(packageName) || mGnssMeasurementCorrectionsProvider == null) {
             return -1;
         }
-        return mGnssMeasurementsProvider.getGnssCapabilities();
+        return mGnssMeasurementCorrectionsProvider.getCapabilities();
     }
 
     @Override
diff --git a/services/core/java/com/android/server/NetworkManagementService.java b/services/core/java/com/android/server/NetworkManagementService.java
index 5582ad7..61a7182 100644
--- a/services/core/java/com/android/server/NetworkManagementService.java
+++ b/services/core/java/com/android/server/NetworkManagementService.java
@@ -39,7 +39,6 @@
 import static android.net.NetworkStats.UID_ALL;
 import static android.net.TrafficStats.UID_TETHERING;
 
-import static com.android.server.NetworkManagementService.NetdResponseCode.TtyListResult;
 import static com.android.server.NetworkManagementSocketTagger.PROP_QTAGUID_ENABLED;
 
 import android.annotation.NonNull;
@@ -62,6 +61,7 @@
 import android.net.RouteInfo;
 import android.net.TetherStatsParcel;
 import android.net.UidRange;
+import android.net.UidRangeParcel;
 import android.net.util.NetdService;
 import android.os.BatteryStats;
 import android.os.Binder;
@@ -69,7 +69,6 @@
 import android.os.IBinder;
 import android.os.INetworkActivityListener;
 import android.os.INetworkManagementService;
-import android.os.PowerManager;
 import android.os.Process;
 import android.os.RemoteCallbackList;
 import android.os.RemoteException;
@@ -80,6 +79,7 @@
 import android.os.SystemProperties;
 import android.os.Trace;
 import android.telephony.DataConnectionRealTimeInfo;
+import android.text.TextUtils;
 import android.util.Log;
 import android.util.Slog;
 import android.util.SparseBooleanArray;
@@ -110,13 +110,11 @@
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
-import java.util.concurrent.CountDownLatch;
 
 /**
  * @hide
  */
-public class NetworkManagementService extends INetworkManagementService.Stub
-        implements Watchdog.Monitor {
+public class NetworkManagementService extends INetworkManagementService.Stub {
 
     /**
      * Helper class that encapsulates NetworkManagementService dependencies and makes them
@@ -136,8 +134,6 @@
 
     private static final String TAG = "NetworkManagement";
     private static final boolean DBG = Log.isLoggable(TAG, Log.DEBUG);
-    private static final String NETD_TAG = "NetdConnector";
-    static final String NETD_SERVICE_NAME = "netd";
 
     private static final int MAX_UID_RANGES_PER_COMMAND = 10;
 
@@ -147,44 +143,6 @@
      */
     public static final String LIMIT_GLOBAL_ALERT = "globalAlert";
 
-    static class NetdResponseCode {
-        /* Keep in sync with system/netd/server/ResponseCode.h */
-        public static final int InterfaceListResult       = 110;
-        public static final int TetherInterfaceListResult = 111;
-        public static final int TetherDnsFwdTgtListResult = 112;
-        public static final int TtyListResult             = 113;
-        public static final int TetheringStatsListResult  = 114;
-
-        public static final int TetherStatusResult        = 210;
-        public static final int IpFwdStatusResult         = 211;
-        public static final int InterfaceGetCfgResult     = 213;
-        public static final int SoftapStatusResult        = 214;
-        public static final int InterfaceRxCounterResult  = 216;
-        public static final int InterfaceTxCounterResult  = 217;
-        public static final int QuotaCounterResult        = 220;
-        public static final int TetheringStatsResult      = 221;
-        public static final int DnsProxyQueryResult       = 222;
-        public static final int ClatdStatusResult         = 223;
-
-        public static final int InterfaceChange           = 600;
-        public static final int BandwidthControl          = 601;
-        public static final int InterfaceClassActivity    = 613;
-        public static final int InterfaceAddressChange    = 614;
-        public static final int InterfaceDnsServerInfo    = 615;
-        public static final int RouteChange               = 616;
-        public static final int StrictCleartext           = 617;
-    }
-
-    /**
-     * String indicating a softap command.
-     */
-    static final String SOFT_AP_COMMAND = "softap";
-
-    /**
-     * String passed back to netd connector indicating softap command success.
-     */
-    static final String SOFT_AP_COMMAND_SUCCESS = "Ok";
-
     static final int DAEMON_MSG_MOBILE_CONN_REAL_TIME_INFO = 1;
 
     static final boolean MODIFY_OPERATION_ADD = true;
@@ -195,12 +153,6 @@
      */
     private final Context mContext;
 
-    /**
-     * connector object for communicating with netd
-     */
-    private final NativeDaemonConnector mConnector;
-
-    private final Handler mFgHandler;
     private final Handler mDaemonHandler;
 
     private final SystemServices mServices;
@@ -211,9 +163,6 @@
 
     private IBatteryStats mBatteryStats;
 
-    private final Thread mThread;
-    private CountDownLatch mConnectedSignal = new CountDownLatch(1);
-
     private final RemoteCallbackList<INetworkManagementEventObserver> mObservers =
             new RemoteCallbackList<>();
 
@@ -305,32 +254,14 @@
      * @param context  Binder context for this service
      */
     private NetworkManagementService(
-            Context context, String socket, SystemServices services) {
+            Context context, SystemServices services) {
         mContext = context;
         mServices = services;
 
-        // make sure this is on the same looper as our NativeDaemonConnector for sync purposes
-        mFgHandler = new Handler(FgThread.get().getLooper());
-
-        // Don't need this wake lock, since we now have a time stamp for when
-        // the network actually went inactive.  (It might be nice to still do this,
-        // but I don't want to do it through the power manager because that pollutes the
-        // battery stats history with pointless noise.)
-        //PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
-        PowerManager.WakeLock wl = null; //pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, NETD_TAG);
-
-        mConnector = new NativeDaemonConnector(
-                new NetdCallbackReceiver(), socket, 10, NETD_TAG, 160, wl,
-                FgThread.get().getLooper());
-        mThread = new Thread(mConnector, NETD_TAG);
-
         mDaemonHandler = new Handler(FgThread.get().getLooper());
 
         mNetdUnsolicitedEventListener = new NetdUnsolicitedEventListener();
 
-        // Add ourself to the Watchdog monitors.
-        Watchdog.getInstance().addMonitor(this);
-
         mServices.registerLocalService(new LocalService());
 
         synchronized (mTetheringStatsProviders) {
@@ -340,25 +271,17 @@
 
     @VisibleForTesting
     NetworkManagementService() {
-        mConnector = null;
         mContext = null;
         mDaemonHandler = null;
-        mFgHandler = null;
-        mThread = null;
         mServices = null;
         mNetdUnsolicitedEventListener = null;
     }
 
-    static NetworkManagementService create(Context context, String socket, SystemServices services)
+    static NetworkManagementService create(Context context, SystemServices services)
             throws InterruptedException {
         final NetworkManagementService service =
-                new NetworkManagementService(context, socket, services);
-        final CountDownLatch connectedSignal = service.mConnectedSignal;
+                new NetworkManagementService(context, services);
         if (DBG) Slog.d(TAG, "Creating NetworkManagementService");
-        service.mThread.start();
-        if (DBG) Slog.d(TAG, "Awaiting socket connection");
-        connectedSignal.await();
-        if (DBG) Slog.d(TAG, "Connected");
         if (DBG) Slog.d(TAG, "Connecting native netd service");
         service.connectNativeNetdService();
         if (DBG) Slog.d(TAG, "Connected");
@@ -366,7 +289,7 @@
     }
 
     public static NetworkManagementService create(Context context) throws InterruptedException {
-        return create(context, NETD_SERVICE_NAME, new SystemServices());
+        return create(context, new SystemServices());
     }
 
     public void systemReady() {
@@ -810,212 +733,6 @@
     }
 
     //
-    // Netd Callback handling
-    //
-
-    private class NetdCallbackReceiver implements INativeDaemonConnectorCallbacks {
-        @Override
-        public void onDaemonConnected() {
-            Slog.i(TAG, "onDaemonConnected()");
-            // event is dispatched from internal NDC thread, so we prepare the
-            // daemon back on main thread.
-            if (mConnectedSignal != null) {
-                // The system is booting and we're connecting to netd for the first time.
-                mConnectedSignal.countDown();
-                mConnectedSignal = null;
-            } else {
-                // We're reconnecting to netd after the socket connection
-                // was interrupted (e.g., if it crashed).
-                mFgHandler.post(new Runnable() {
-                    @Override
-                    public void run() {
-                        connectNativeNetdService();
-                        prepareNativeDaemon();
-                    }
-                });
-            }
-        }
-
-        @Override
-        public boolean onCheckHoldWakeLock(int code) {
-            return code == NetdResponseCode.InterfaceClassActivity;
-        }
-
-        @Override
-        public boolean onEvent(int code, String raw, String[] cooked) {
-            String errorMessage = String.format("Invalid event from daemon (%s)", raw);
-            switch (code) {
-            case NetdResponseCode.InterfaceChange:
-                    /*
-                     * a network interface change occured
-                     * Format: "NNN Iface added <name>"
-                     *         "NNN Iface removed <name>"
-                     *         "NNN Iface changed <name> <up/down>"
-                     *         "NNN Iface linkstatus <name> <up/down>"
-                     */
-                    if (cooked.length < 4 || !cooked[1].equals("Iface")) {
-                        throw new IllegalStateException(errorMessage);
-                    }
-                    if (cooked[2].equals("added")) {
-                        notifyInterfaceAdded(cooked[3]);
-                        return true;
-                    } else if (cooked[2].equals("removed")) {
-                        notifyInterfaceRemoved(cooked[3]);
-                        return true;
-                    } else if (cooked[2].equals("changed") && cooked.length == 5) {
-                        notifyInterfaceStatusChanged(cooked[3], cooked[4].equals("up"));
-                        return true;
-                    } else if (cooked[2].equals("linkstate") && cooked.length == 5) {
-                        notifyInterfaceLinkStateChanged(cooked[3], cooked[4].equals("up"));
-                        return true;
-                    }
-                    throw new IllegalStateException(errorMessage);
-                    // break;
-            case NetdResponseCode.BandwidthControl:
-                    /*
-                     * Bandwidth control needs some attention
-                     * Format: "NNN limit alert <alertName> <ifaceName>"
-                     */
-                    if (cooked.length < 5 || !cooked[1].equals("limit")) {
-                        throw new IllegalStateException(errorMessage);
-                    }
-                    if (cooked[2].equals("alert")) {
-                        notifyLimitReached(cooked[3], cooked[4]);
-                        return true;
-                    }
-                    throw new IllegalStateException(errorMessage);
-                    // break;
-            case NetdResponseCode.InterfaceClassActivity:
-                    /*
-                     * An network interface class state changed (active/idle)
-                     * Format: "NNN IfaceClass <active/idle> <label>"
-                     */
-                    if (cooked.length < 4 || !cooked[1].equals("IfaceClass")) {
-                        throw new IllegalStateException(errorMessage);
-                    }
-                    long timestampNanos = 0;
-                    int processUid = -1;
-                    if (cooked.length >= 5) {
-                        try {
-                            timestampNanos = Long.parseLong(cooked[4]);
-                            if (cooked.length == 6) {
-                                processUid = Integer.parseInt(cooked[5]);
-                            }
-                        } catch(NumberFormatException ne) {}
-                    } else {
-                        timestampNanos = SystemClock.elapsedRealtimeNanos();
-                    }
-                    boolean isActive = cooked[2].equals("active");
-                    notifyInterfaceClassActivity(Integer.parseInt(cooked[3]),
-                            isActive, timestampNanos, processUid, false);
-                    return true;
-                    // break;
-            case NetdResponseCode.InterfaceAddressChange:
-                    /*
-                     * A network address change occurred
-                     * Format: "NNN Address updated <addr> <iface> <flags> <scope>"
-                     *         "NNN Address removed <addr> <iface> <flags> <scope>"
-                     */
-                    if (cooked.length < 7 || !cooked[1].equals("Address")) {
-                        throw new IllegalStateException(errorMessage);
-                    }
-
-                    String iface = cooked[4];
-                    LinkAddress address;
-                    try {
-                        int flags = Integer.parseInt(cooked[5]);
-                        int scope = Integer.parseInt(cooked[6]);
-                        address = new LinkAddress(cooked[3], flags, scope);
-                    } catch(NumberFormatException e) {     // Non-numeric lifetime or scope.
-                        throw new IllegalStateException(errorMessage, e);
-                    } catch(IllegalArgumentException e) {  // Malformed/invalid IP address.
-                        throw new IllegalStateException(errorMessage, e);
-                    }
-
-                    if (cooked[2].equals("updated")) {
-                        notifyAddressUpdated(iface, address);
-                    } else {
-                        notifyAddressRemoved(iface, address);
-                    }
-                    return true;
-                    // break;
-            case NetdResponseCode.InterfaceDnsServerInfo:
-                    /*
-                     * Information about available DNS servers has been received.
-                     * Format: "NNN DnsInfo servers <interface> <lifetime> <servers>"
-                     */
-                    long lifetime;  // Actually a 32-bit unsigned integer.
-
-                    if (cooked.length == 6 &&
-                        cooked[1].equals("DnsInfo") &&
-                        cooked[2].equals("servers")) {
-                        try {
-                            lifetime = Long.parseLong(cooked[4]);
-                        } catch (NumberFormatException e) {
-                            throw new IllegalStateException(errorMessage);
-                        }
-                        String[] servers = cooked[5].split(",");
-                        notifyInterfaceDnsServerInfo(cooked[3], lifetime, servers);
-                    }
-                    return true;
-                    // break;
-            case NetdResponseCode.RouteChange:
-                    /*
-                     * A route has been updated or removed.
-                     * Format: "NNN Route <updated|removed> <dst> [via <gateway] [dev <iface>]"
-                     */
-                    if (!cooked[1].equals("Route") || cooked.length < 6) {
-                        throw new IllegalStateException(errorMessage);
-                    }
-
-                    String via = null;
-                    String dev = null;
-                    boolean valid = true;
-                    for (int i = 4; (i + 1) < cooked.length && valid; i += 2) {
-                        if (cooked[i].equals("dev")) {
-                            if (dev == null) {
-                                dev = cooked[i+1];
-                            } else {
-                                valid = false;  // Duplicate interface.
-                            }
-                        } else if (cooked[i].equals("via")) {
-                            if (via == null) {
-                                via = cooked[i+1];
-                            } else {
-                                valid = false;  // Duplicate gateway.
-                            }
-                        } else {
-                            valid = false;      // Unknown syntax.
-                        }
-                    }
-                    if (valid) {
-                        try {
-                            // InetAddress.parseNumericAddress(null) inexplicably returns ::1.
-                            InetAddress gateway = null;
-                            if (via != null) gateway = InetAddress.parseNumericAddress(via);
-                            RouteInfo route = new RouteInfo(new IpPrefix(cooked[3]), gateway, dev);
-                            notifyRouteChange(cooked[2].equals("updated"), route);
-                            return true;
-                        } catch (IllegalArgumentException e) {}
-                    }
-                    throw new IllegalStateException(errorMessage);
-                    // break;
-            case NetdResponseCode.StrictCleartext:
-                final int uid = Integer.parseInt(cooked[1]);
-                final byte[] firstPacket = HexDump.hexStringToByteArray(cooked[2]);
-                try {
-                    ActivityManager.getService().notifyCleartextNetwork(uid, firstPacket);
-                } catch (RemoteException ignored) {
-                }
-                break;
-            default: break;
-            }
-            return false;
-        }
-    }
-
-
-    //
     // INetworkManagementService members
     //
     @Override
@@ -1028,6 +745,46 @@
         }
     }
 
+    /**
+     * Convert InterfaceConfiguration to InterfaceConfigurationParcel with given ifname.
+     */
+    private static InterfaceConfigurationParcel toStableParcel(InterfaceConfiguration cfg,
+            String iface) {
+        InterfaceConfigurationParcel cfgParcel = new InterfaceConfigurationParcel();
+        cfgParcel.ifName = iface;
+        String hwAddr = cfg.getHardwareAddress();
+        if (!TextUtils.isEmpty(hwAddr)) {
+            cfgParcel.hwAddr = hwAddr;
+        } else {
+            cfgParcel.hwAddr = "";
+        }
+        cfgParcel.ipv4Addr = cfg.getLinkAddress().getAddress().getHostAddress();
+        cfgParcel.prefixLength = cfg.getLinkAddress().getPrefixLength();
+        ArrayList<String> flags = new ArrayList<>();
+        for (String flag : cfg.getFlags()) {
+            flags.add(flag);
+        }
+        cfgParcel.flags = flags.toArray(new String[0]);
+
+        return cfgParcel;
+    }
+
+    /**
+     * Construct InterfaceConfiguration from InterfaceConfigurationParcel.
+     */
+    public static InterfaceConfiguration fromStableParcel(InterfaceConfigurationParcel p) {
+        InterfaceConfiguration cfg = new InterfaceConfiguration();
+        cfg.setHardwareAddress(p.hwAddr);
+
+        final InetAddress addr = NetworkUtils.numericToInetAddress(p.ipv4Addr);
+        cfg.setLinkAddress(new LinkAddress(addr, p.prefixLength));
+        for (String flag : p.flags) {
+            cfg.setFlag(flag);
+        }
+
+        return cfg;
+    }
+
     @Override
     public InterfaceConfiguration getInterfaceConfig(String iface) {
         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
@@ -1039,7 +796,7 @@
         }
 
         try {
-            final InterfaceConfiguration cfg = InterfaceConfiguration.fromParcel(result);
+            final InterfaceConfiguration cfg = fromStableParcel(result);
             return cfg;
         } catch (IllegalArgumentException iae) {
             throw new IllegalStateException("Invalid InterfaceConfigurationParcel", iae);
@@ -1054,7 +811,7 @@
             throw new IllegalStateException("Null LinkAddress given");
         }
 
-        final InterfaceConfigurationParcel cfgParcel = cfg.toParcel(iface);
+        final InterfaceConfigurationParcel cfgParcel = toStableParcel(cfg, iface);
 
         try {
             mNetdService.interfaceSetCfg(cfgParcel);
@@ -1397,42 +1154,6 @@
     }
 
     @Override
-    public String[] listTtys() {
-        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
-        try {
-            return NativeDaemonEvent.filterMessageList(
-                    mConnector.executeForList("list_ttys"), TtyListResult);
-        } catch (NativeDaemonConnectorException e) {
-            throw e.rethrowAsParcelableException();
-        }
-    }
-
-    @Override
-    public void attachPppd(
-            String tty, String localAddr, String remoteAddr, String dns1Addr, String dns2Addr) {
-        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
-        try {
-            mConnector.execute("pppd", "attach", tty,
-                    NetworkUtils.numericToInetAddress(localAddr).getHostAddress(),
-                    NetworkUtils.numericToInetAddress(remoteAddr).getHostAddress(),
-                    NetworkUtils.numericToInetAddress(dns1Addr).getHostAddress(),
-                    NetworkUtils.numericToInetAddress(dns2Addr).getHostAddress());
-        } catch (NativeDaemonConnectorException e) {
-            throw e.rethrowAsParcelableException();
-        }
-    }
-
-    @Override
-    public void detachPppd(String tty) {
-        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
-        try {
-            mConnector.execute("pppd", "detach", tty);
-        } catch (NativeDaemonConnectorException e) {
-            throw e.rethrowAsParcelableException();
-        }
-    }
-
-    @Override
     public void addIdleTimer(String iface, int timeout, final int type) {
         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
 
@@ -1718,12 +1439,27 @@
         }
     }
 
+    private static UidRangeParcel makeUidRangeParcel(int start, int stop) {
+        UidRangeParcel range = new UidRangeParcel();
+        range.start = start;
+        range.stop = stop;
+        return range;
+    }
+
+    private static UidRangeParcel[] toStableParcels(UidRange[] ranges) {
+        UidRangeParcel[] stableRanges = new UidRangeParcel[ranges.length];
+        for (int i = 0; i < ranges.length; i++) {
+            stableRanges[i] = makeUidRangeParcel(ranges[i].start, ranges[i].stop);
+        }
+        return stableRanges;
+    }
+
     @Override
     public void setAllowOnlyVpnForUids(boolean add, UidRange[] uidRanges)
             throws ServiceSpecificException {
         mContext.enforceCallingOrSelfPermission(NETWORK_STACK, TAG);
         try {
-            mNetdService.networkRejectNonSecureVpn(add, uidRanges);
+            mNetdService.networkRejectNonSecureVpn(add, toStableParcels(uidRanges));
         } catch (ServiceSpecificException e) {
             Log.w(TAG, "setAllowOnlyVpnForUids(" + add + ", " + Arrays.toString(uidRanges) + ")"
                     + ": netd command failed", e);
@@ -1892,7 +1628,7 @@
         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
 
         try {
-            mNetdService.networkAddUidRanges(netId, ranges);
+            mNetdService.networkAddUidRanges(netId, toStableParcels(ranges));
         } catch (RemoteException | ServiceSpecificException e) {
             throw new IllegalStateException(e);
         }
@@ -1902,7 +1638,7 @@
     public void removeVpnUidRanges(int netId, UidRange[] ranges) {
         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
         try {
-            mNetdService.networkRemoveUidRanges(netId, ranges);
+            mNetdService.networkRemoveUidRanges(netId, toStableParcels(ranges));
         } catch (RemoteException | ServiceSpecificException e) {
             throw new IllegalStateException(e);
         }
@@ -1940,7 +1676,7 @@
 
     private void closeSocketsForFirewallChainLocked(int chain, String chainName) {
         // UID ranges to close sockets on.
-        UidRange[] ranges;
+        UidRangeParcel[] ranges;
         // UID ranges whose sockets we won't touch.
         int[] exemptUids;
 
@@ -1948,10 +1684,10 @@
         if (DBG) Slog.d(TAG, "Closing sockets after enabling chain " + chainName);
         if (getFirewallType(chain) == FIREWALL_WHITELIST) {
             // Close all sockets on all non-system UIDs...
-            ranges = new UidRange[] {
+            ranges = new UidRangeParcel[] {
                 // TODO: is there a better way of finding all existing users? If so, we could
                 // specify their ranges here.
-                new UidRange(Process.FIRST_APPLICATION_UID, Integer.MAX_VALUE),
+                makeUidRangeParcel(Process.FIRST_APPLICATION_UID, Integer.MAX_VALUE),
             };
             // ... except for the UIDs that have allow rules.
             synchronized (mRulesLock) {
@@ -1978,11 +1714,11 @@
             // Close sockets for every UID that has a deny rule...
             synchronized (mRulesLock) {
                 final SparseIntArray rules = getUidFirewallRulesLR(chain);
-                ranges = new UidRange[rules.size()];
+                ranges = new UidRangeParcel[rules.size()];
                 for (int i = 0; i < ranges.length; i++) {
                     if (rules.valueAt(i) == FIREWALL_RULE_DENY) {
                         int uid = rules.keyAt(i);
-                        ranges[numUids] = new UidRange(uid, uid);
+                        ranges[numUids] = makeUidRangeParcel(uid, uid);
                         numUids++;
                     }
                 }
@@ -2238,22 +1974,10 @@
         }
     }
 
-    /** {@inheritDoc} */
-    @Override
-    public void monitor() {
-        if (mConnector != null) {
-            mConnector.monitor();
-        }
-    }
-
     @Override
     protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
         if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
 
-        pw.println("NetworkManagementService NativeDaemonConnector Log:");
-        mConnector.dump(fd, pw, args);
-        pw.println();
-
         pw.print("mMobileActivityFromRadio="); pw.print(mMobileActivityFromRadio);
                 pw.print(" mLastPowerStateFromRadio="); pw.println(mLastPowerStateFromRadio);
         pw.print("mNetworkActive="); pw.println(mNetworkActive);
diff --git a/services/core/java/com/android/server/SensorPrivacyService.java b/services/core/java/com/android/server/SensorPrivacyService.java
index 1cbcbe5..edeb049 100644
--- a/services/core/java/com/android/server/SensorPrivacyService.java
+++ b/services/core/java/com/android/server/SensorPrivacyService.java
@@ -18,20 +18,15 @@
 
 import static android.content.pm.PackageManager.PERMISSION_GRANTED;
 
-import android.app.ActivityManager;
 import android.content.Context;
 import android.hardware.ISensorPrivacyListener;
 import android.hardware.ISensorPrivacyManager;
-import android.location.LocationManager;
-import android.net.ConnectivityManager;
 import android.os.Environment;
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.Looper;
 import android.os.RemoteCallbackList;
 import android.os.RemoteException;
-import android.os.UserHandle;
-import android.provider.Settings;
 import android.util.ArrayMap;
 import android.util.AtomicFile;
 import android.util.Log;
@@ -277,8 +272,6 @@
                 }
             }
             mListeners.finishBroadcast();
-            // Handle the state of all sensors managed by this service.
-            SensorState.handleSensorPrivacyToggled(mContext, enabled);
         }
     }
 
@@ -306,121 +299,4 @@
             }
         }
     }
-
-    /**
-     * Maintains the state of the sensors when sensor privacy is enabled to return them to their
-     * original state when sensor privacy is disabled.
-     */
-    private static final class SensorState {
-
-        private static Object sLock = new Object();
-        @GuardedBy("sLock")
-        private static SensorState sPreviousState;
-
-        private boolean mAirplaneEnabled;
-        private boolean mLocationEnabled;
-
-        SensorState(boolean airplaneEnabled, boolean locationEnabled) {
-            mAirplaneEnabled = airplaneEnabled;
-            mLocationEnabled = locationEnabled;
-        }
-
-        public static void handleSensorPrivacyToggled(Context context, boolean enabled) {
-            synchronized (sLock) {
-                SensorState state;
-                if (enabled) {
-                    // if sensor privacy is being enabled then obtain the current state of the
-                    // sensors to be persisted and restored when sensor privacy is disabled.
-                    state = getCurrentSensorState(context);
-                } else {
-                    // else obtain the previous sensor state to be restored, first from the saved
-                    // state if available, otherwise attempt to read it from Settings.
-                    if (sPreviousState != null) {
-                        state = sPreviousState;
-                    } else {
-                        state = getPersistedSensorState(context);
-                    }
-                    // if the previous state is not available then return without attempting to
-                    // modify the sensor state.
-                    if (state == null) {
-                        return;
-                    }
-                }
-                // The SensorState represents the state of the sensor before sensor privacy was
-                // enabled; if airplane mode was not enabled then the state of airplane mode should
-                // be the same as the state of sensor privacy.
-                if (!state.mAirplaneEnabled) {
-                    setAirplaneMode(context, enabled);
-                }
-                // Similar to airplane mode the state of location should be the opposite of sensor
-                // privacy mode, if it was enabled when sensor privacy was enabled then it should be
-                // disabled. If location is disabled when sensor privacy is enabled then it will be
-                // left disabled when sensor privacy is disabled.
-                if (state.mLocationEnabled) {
-                    setLocationEnabled(context, !enabled);
-                }
-
-                // if sensor privacy is being enabled then persist the current state.
-                if (enabled) {
-                    sPreviousState = state;
-                    persistState(context, sPreviousState);
-                }
-            }
-        }
-
-        public static SensorState getCurrentSensorState(Context context) {
-            LocationManager locationManager = (LocationManager) context.getSystemService(
-                    Context.LOCATION_SERVICE);
-            boolean airplaneEnabled = Settings.Global.getInt(context.getContentResolver(),
-                    Settings.Global.AIRPLANE_MODE_ON, 0) != 0;
-            boolean locationEnabled = locationManager.isLocationEnabled();
-            return new SensorState(airplaneEnabled, locationEnabled);
-        }
-
-        public static void persistState(Context context, SensorState state) {
-            StringBuilder stateValue = new StringBuilder();
-            stateValue.append(state.mAirplaneEnabled
-                    ? Settings.Secure.MAINTAIN_AIRPLANE_MODE_AFTER_SP_DISABLED
-                    : Settings.Secure.DISABLE_AIRPLANE_MODE_AFTER_SP_DISABLED);
-            stateValue.append(",");
-            stateValue.append(
-                    state.mLocationEnabled ? Settings.Secure.REENABLE_LOCATION_AFTER_SP_DISABLED
-                            : Settings.Secure.MAINTAIN_LOCATION_AFTER_SP_DISABLED);
-            Settings.Secure.putString(context.getContentResolver(),
-                    Settings.Secure.SENSOR_PRIVACY_SENSOR_STATE, stateValue.toString());
-        }
-
-        public static SensorState getPersistedSensorState(Context context) {
-            String persistedState = Settings.Secure.getString(context.getContentResolver(),
-                    Settings.Secure.SENSOR_PRIVACY_SENSOR_STATE);
-            if (persistedState == null) {
-                Log.e(TAG, "The persisted sensor state could not be obtained from Settings");
-                return null;
-            }
-            String[] sensorStates = persistedState.split(",");
-            if (sensorStates.length < 2) {
-                Log.e(TAG, "The persisted sensor state does not contain the expected values: "
-                        + persistedState);
-                return null;
-            }
-            boolean airplaneEnabled = sensorStates[0].equals(
-                    Settings.Secure.MAINTAIN_AIRPLANE_MODE_AFTER_SP_DISABLED);
-            boolean locationEnabled = sensorStates[1].equals(
-                    Settings.Secure.REENABLE_LOCATION_AFTER_SP_DISABLED);
-            return new SensorState(airplaneEnabled, locationEnabled);
-        }
-
-        private static void setAirplaneMode(Context context, boolean enable) {
-            ConnectivityManager connectivityManager =
-                    (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
-            connectivityManager.setAirplaneMode(enable);
-        }
-
-        private static void setLocationEnabled(Context context, boolean enable) {
-            LocationManager locationManager = (LocationManager) context.getSystemService(
-                    Context.LOCATION_SERVICE);
-            locationManager.setLocationEnabledForUser(enable,
-                    UserHandle.of(ActivityManager.getCurrentUser()));
-        }
-    }
 }
diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java
index f416110..5bd0b89 100644
--- a/services/core/java/com/android/server/StorageManagerService.java
+++ b/services/core/java/com/android/server/StorageManagerService.java
@@ -21,6 +21,9 @@
 import static android.app.AppOpsManager.MODE_ALLOWED;
 import static android.app.AppOpsManager.OP_LEGACY_STORAGE;
 import static android.app.AppOpsManager.OP_REQUEST_INSTALL_PACKAGES;
+import static android.content.pm.PackageManager.FLAG_PERMISSION_HIDDEN;
+import static android.content.pm.PackageManager.FLAG_PERMISSION_SYSTEM_FIXED;
+import static android.content.pm.PackageManager.GET_PERMISSIONS;
 import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_AWARE;
 import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_UNAWARE;
 import static android.content.pm.PackageManager.MATCH_UNINSTALLED_PACKAGES;
@@ -74,6 +77,7 @@
 import android.database.ContentObserver;
 import android.net.Uri;
 import android.os.Binder;
+import android.os.Build;
 import android.os.DropBoxManager;
 import android.os.Environment;
 import android.os.Environment.UserEnvironment;
@@ -208,6 +212,13 @@
     private static final boolean ENABLE_LEGACY_GREYLIST = SystemProperties
             .getBoolean(StorageManager.PROP_LEGACY_GREYLIST, true);
 
+    /**
+     * If {@code 1}, enables the isolated storage feature. If {@code -1},
+     * disables the isolated storage feature. If {@code 0}, uses the default
+     * value from the build system.
+     */
+    private static final String ISOLATED_STORAGE_ENABLED = "isolated_storage_enabled";
+
     public static class Lifecycle extends SystemService {
         private StorageManagerService mStorageManagerService;
 
@@ -294,6 +305,19 @@
     private static final String ATTR_LAST_TRIM_MILLIS = "lastTrimMillis";
     private static final String ATTR_LAST_BENCH_MILLIS = "lastBenchMillis";
 
+    private static final String[] LEGACY_STORAGE_PERMISSIONS = {
+            Manifest.permission.READ_EXTERNAL_STORAGE,
+            Manifest.permission.WRITE_EXTERNAL_STORAGE
+    };
+
+    private static final String[] ALL_STORAGE_PERMISSIONS = {
+            Manifest.permission.READ_EXTERNAL_STORAGE,
+            Manifest.permission.WRITE_EXTERNAL_STORAGE,
+            Manifest.permission.READ_MEDIA_AUDIO,
+            Manifest.permission.READ_MEDIA_VIDEO,
+            Manifest.permission.READ_MEDIA_IMAGES
+    };
+
     private final AtomicFile mSettingsFile;
 
     /**
@@ -587,6 +611,7 @@
     private static final int H_RESET = 10;
     private static final int H_RUN_IDLE_MAINT = 11;
     private static final int H_ABORT_IDLE_MAINT = 12;
+    private static final int H_BOOT_COMPLETED = 13;
 
     class StorageManagerServiceHandler extends Handler {
         public StorageManagerServiceHandler(Looper looper) {
@@ -600,6 +625,10 @@
                     handleSystemReady();
                     break;
                 }
+                case H_BOOT_COMPLETED: {
+                    handleBootCompleted();
+                    break;
+                }
                 case H_DAEMON_CONNECTED: {
                     handleDaemonConnected();
                     break;
@@ -688,7 +717,7 @@
                     break;
                 }
                 case H_RESET: {
-                    resetIfReadyAndConnected();
+                    resetIfBootedAndConnected();
                     break;
                 }
                 case H_RUN_IDLE_MAINT: {
@@ -761,9 +790,6 @@
     }
 
     private void handleSystemReady() {
-        initIfReadyAndConnected();
-        resetIfReadyAndConnected();
-
         // Start scheduling nominally-daily fstrim operations
         MountServiceIdler.scheduleIdlePass(mContext);
 
@@ -797,7 +823,7 @@
                 }
             });
         // For now, simply clone property when it changes
-        DeviceConfig.addOnPropertyChangedListener(DeviceConfig.Storage.NAMESPACE,
+        DeviceConfig.addOnPropertyChangedListener(DeviceConfig.NAMESPACE_STORAGE,
                 mContext.getMainExecutor(), (namespace, name, value) -> {
                     refreshIsolatedStorageSettings();
                 });
@@ -837,8 +863,7 @@
         // Always copy value from newer DeviceConfig location
         Settings.Global.putString(mResolver,
                 Settings.Global.ISOLATED_STORAGE_REMOTE,
-                DeviceConfig.getProperty(DeviceConfig.Storage.NAMESPACE,
-                        DeviceConfig.Storage.ISOLATED_STORAGE_ENABLED));
+                DeviceConfig.getProperty(DeviceConfig.NAMESPACE_STORAGE, ISOLATED_STORAGE_ENABLED));
 
         final int local = Settings.Global.getInt(mContext.getContentResolver(),
                 Settings.Global.ISOLATED_STORAGE_LOCAL, 0);
@@ -910,10 +935,10 @@
         mVolumes.put(internal.id, internal);
     }
 
-    private void initIfReadyAndConnected() {
-        Slog.d(TAG, "Thinking about init, mSystemReady=" + mSystemReady
+    private void initIfBootedAndConnected() {
+        Slog.d(TAG, "Thinking about init, mBootCompleted=" + mBootCompleted
                 + ", mDaemonConnected=" + mDaemonConnected);
-        if (mSystemReady && mDaemonConnected
+        if (mBootCompleted && mDaemonConnected
                 && !StorageManager.isFileEncryptedNativeOnly()) {
             // When booting a device without native support, make sure that our
             // user directories are locked or unlocked based on the current
@@ -936,10 +961,10 @@
         }
     }
 
-    private void resetIfReadyAndConnected() {
-        Slog.d(TAG, "Thinking about reset, mSystemReady=" + mSystemReady
+    private void resetIfBootedAndConnected() {
+        Slog.d(TAG, "Thinking about reset, mBootCompleted=" + mBootCompleted
                 + ", mDaemonConnected=" + mDaemonConnected);
-        if (mSystemReady && mDaemonConnected) {
+        if (mBootCompleted && mDaemonConnected) {
             final List<UserInfo> users = mContext.getSystemService(UserManager.class).getUsers();
             killMediaProvider(users);
 
@@ -1098,8 +1123,8 @@
     }
 
     private void handleDaemonConnected() {
-        initIfReadyAndConnected();
-        resetIfReadyAndConnected();
+        initIfBootedAndConnected();
+        resetIfBootedAndConnected();
 
         // On an encrypted device we can't see system properties yet, so pull
         // the system locale out of the mount service.
@@ -1668,16 +1693,18 @@
 
         synchronized (mLock) {
             final boolean thisIsolatedStorage = StorageManager.hasIsolatedStorage();
-            if (mLastIsolatedStorage == thisIsolatedStorage) {
-                // Nothing changed since last boot; keep rolling forward
-                return;
-            } else if (thisIsolatedStorage) {
-                // This boot enables isolated storage; apply legacy behavior
-                applyLegacyStorage();
+            if (mLastIsolatedStorage != thisIsolatedStorage) {
+                if (thisIsolatedStorage) {
+                    // This boot enables isolated storage; apply legacy behavior
+                    applyLegacyStorage();
+                }
+
+                // Always remember the new state we just booted with
+                writeSettingsLocked();
             }
 
-            // Always remember the new state we just booted with
-            writeSettingsLocked();
+            // Execute special logic to recover certain devices
+            recoverFrom128872367();
         }
     }
 
@@ -1685,23 +1712,27 @@
      * If we're enabling isolated storage, we need to remember which existing
      * apps have already been using shared storage, and grant them legacy access
      * to keep them running smoothly.
+     *
+     * @see com.android.server.pm.permission.PermissionManagerService
+     *      #applyLegacyStoragePermissionModel
      */
     private void applyLegacyStorage() {
         final AppOpsManager appOps = mContext.getSystemService(AppOpsManager.class);
         final UserManagerInternal um = LocalServices.getService(UserManagerInternal.class);
         for (int userId : um.getUserIds()) {
+            final UserHandle user = UserHandle.of(userId);
             final PackageManager pm;
             try {
-                pm = mContext.createPackageContextAsUser(mContext.getPackageName(),
-                        0, UserHandle.of(userId)).getPackageManager();
+                pm = mContext.createPackageContextAsUser(mContext.getPackageName(), 0,
+                        user).getPackageManager();
             } catch (PackageManager.NameNotFoundException e) {
                 throw new RuntimeException(e);
             }
 
-            final List<PackageInfo> pkgs = pm.getPackagesHoldingPermissions(new String[] {
-                    android.Manifest.permission.READ_EXTERNAL_STORAGE,
-                    android.Manifest.permission.WRITE_EXTERNAL_STORAGE
-            }, MATCH_UNINSTALLED_PACKAGES | MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE);
+            final List<PackageInfo> pkgs = pm.getPackagesHoldingPermissions(
+                    LEGACY_STORAGE_PERMISSIONS,
+                    MATCH_UNINSTALLED_PACKAGES | MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE
+                            | GET_PERMISSIONS);
             for (PackageInfo pkg : pkgs) {
                 final int uid = pkg.applicationInfo.uid;
                 final String packageName = pkg.applicationInfo.packageName;
@@ -1714,8 +1745,28 @@
                 Log.d(TAG, "Found " + uid + " " + packageName
                         + " with granted storage access, last accessed " + lastAccess);
                 if (lastAccess > 0) {
-                    appOps.setMode(AppOpsManager.OP_LEGACY_STORAGE,
-                            uid, packageName, AppOpsManager.MODE_ALLOWED);
+                    appOps.setUidMode(AppOpsManager.OP_LEGACY_STORAGE, uid,
+                            AppOpsManager.MODE_ALLOWED);
+
+                    // Grandfather pre-Q app by granting all permissions and fixing them. The user
+                    // needs to uninstall the app to revoke the permissions.
+                    // TODO: Deal with shard Uids
+                    if (pkg.applicationInfo.targetSdkVersion >= Build.VERSION_CODES.Q) {
+                        for (String perm : ALL_STORAGE_PERMISSIONS) {
+                            if (ArrayUtils.contains(pkg.requestedPermissions, perm)) {
+                                pm.grantRuntimePermission(packageName, perm, user);
+
+                                int flags = FLAG_PERMISSION_SYSTEM_FIXED;
+                                if (!ArrayUtils.contains(LEGACY_STORAGE_PERMISSIONS, perm)) {
+                                    flags |= FLAG_PERMISSION_HIDDEN;
+                                }
+
+                                pm.updatePermissionFlags(perm, packageName,
+                                        FLAG_PERMISSION_SYSTEM_FIXED | FLAG_PERMISSION_HIDDEN,
+                                        flags, user);
+                            }
+                        }
+                    }
                 }
             }
         }
@@ -1734,6 +1785,69 @@
         return maxTime;
     }
 
+    /**
+     * In b/128872367 we lost all app-ops on devices in the wild. This logic
+     * attempts to detect and recover from this by granting
+     * {@link AppOpsManager#OP_LEGACY_STORAGE} to any apps installed before
+     * isolated storage was enabled.
+     */
+    private void recoverFrom128872367() {
+        // We're interested in packages that were installed or updated between
+        // 1/1/2014 and 12/17/2018
+        final long START_TIMESTAMP = 1388534400000L;
+        final long END_TIMESTAMP = 1545004800000L;
+
+        final PackageManager pm = mContext.getPackageManager();
+        final AppOpsManager appOps = mContext.getSystemService(AppOpsManager.class);
+        final UserManagerInternal um = LocalServices.getService(UserManagerInternal.class);
+
+        boolean activeDuringWindow = false;
+        List<PackageInfo> pendingHolders = new ArrayList<>();
+
+        for (int userId : um.getUserIds()) {
+            final List<PackageInfo> pkgs = pm.getInstalledPackagesAsUser(MATCH_UNINSTALLED_PACKAGES
+                    | MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE, userId);
+            for (PackageInfo pkg : pkgs) {
+                // Determine if any apps on this device had been installed or
+                // updated during the period where the feature was disabled
+                activeDuringWindow |= (pkg.firstInstallTime > START_TIMESTAMP
+                        && pkg.firstInstallTime < END_TIMESTAMP);
+                activeDuringWindow |= (pkg.lastUpdateTime > START_TIMESTAMP
+                        && pkg.lastUpdateTime < END_TIMESTAMP);
+
+                // This app should hold legacy op if they were installed before
+                // the cutoff; we only check the end boundary here so that
+                // include system apps, which are always installed on 1/1/2009.
+                final boolean shouldHold = (pkg.firstInstallTime < END_TIMESTAMP);
+                final boolean doesHold = (appOps.checkOpNoThrow(OP_LEGACY_STORAGE,
+                        pkg.applicationInfo.uid,
+                        pkg.applicationInfo.packageName) == MODE_ALLOWED);
+
+                if (doesHold) {
+                    Slog.d(TAG, "Found " + pkg + " holding legacy op; skipping recovery");
+                    return;
+                } else if (shouldHold) {
+                    Slog.d(TAG, "Found " + pkg + " that should hold legacy op");
+                    pendingHolders.add(pkg);
+                }
+            }
+        }
+
+        if (!activeDuringWindow) {
+            Slog.d(TAG, "No packages were active during the time window; skipping grants");
+            return;
+        }
+
+        // If we made it this far, nobody actually holds the legacy op, which
+        // means we probably lost the database, and we should grant the op to
+        // all the apps we identified.
+        for (PackageInfo pkg : pendingHolders) {
+            appOps.setMode(AppOpsManager.OP_LEGACY_STORAGE,
+                    pkg.applicationInfo.uid,
+                    pkg.applicationInfo.packageName, AppOpsManager.MODE_ALLOWED);
+        }
+    }
+
     private void systemReady() {
         LocalServices.getService(ActivityTaskManagerInternal.class)
                 .registerScreenObserver(this);
@@ -1744,6 +1858,12 @@
 
     private void bootCompleted() {
         mBootCompleted = true;
+        mHandler.obtainMessage(H_BOOT_COMPLETED).sendToTarget();
+    }
+
+    private void handleBootCompleted() {
+        initIfBootedAndConnected();
+        resetIfBootedAndConnected();
     }
 
     private String getDefaultPrimaryStorageUuid() {
@@ -3741,6 +3861,7 @@
                         case "com.facebook.katana": // b/123996076
                         case "jp.naver.line.android": // b/124767356
                         case "com.mxtech.videoplayer.ad": // b/124531483
+                        case "com.whatsapp": // b/124766614
                             return Zygote.MOUNT_EXTERNAL_LEGACY;
                     }
                 }
diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java
index d6fdbe3..26896f5 100644
--- a/services/core/java/com/android/server/TelephonyRegistry.java
+++ b/services/core/java/com/android/server/TelephonyRegistry.java
@@ -625,6 +625,11 @@
                 r.callingPackage = callingPackage;
                 r.callerUid = Binder.getCallingUid();
                 r.callerPid = Binder.getCallingPid();
+                if (r.subId != SubscriptionManager.INVALID_SUBSCRIPTION_ID && r.subId != subId) {
+                    throw new IllegalArgumentException(
+                            "PhoneStateListener cannot concurrently listen on multiple " +
+                                    "subscriptions. Previously registered on subId: " + r.subId);
+                }
                 // Legacy applications pass SubscriptionManager.DEFAULT_SUB_ID,
                 // force all illegal subId to SubscriptionManager.DEFAULT_SUB_ID
                 if (!SubscriptionManager.isValidSubscriptionId(subId)) {
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 7c6049c..97cc756 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -1273,11 +1273,13 @@
 
     static final class ProcessChangeItem {
         static final int CHANGE_ACTIVITIES = 1<<0;
+        static final int CHANGE_FOREGROUND_SERVICES = 1<<1;
         int changes;
         int uid;
         int pid;
         int processState;
         boolean foregroundActivities;
+        int foregroundServiceTypes;
     }
 
     static final class UidObserverRegistration {
@@ -2935,7 +2937,8 @@
             }
         }
         if (mContentCaptureService != null && (event == Event.ACTIVITY_PAUSED
-                || event == Event.ACTIVITY_RESUMED || event == Event.ACTIVITY_STOPPED)) {
+                || event == Event.ACTIVITY_RESUMED || event == Event.ACTIVITY_STOPPED
+                || event == Event.ACTIVITY_DESTROYED)) {
             mContentCaptureService.notifyActivityEvent(userId, activity, event);
         }
     }
@@ -3079,6 +3082,13 @@
                             observer.onForegroundActivitiesChanged(item.pid, item.uid,
                                     item.foregroundActivities);
                         }
+                        if ((item.changes & ProcessChangeItem.CHANGE_FOREGROUND_SERVICES) != 0) {
+                            if (DEBUG_PROCESS_OBSERVERS) Slog.i(TAG_PROCESS_OBSERVERS,
+                                    "FOREGROUND SERVICES CHANGED pid=" + item.pid + " uid="
+                                            + item.uid + ": " + item.foregroundServiceTypes);
+                            observer.onForegroundServicesChanged(item.pid, item.uid,
+                                    item.foregroundServiceTypes);
+                        }
                     }
                 } catch (RemoteException e) {
                 }
@@ -3093,6 +3103,47 @@
         }
     }
 
+    @GuardedBy("this")
+    ProcessChangeItem enqueueProcessChangeItemLocked(int uid, int pid) {
+        int i = mPendingProcessChanges.size()-1;
+        ActivityManagerService.ProcessChangeItem item = null;
+        while (i >= 0) {
+            item = mPendingProcessChanges.get(i);
+            if (item.pid == pid) {
+                if (DEBUG_PROCESS_OBSERVERS) Slog.i(TAG_PROCESS_OBSERVERS,
+                        "Re-using existing item: " + item);
+                break;
+            }
+            i--;
+        }
+
+        if (i < 0) {
+            // No existing item in pending changes; need a new one.
+            final int NA = mAvailProcessChanges.size();
+            if (NA > 0) {
+                item = mAvailProcessChanges.remove(NA-1);
+                if (DEBUG_PROCESS_OBSERVERS) Slog.i(TAG_PROCESS_OBSERVERS,
+                        "Retrieving available item: " + item);
+            } else {
+                item = new ActivityManagerService.ProcessChangeItem();
+                if (DEBUG_PROCESS_OBSERVERS) Slog.i(TAG_PROCESS_OBSERVERS,
+                        "Allocating new item: " + item);
+            }
+            item.changes = 0;
+            item.pid = pid;
+            item.uid = uid;
+            if (mPendingProcessChanges.size() == 0) {
+                if (DEBUG_PROCESS_OBSERVERS) Slog.i(TAG_PROCESS_OBSERVERS,
+                        "*** Enqueueing dispatch processes changed!");
+                mUiHandler.obtainMessage(DISPATCH_PROCESSES_CHANGED_UI_MSG)
+                        .sendToTarget();
+            }
+            mPendingProcessChanges.add(item);
+        }
+
+        return item;
+    }
+
     private void dispatchProcessDied(int pid, int uid) {
         int i = mProcessObservers.beginBroadcast();
         while (i > 0) {
@@ -5492,6 +5543,12 @@
         }
     }
 
+    private boolean isAppBad(ApplicationInfo info) {
+        synchronized (this) {
+            return mAppErrors.isBadProcessLocked(info);
+        }
+    }
+
     // NOTE: this is an internal method used by the OnShellCommand implementation only and should
     // be guarded by permission checking.
     int getUidState(int uid) {
@@ -16269,11 +16326,12 @@
     @GuardedBy("this")
     final void updateProcessForegroundLocked(ProcessRecord proc, boolean isForeground,
             int fgServiceTypes, boolean oomAdj) {
+        proc.setHasForegroundServices(isForeground, fgServiceTypes);
+
         final boolean hasFgServiceLocationType =
                 (fgServiceTypes & ServiceInfo.FOREGROUND_SERVICE_TYPE_LOCATION) != 0;
         if (isForeground != proc.hasForegroundServices()
                 || proc.hasLocationForegroundServices() != hasFgServiceLocationType) {
-            proc.setHasForegroundServices(isForeground, fgServiceTypes);
             ArrayList<ProcessRecord> curProcs = mForegroundPackages.get(proc.info.packageName,
                     proc.info.uid);
             if (isForeground) {
@@ -16302,6 +16360,13 @@
                 updateOomAdjLocked();
             }
         }
+
+        if (proc.getForegroundServiceTypes() != fgServiceTypes) {
+            proc.setReportedForegroundServiceTypes(fgServiceTypes);
+            ProcessChangeItem item = enqueueProcessChangeItemLocked(proc.info.uid, proc.pid);
+            item.changes = ProcessChangeItem.CHANGE_FOREGROUND_SERVICES;
+            item.foregroundServiceTypes = fgServiceTypes;
+        }
     }
 
     // TODO(b/111541062): This method is only used for updating OOM adjustments. We need to update
@@ -18078,6 +18143,11 @@
         }
 
         @Override
+        public boolean isAppBad(ApplicationInfo info) {
+            return ActivityManagerService.this.isAppBad(info);
+        }
+
+        @Override
         public void clearPendingBackup(int userId) {
             ActivityManagerService.this.clearPendingBackup(userId);
         }
@@ -18090,6 +18160,34 @@
         public void prepareForPossibleShutdown() {
             ActivityManagerService.this.prepareForPossibleShutdown();
         }
+
+        @Override
+        public boolean hasRunningForegroundService(int uid, int foregroundServicetype) {
+            synchronized (ActivityManagerService.this) {
+                for (int i = 0; i < mProcessList.mLruProcesses.size(); i++) {
+                    final ProcessRecord pr = mProcessList.mLruProcesses.get(i);
+                    if (pr.uid != uid) {
+                        continue;
+                    }
+
+                    if ((pr.getForegroundServiceTypes() & foregroundServicetype) != 0) {
+                        return true;
+                    }
+                }
+            }
+
+            return false;
+        }
+
+        @Override
+        public void registerProcessObserver(IProcessObserver processObserver) {
+            ActivityManagerService.this.registerProcessObserver(processObserver);
+        }
+
+        @Override
+        public void unregisterProcessObserver(IProcessObserver processObserver) {
+            ActivityManagerService.this.unregisterProcessObserver(processObserver);
+        }
     }
 
     long inputDispatchingTimedOut(int pid, final boolean aboveSystem, String reason) {
diff --git a/services/core/java/com/android/server/am/AppCompactor.java b/services/core/java/com/android/server/am/AppCompactor.java
index 438538f..9216343 100644
--- a/services/core/java/com/android/server/am/AppCompactor.java
+++ b/services/core/java/com/android/server/am/AppCompactor.java
@@ -230,11 +230,8 @@
      */
     @GuardedBy("mPhenotypeFlagLock")
     private void updateUseCompaction() {
-        String useCompactionFlag =
-                DeviceConfig.getProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
-                    KEY_USE_COMPACTION);
-        mUseCompaction = TextUtils.isEmpty(useCompactionFlag)
-                ? DEFAULT_USE_COMPACTION : Boolean.parseBoolean(useCompactionFlag);
+        mUseCompaction = DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
+                    KEY_USE_COMPACTION, DEFAULT_USE_COMPACTION);
         if (mUseCompaction && !mCompactionThread.isAlive()) {
             mCompactionThread.start();
             mCompactionHandler = new MemCompactionHandler();
@@ -243,28 +240,11 @@
 
     @GuardedBy("mPhenotypeFlagLock")
     private void updateCompactionActions() {
-        String compactAction1Flag =
-                DeviceConfig.getProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
-                        KEY_COMPACT_ACTION_1);
-        String compactAction2Flag =
-                DeviceConfig.getProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
-                        KEY_COMPACT_ACTION_2);
+        int compactAction1 = DeviceConfig.getInt(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
+                KEY_COMPACT_ACTION_1, DEFAULT_COMPACT_ACTION_1);
 
-        int compactAction1 = DEFAULT_COMPACT_ACTION_1;
-        try {
-            compactAction1 = TextUtils.isEmpty(compactAction1Flag)
-                    ? DEFAULT_COMPACT_ACTION_1 : Integer.parseInt(compactAction1Flag);
-        } catch (NumberFormatException e) {
-          // Do nothing, leave default.
-        }
-
-        int compactAction2 = DEFAULT_COMPACT_ACTION_2;
-        try {
-            compactAction2 = TextUtils.isEmpty(compactAction2Flag)
-                    ? DEFAULT_COMPACT_ACTION_2 : Integer.parseInt(compactAction2Flag);
-        } catch (NumberFormatException e) {
-            // Do nothing, leave default.
-        }
+        int compactAction2 = DeviceConfig.getInt(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
+                KEY_COMPACT_ACTION_2, DEFAULT_COMPACT_ACTION_2);
 
         mCompactActionSome = compactActionIntToString(compactAction1);
         mCompactActionFull = compactActionIntToString(compactAction2);
@@ -312,14 +292,8 @@
 
     @GuardedBy("mPhenotypeFlagLock")
     private void updateStatsdSampleRate() {
-        String sampleRateFlag = DeviceConfig.getProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
-                KEY_COMPACT_STATSD_SAMPLE_RATE);
-        try {
-            mStatsdSampleRate = TextUtils.isEmpty(sampleRateFlag)
-                    ? DEFAULT_STATSD_SAMPLE_RATE : Float.parseFloat(sampleRateFlag);
-        } catch (NumberFormatException e) {
-            mStatsdSampleRate = DEFAULT_STATSD_SAMPLE_RATE;
-        }
+        mStatsdSampleRate = DeviceConfig.getFloat(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
+                KEY_COMPACT_STATSD_SAMPLE_RATE, DEFAULT_STATSD_SAMPLE_RATE);
         mStatsdSampleRate = Math.min(1.0f, Math.max(0.0f, mStatsdSampleRate));
     }
 
diff --git a/services/core/java/com/android/server/am/AssistDataRequester.java b/services/core/java/com/android/server/am/AssistDataRequester.java
index 09df7e20..d8d6528 100644
--- a/services/core/java/com/android/server/am/AssistDataRequester.java
+++ b/services/core/java/com/android/server/am/AssistDataRequester.java
@@ -24,6 +24,7 @@
 
 import android.app.ActivityTaskManager;
 import android.app.AppOpsManager;
+import android.app.IActivityTaskManager;
 import android.app.IAssistDataReceiver;
 import android.content.Context;
 import android.graphics.Bitmap;
@@ -33,6 +34,7 @@
 import android.view.IWindowManager;
 
 import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.logging.MetricsLogger;
 
 import java.io.PrintWriter;
@@ -50,6 +52,8 @@
     public static final String KEY_RECEIVER_EXTRA_INDEX = "index";
 
     private IWindowManager mWindowManager;
+    @VisibleForTesting
+    public IActivityTaskManager mActivityTaskManager;
     private Context mContext;
     private AppOpsManager mAppOpsManager;
 
@@ -128,6 +132,7 @@
         mCallbacks = callbacks;
         mCallbacksLock = callbacksLock;
         mWindowManager = windowManager;
+        mActivityTaskManager = ActivityTaskManager.getService();
         mContext = context;
         mAppOpsManager = appOpsManager;
         mRequestStructureAppOps = requestStructureAppOps;
@@ -195,8 +200,7 @@
         // Ensure that the current activity supports assist data
         boolean isAssistDataAllowed = false;
         try {
-            isAssistDataAllowed =
-                    ActivityTaskManager.getService().isAssistDataAllowedOnCurrentActivity();
+            isAssistDataAllowed = mActivityTaskManager.isAssistDataAllowedOnCurrentActivity();
         } catch (RemoteException e) {
             // Should never happen
         }
@@ -222,9 +226,9 @@
                         receiverExtras.putInt(KEY_RECEIVER_EXTRA_INDEX, i);
                         receiverExtras.putInt(KEY_RECEIVER_EXTRA_COUNT, numActivities);
                         boolean result = requestAutofillData
-                                ? ActivityTaskManager.getService().requestAutofillData(this,
+                                ? mActivityTaskManager.requestAutofillData(this,
                                         receiverExtras, topActivity, 0 /* flags */)
-                                : ActivityTaskManager.getService().requestAssistContextExtras(
+                                : mActivityTaskManager.requestAssistContextExtras(
                                         ASSIST_CONTEXT_FULL, this, receiverExtras, topActivity,
                                         /* focused= */ i == 0, /* newSessionId= */ i == 0);
                         if (result) {
diff --git a/services/core/java/com/android/server/am/BaseErrorDialog.java b/services/core/java/com/android/server/am/BaseErrorDialog.java
index dc9a4bf..aabb587 100644
--- a/services/core/java/com/android/server/am/BaseErrorDialog.java
+++ b/services/core/java/com/android/server/am/BaseErrorDialog.java
@@ -16,6 +16,8 @@
 
 package com.android.server.am;
 
+import com.android.internal.R;
+
 import android.app.AlertDialog;
 import android.content.Context;
 import android.os.Handler;
@@ -24,8 +26,6 @@
 import android.view.WindowManager;
 import android.widget.Button;
 
-import com.android.internal.R;
-
 public class BaseErrorDialog extends AlertDialog {
     private static final int ENABLE_BUTTONS = 0;
     private static final int DISABLE_BUTTONS = 1;
@@ -36,7 +36,7 @@
         super(context, com.android.internal.R.style.Theme_DeviceDefault_Dialog_AppError);
         context.assertRuntimeOverlayThemable();
 
-        getWindow().setType(WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY);
+        getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
         getWindow().setFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM,
                 WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM);
         WindowManager.LayoutParams attrs = getWindow().getAttributes();
diff --git a/services/core/java/com/android/server/am/HealthStatsBatteryStatsWriter.java b/services/core/java/com/android/server/am/HealthStatsBatteryStatsWriter.java
index c2f1890..1c916e9 100644
--- a/services/core/java/com/android/server/am/HealthStatsBatteryStatsWriter.java
+++ b/services/core/java/com/android/server/am/HealthStatsBatteryStatsWriter.java
@@ -17,7 +17,7 @@
 package com.android.server.am;
 
 import android.os.BatteryStats;
-import static android.os.BatteryStats.STATS_SINCE_UNPLUGGED;
+import static android.os.BatteryStats.STATS_SINCE_CHARGED;
 import android.os.PowerManager;
 import android.os.SystemClock;
 import android.os.health.HealthKeys;
@@ -63,20 +63,20 @@
 
         // MEASUREMENT_REALTIME_BATTERY_MS
         uidWriter.addMeasurement(UidHealthStats.MEASUREMENT_REALTIME_BATTERY_MS,
-                bs.computeBatteryRealtime(mNowRealtimeMs*1000, STATS_SINCE_UNPLUGGED)/1000);
+                bs.computeBatteryRealtime(mNowRealtimeMs*1000, STATS_SINCE_CHARGED)/1000);
 
         // MEASUREMENT_UPTIME_BATTERY_MS
         uidWriter.addMeasurement(UidHealthStats.MEASUREMENT_UPTIME_BATTERY_MS,
-                bs.computeBatteryUptime(mNowUptimeMs*1000, STATS_SINCE_UNPLUGGED)/1000);
+                bs.computeBatteryUptime(mNowUptimeMs*1000, STATS_SINCE_CHARGED)/1000);
 
         // MEASUREMENT_REALTIME_SCREEN_OFF_BATTERY_MS
         uidWriter.addMeasurement(UidHealthStats.MEASUREMENT_REALTIME_SCREEN_OFF_BATTERY_MS,
                 bs.computeBatteryScreenOffRealtime(
-                    mNowRealtimeMs*1000, STATS_SINCE_UNPLUGGED)/1000);
+                    mNowRealtimeMs*1000, STATS_SINCE_CHARGED)/1000);
 
         // MEASUREMENT_UPTIME_SCREEN_OFF_BATTERY_MS
         uidWriter.addMeasurement(UidHealthStats.MEASUREMENT_UPTIME_SCREEN_OFF_BATTERY_MS,
-                bs.computeBatteryScreenOffUptime(mNowUptimeMs*1000, STATS_SINCE_UNPLUGGED)/1000);
+                bs.computeBatteryScreenOffUptime(mNowUptimeMs*1000, STATS_SINCE_CHARGED)/1000);
 
         //
         // Now on to the real per-uid stats...
@@ -161,75 +161,75 @@
         if (controller != null) {
             // MEASUREMENT_WIFI_IDLE_MS
             uidWriter.addMeasurement(UidHealthStats.MEASUREMENT_WIFI_IDLE_MS,
-                    controller.getIdleTimeCounter().getCountLocked(STATS_SINCE_UNPLUGGED));
+                    controller.getIdleTimeCounter().getCountLocked(STATS_SINCE_CHARGED));
             // MEASUREMENT_WIFI_RX_MS
             uidWriter.addMeasurement(UidHealthStats.MEASUREMENT_WIFI_RX_MS,
-                    controller.getRxTimeCounter().getCountLocked(STATS_SINCE_UNPLUGGED));
+                    controller.getRxTimeCounter().getCountLocked(STATS_SINCE_CHARGED));
             // MEASUREMENT_WIFI_TX_MS
             sum = 0;
             for (final BatteryStats.LongCounter counter: controller.getTxTimeCounters()) {
-                sum += counter.getCountLocked(STATS_SINCE_UNPLUGGED);
+                sum += counter.getCountLocked(STATS_SINCE_CHARGED);
             }
             uidWriter.addMeasurement(UidHealthStats.MEASUREMENT_WIFI_TX_MS, sum);
             // MEASUREMENT_WIFI_POWER_MAMS
             uidWriter.addMeasurement(UidHealthStats.MEASUREMENT_WIFI_POWER_MAMS,
-                    controller.getPowerCounter().getCountLocked(STATS_SINCE_UNPLUGGED));
+                    controller.getPowerCounter().getCountLocked(STATS_SINCE_CHARGED));
         }
 
         controller = uid.getBluetoothControllerActivity();
         if (controller != null) {
             // MEASUREMENT_BLUETOOTH_IDLE_MS
             uidWriter.addMeasurement(UidHealthStats.MEASUREMENT_BLUETOOTH_IDLE_MS,
-                    controller.getIdleTimeCounter().getCountLocked(STATS_SINCE_UNPLUGGED));
+                    controller.getIdleTimeCounter().getCountLocked(STATS_SINCE_CHARGED));
             // MEASUREMENT_BLUETOOTH_RX_MS
             uidWriter.addMeasurement(UidHealthStats.MEASUREMENT_BLUETOOTH_RX_MS,
-                    controller.getRxTimeCounter().getCountLocked(STATS_SINCE_UNPLUGGED));
+                    controller.getRxTimeCounter().getCountLocked(STATS_SINCE_CHARGED));
             // MEASUREMENT_BLUETOOTH_TX_MS
             sum = 0;
             for (final BatteryStats.LongCounter counter: controller.getTxTimeCounters()) {
-                sum += counter.getCountLocked(STATS_SINCE_UNPLUGGED);
+                sum += counter.getCountLocked(STATS_SINCE_CHARGED);
             }
             uidWriter.addMeasurement(UidHealthStats.MEASUREMENT_BLUETOOTH_TX_MS, sum);
             // MEASUREMENT_BLUETOOTH_POWER_MAMS
             uidWriter.addMeasurement(UidHealthStats.MEASUREMENT_BLUETOOTH_POWER_MAMS,
-                    controller.getPowerCounter().getCountLocked(STATS_SINCE_UNPLUGGED));
+                    controller.getPowerCounter().getCountLocked(STATS_SINCE_CHARGED));
         }
 
         controller = uid.getModemControllerActivity();
         if (controller != null) {
             // MEASUREMENT_MOBILE_IDLE_MS
             uidWriter.addMeasurement(UidHealthStats.MEASUREMENT_MOBILE_IDLE_MS,
-                    controller.getIdleTimeCounter().getCountLocked(STATS_SINCE_UNPLUGGED));
+                    controller.getIdleTimeCounter().getCountLocked(STATS_SINCE_CHARGED));
             // MEASUREMENT_MOBILE_RX_MS
             uidWriter.addMeasurement(UidHealthStats.MEASUREMENT_MOBILE_RX_MS,
-                    controller.getRxTimeCounter().getCountLocked(STATS_SINCE_UNPLUGGED));
+                    controller.getRxTimeCounter().getCountLocked(STATS_SINCE_CHARGED));
             // MEASUREMENT_MOBILE_TX_MS
             sum = 0;
             for (final BatteryStats.LongCounter counter: controller.getTxTimeCounters()) {
-                sum += counter.getCountLocked(STATS_SINCE_UNPLUGGED);
+                sum += counter.getCountLocked(STATS_SINCE_CHARGED);
             }
             uidWriter.addMeasurement(UidHealthStats.MEASUREMENT_MOBILE_TX_MS, sum);
             // MEASUREMENT_MOBILE_POWER_MAMS
             uidWriter.addMeasurement(UidHealthStats.MEASUREMENT_MOBILE_POWER_MAMS,
-                    controller.getPowerCounter().getCountLocked(STATS_SINCE_UNPLUGGED));
+                    controller.getPowerCounter().getCountLocked(STATS_SINCE_CHARGED));
         }
 
         // MEASUREMENT_WIFI_RUNNING_MS
         uidWriter.addMeasurement(UidHealthStats.MEASUREMENT_WIFI_RUNNING_MS,
-                uid.getWifiRunningTime(mNowRealtimeMs*1000, STATS_SINCE_UNPLUGGED)/1000);
+                uid.getWifiRunningTime(mNowRealtimeMs*1000, STATS_SINCE_CHARGED)/1000);
 
         // MEASUREMENT_WIFI_FULL_LOCK_MS
         uidWriter.addMeasurement(UidHealthStats.MEASUREMENT_WIFI_FULL_LOCK_MS,
-                uid.getFullWifiLockTime(mNowRealtimeMs*1000, STATS_SINCE_UNPLUGGED)/1000);
+                uid.getFullWifiLockTime(mNowRealtimeMs*1000, STATS_SINCE_CHARGED)/1000);
 
         // TIMER_WIFI_SCAN
         uidWriter.addTimer(UidHealthStats.TIMER_WIFI_SCAN,
-                uid.getWifiScanCount(STATS_SINCE_UNPLUGGED),
-                uid.getWifiScanTime(mNowRealtimeMs*1000, STATS_SINCE_UNPLUGGED)/1000);
+                uid.getWifiScanCount(STATS_SINCE_CHARGED),
+                uid.getWifiScanTime(mNowRealtimeMs*1000, STATS_SINCE_CHARGED)/1000);
 
         // MEASUREMENT_WIFI_MULTICAST_MS
         uidWriter.addMeasurement(UidHealthStats.MEASUREMENT_WIFI_MULTICAST_MS,
-                uid.getWifiMulticastTime(mNowRealtimeMs*1000, STATS_SINCE_UNPLUGGED)/1000);
+                uid.getWifiMulticastTime(mNowRealtimeMs*1000, STATS_SINCE_CHARGED)/1000);
 
         // TIMER_AUDIO
         addTimer(uidWriter, UidHealthStats.TIMER_AUDIO, uid.getAudioTurnedOnTimer());
@@ -280,90 +280,90 @@
         // MEASUREMENT_OTHER_USER_ACTIVITY_COUNT
         uidWriter.addMeasurement(UidHealthStats.MEASUREMENT_OTHER_USER_ACTIVITY_COUNT,
                 uid.getUserActivityCount(PowerManager.USER_ACTIVITY_EVENT_OTHER,
-                    STATS_SINCE_UNPLUGGED));
+                    STATS_SINCE_CHARGED));
 
         // MEASUREMENT_BUTTON_USER_ACTIVITY_COUNT
         uidWriter.addMeasurement(UidHealthStats.MEASUREMENT_BUTTON_USER_ACTIVITY_COUNT,
                 uid.getUserActivityCount(PowerManager.USER_ACTIVITY_EVENT_BUTTON,
-                    STATS_SINCE_UNPLUGGED));
+                    STATS_SINCE_CHARGED));
 
         // MEASUREMENT_TOUCH_USER_ACTIVITY_COUNT
         uidWriter.addMeasurement(UidHealthStats.MEASUREMENT_TOUCH_USER_ACTIVITY_COUNT,
                 uid.getUserActivityCount(PowerManager.USER_ACTIVITY_EVENT_TOUCH,
-                    STATS_SINCE_UNPLUGGED));
+                    STATS_SINCE_CHARGED));
 
         // MEASUREMENT_MOBILE_RX_BYTES
         uidWriter.addMeasurement(UidHealthStats.MEASUREMENT_MOBILE_RX_BYTES,
                 uid.getNetworkActivityBytes(BatteryStats.NETWORK_MOBILE_RX_DATA,
-                    STATS_SINCE_UNPLUGGED));
+                    STATS_SINCE_CHARGED));
 
         // MEASUREMENT_MOBILE_TX_BYTES
         uidWriter.addMeasurement(UidHealthStats.MEASUREMENT_MOBILE_TX_BYTES,
                 uid.getNetworkActivityBytes(BatteryStats.NETWORK_MOBILE_TX_DATA,
-                    STATS_SINCE_UNPLUGGED));
+                    STATS_SINCE_CHARGED));
 
         // MEASUREMENT_WIFI_RX_BYTES
         uidWriter.addMeasurement(UidHealthStats.MEASUREMENT_WIFI_RX_BYTES,
                 uid.getNetworkActivityBytes(BatteryStats.NETWORK_WIFI_RX_DATA,
-                    STATS_SINCE_UNPLUGGED));
+                    STATS_SINCE_CHARGED));
 
         // MEASUREMENT_WIFI_TX_BYTES
         uidWriter.addMeasurement(UidHealthStats.MEASUREMENT_WIFI_TX_BYTES,
                 uid.getNetworkActivityBytes(BatteryStats.NETWORK_WIFI_TX_DATA,
-                    STATS_SINCE_UNPLUGGED));
+                    STATS_SINCE_CHARGED));
 
         // MEASUREMENT_BLUETOOTH_RX_BYTES
         uidWriter.addMeasurement(UidHealthStats.MEASUREMENT_BLUETOOTH_RX_BYTES,
                 uid.getNetworkActivityBytes(BatteryStats.NETWORK_BT_RX_DATA,
-                    STATS_SINCE_UNPLUGGED));
+                    STATS_SINCE_CHARGED));
 
         // MEASUREMENT_BLUETOOTH_TX_BYTES
         uidWriter.addMeasurement(UidHealthStats.MEASUREMENT_BLUETOOTH_TX_BYTES,
                 uid.getNetworkActivityBytes(BatteryStats.NETWORK_BT_TX_DATA,
-                    STATS_SINCE_UNPLUGGED));
+                    STATS_SINCE_CHARGED));
 
         // MEASUREMENT_MOBILE_RX_PACKETS
         uidWriter.addMeasurement(UidHealthStats.MEASUREMENT_MOBILE_RX_PACKETS,
                 uid.getNetworkActivityPackets(BatteryStats.NETWORK_MOBILE_RX_DATA,
-                    STATS_SINCE_UNPLUGGED));
+                    STATS_SINCE_CHARGED));
 
         // MEASUREMENT_MOBILE_TX_PACKETS
         uidWriter.addMeasurement(UidHealthStats.MEASUREMENT_MOBILE_TX_PACKETS,
                 uid.getNetworkActivityPackets(BatteryStats.NETWORK_MOBILE_TX_DATA,
-                    STATS_SINCE_UNPLUGGED));
+                    STATS_SINCE_CHARGED));
 
         // MEASUREMENT_WIFI_RX_PACKETS
         uidWriter.addMeasurement(UidHealthStats.MEASUREMENT_WIFI_RX_PACKETS,
                 uid.getNetworkActivityPackets(BatteryStats.NETWORK_WIFI_RX_DATA,
-                    STATS_SINCE_UNPLUGGED));
+                    STATS_SINCE_CHARGED));
 
         // MEASUREMENT_WIFI_TX_PACKETS
         uidWriter.addMeasurement(UidHealthStats.MEASUREMENT_WIFI_TX_PACKETS,
                 uid.getNetworkActivityPackets(BatteryStats.NETWORK_WIFI_TX_DATA,
-                    STATS_SINCE_UNPLUGGED));
+                    STATS_SINCE_CHARGED));
 
         // MEASUREMENT_BLUETOOTH_RX_PACKETS
         uidWriter.addMeasurement(UidHealthStats.MEASUREMENT_BLUETOOTH_RX_PACKETS,
                 uid.getNetworkActivityPackets(BatteryStats.NETWORK_BT_RX_DATA,
-                    STATS_SINCE_UNPLUGGED));
+                    STATS_SINCE_CHARGED));
 
         // MEASUREMENT_BLUETOOTH_TX_PACKETS
         uidWriter.addMeasurement(UidHealthStats.MEASUREMENT_BLUETOOTH_TX_PACKETS,
                 uid.getNetworkActivityPackets(BatteryStats.NETWORK_BT_TX_DATA,
-                    STATS_SINCE_UNPLUGGED));
+                    STATS_SINCE_CHARGED));
 
         // TIMER_MOBILE_RADIO_ACTIVE
         uidWriter.addTimer(UidHealthStats.TIMER_MOBILE_RADIO_ACTIVE,
-                uid.getMobileRadioActiveCount(STATS_SINCE_UNPLUGGED),
-                uid.getMobileRadioActiveTime(STATS_SINCE_UNPLUGGED));
+                uid.getMobileRadioActiveCount(STATS_SINCE_CHARGED),
+                uid.getMobileRadioActiveTime(STATS_SINCE_CHARGED));
 
         // MEASUREMENT_USER_CPU_TIME_MS
         uidWriter.addMeasurement(UidHealthStats.MEASUREMENT_USER_CPU_TIME_MS,
-                uid.getUserCpuTimeUs(STATS_SINCE_UNPLUGGED)/1000);
+                uid.getUserCpuTimeUs(STATS_SINCE_CHARGED)/1000);
 
         // MEASUREMENT_SYSTEM_CPU_TIME_MS
         uidWriter.addMeasurement(UidHealthStats.MEASUREMENT_SYSTEM_CPU_TIME_MS,
-                uid.getSystemCpuTimeUs(STATS_SINCE_UNPLUGGED)/1000);
+                uid.getSystemCpuTimeUs(STATS_SINCE_CHARGED)/1000);
 
         // MEASUREMENT_CPU_POWER_MAMS
         uidWriter.addMeasurement(UidHealthStats.MEASUREMENT_CPU_POWER_MAMS, 0);
@@ -393,27 +393,27 @@
     public void writeProc(HealthStatsWriter procWriter, BatteryStats.Uid.Proc proc) {
         // MEASUREMENT_USER_TIME_MS
         procWriter.addMeasurement(ProcessHealthStats.MEASUREMENT_USER_TIME_MS,
-                proc.getUserTime(STATS_SINCE_UNPLUGGED));
+                proc.getUserTime(STATS_SINCE_CHARGED));
 
         // MEASUREMENT_SYSTEM_TIME_MS
         procWriter.addMeasurement(ProcessHealthStats.MEASUREMENT_SYSTEM_TIME_MS,
-                proc.getSystemTime(STATS_SINCE_UNPLUGGED));
+                proc.getSystemTime(STATS_SINCE_CHARGED));
 
         // MEASUREMENT_STARTS_COUNT
         procWriter.addMeasurement(ProcessHealthStats.MEASUREMENT_STARTS_COUNT,
-                proc.getStarts(STATS_SINCE_UNPLUGGED));
+                proc.getStarts(STATS_SINCE_CHARGED));
 
         // MEASUREMENT_CRASHES_COUNT
         procWriter.addMeasurement(ProcessHealthStats.MEASUREMENT_CRASHES_COUNT,
-                proc.getNumCrashes(STATS_SINCE_UNPLUGGED));
+                proc.getNumCrashes(STATS_SINCE_CHARGED));
 
         // MEASUREMENT_ANR_COUNT
         procWriter.addMeasurement(ProcessHealthStats.MEASUREMENT_ANR_COUNT,
-                proc.getNumAnrs(STATS_SINCE_UNPLUGGED));
+                proc.getNumAnrs(STATS_SINCE_CHARGED));
 
         // MEASUREMENT_FOREGROUND_MS
         procWriter.addMeasurement(ProcessHealthStats.MEASUREMENT_FOREGROUND_MS,
-                proc.getForegroundTime(STATS_SINCE_UNPLUGGED));
+                proc.getForegroundTime(STATS_SINCE_CHARGED));
     }
 
     /**
@@ -434,7 +434,7 @@
             final BatteryStats.Counter counter = entry.getValue();
             if (counter != null) {
                 pkgWriter.addMeasurements(PackageHealthStats.MEASUREMENTS_WAKEUP_ALARMS_COUNT,
-                        entry.getKey(), counter.getCountLocked(STATS_SINCE_UNPLUGGED));
+                        entry.getKey(), counter.getCountLocked(STATS_SINCE_CHARGED));
             }
         }
     }
@@ -445,11 +445,11 @@
     public void writeServ(HealthStatsWriter servWriter, BatteryStats.Uid.Pkg.Serv serv) {
         // MEASUREMENT_START_SERVICE_COUNT
         servWriter.addMeasurement(ServiceHealthStats.MEASUREMENT_START_SERVICE_COUNT,
-                serv.getStarts(STATS_SINCE_UNPLUGGED));
+                serv.getStarts(STATS_SINCE_CHARGED));
 
         // MEASUREMENT_LAUNCH_COUNT
         servWriter.addMeasurement(ServiceHealthStats.MEASUREMENT_LAUNCH_COUNT,
-                serv.getLaunches(STATS_SINCE_UNPLUGGED));
+                serv.getLaunches(STATS_SINCE_CHARGED));
     }
 
     /**
@@ -457,8 +457,8 @@
      */
     private void addTimer(HealthStatsWriter writer, int key, BatteryStats.Timer timer) {
         if (timer != null) {
-            writer.addTimer(key, timer.getCountLocked(STATS_SINCE_UNPLUGGED),
-                    timer.getTotalTimeLocked(mNowRealtimeMs*1000, STATS_SINCE_UNPLUGGED) / 1000);
+            writer.addTimer(key, timer.getCountLocked(STATS_SINCE_CHARGED),
+                    timer.getTotalTimeLocked(mNowRealtimeMs*1000, STATS_SINCE_CHARGED) / 1000);
         }
     }
 
@@ -468,8 +468,8 @@
     private void addTimers(HealthStatsWriter writer, int key, String name,
             BatteryStats.Timer timer) {
         if (timer != null) {
-            writer.addTimers(key, name, new TimerStat(timer.getCountLocked(STATS_SINCE_UNPLUGGED),
-                    timer.getTotalTimeLocked(mNowRealtimeMs*1000, STATS_SINCE_UNPLUGGED) / 1000));
+            writer.addTimers(key, name, new TimerStat(timer.getCountLocked(STATS_SINCE_CHARGED),
+                    timer.getTotalTimeLocked(mNowRealtimeMs*1000, STATS_SINCE_CHARGED) / 1000));
         }
     }
 }
diff --git a/services/core/java/com/android/server/am/MemoryStatUtil.java b/services/core/java/com/android/server/am/MemoryStatUtil.java
index 0d03580..9cda89a 100644
--- a/services/core/java/com/android/server/am/MemoryStatUtil.java
+++ b/services/core/java/com/android/server/am/MemoryStatUtil.java
@@ -166,17 +166,11 @@
         }
 
         final MemoryStat memoryStat = new MemoryStat();
-        Matcher m;
-        m = PGFAULT.matcher(memoryStatContents);
-        memoryStat.pgfault = m.find() ? Long.parseLong(m.group(1)) : 0;
-        m = PGMAJFAULT.matcher(memoryStatContents);
-        memoryStat.pgmajfault = m.find() ? Long.parseLong(m.group(1)) : 0;
-        m = RSS_IN_BYTES.matcher(memoryStatContents);
-        memoryStat.rssInBytes = m.find() ? Long.parseLong(m.group(1)) : 0;
-        m = CACHE_IN_BYTES.matcher(memoryStatContents);
-        memoryStat.cacheInBytes = m.find() ? Long.parseLong(m.group(1)) : 0;
-        m = SWAP_IN_BYTES.matcher(memoryStatContents);
-        memoryStat.swapInBytes = m.find() ? Long.parseLong(m.group(1)) : 0;
+        memoryStat.pgfault = tryParseLong(PGFAULT, memoryStatContents);
+        memoryStat.pgmajfault = tryParseLong(PGMAJFAULT, memoryStatContents);
+        memoryStat.rssInBytes = tryParseLong(RSS_IN_BYTES, memoryStatContents);
+        memoryStat.cacheInBytes = tryParseLong(CACHE_IN_BYTES, memoryStatContents);
+        memoryStat.swapInBytes = tryParseLong(SWAP_IN_BYTES, memoryStatContents);
         return memoryStat;
     }
 
@@ -217,9 +211,8 @@
         if (procStatusContents == null || procStatusContents.isEmpty()) {
             return 0;
         }
-        Matcher m = RSS_HIGH_WATERMARK_IN_BYTES.matcher(procStatusContents);
         // Convert value read from /proc/pid/status from kilobytes to bytes.
-        return m.find() ? Long.parseLong(m.group(1)) * BYTES_IN_KILOBYTE : 0;
+        return tryParseLong(RSS_HIGH_WATERMARK_IN_BYTES, procStatusContents) * BYTES_IN_KILOBYTE;
     }
 
 
@@ -249,8 +242,7 @@
         if (contents == null || contents.isEmpty()) {
             return 0;
         }
-        Matcher m = ION_HEAP_SIZE_IN_BYTES.matcher(contents);
-        return m.find() ? Long.parseLong(m.group(1)) : 0;
+        return tryParseLong(ION_HEAP_SIZE_IN_BYTES, contents);
     }
 
     /**
@@ -260,6 +252,20 @@
         return DEVICE_HAS_PER_APP_MEMCG;
     }
 
+    /**
+     * Parses a long from the input using the pattern. Returns 0 if the captured value is not
+     * parsable. The pattern must have a single capturing group.
+     */
+    private static long tryParseLong(Pattern pattern, String input) {
+        final Matcher m = pattern.matcher(input);
+        try {
+            return m.find() ? Long.parseLong(m.group(1)) : 0;
+        } catch (NumberFormatException e) {
+            Slog.e(TAG, "Failed to parse value", e);
+            return 0;
+        }
+    }
+
     public static final class MemoryStat {
         /** Number of page faults */
         public long pgfault;
diff --git a/services/core/java/com/android/server/am/OomAdjuster.java b/services/core/java/com/android/server/am/OomAdjuster.java
index 9056f76..aa03de1 100644
--- a/services/core/java/com/android/server/am/OomAdjuster.java
+++ b/services/core/java/com/android/server/am/OomAdjuster.java
@@ -38,7 +38,6 @@
 import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_UID_OBSERVERS;
 import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_USAGE_STATS;
 import static com.android.server.am.ActivityManagerService.DISPATCH_OOM_ADJ_OBSERVER_MSG;
-import static com.android.server.am.ActivityManagerService.DISPATCH_PROCESSES_CHANGED_UI_MSG;
 import static com.android.server.am.ActivityManagerService.IDLE_UIDS_MSG;
 import static com.android.server.am.ActivityManagerService.TAG_BACKUP;
 import static com.android.server.am.ActivityManagerService.TAG_LRU;
@@ -1921,41 +1920,9 @@
         if (changes != 0) {
             if (DEBUG_PROCESS_OBSERVERS) Slog.i(TAG_PROCESS_OBSERVERS,
                     "Changes in " + app + ": " + changes);
-            int i = mService.mPendingProcessChanges.size()-1;
-            ActivityManagerService.ProcessChangeItem item = null;
-            while (i >= 0) {
-                item = mService.mPendingProcessChanges.get(i);
-                if (item.pid == app.pid) {
-                    if (DEBUG_PROCESS_OBSERVERS) Slog.i(TAG_PROCESS_OBSERVERS,
-                            "Re-using existing item: " + item);
-                    break;
-                }
-                i--;
-            }
-            if (i < 0) {
-                // No existing item in pending changes; need a new one.
-                final int NA = mService.mAvailProcessChanges.size();
-                if (NA > 0) {
-                    item = mService.mAvailProcessChanges.remove(NA-1);
-                    if (DEBUG_PROCESS_OBSERVERS) Slog.i(TAG_PROCESS_OBSERVERS,
-                            "Retrieving available item: " + item);
-                } else {
-                    item = new ActivityManagerService.ProcessChangeItem();
-                    if (DEBUG_PROCESS_OBSERVERS) Slog.i(TAG_PROCESS_OBSERVERS,
-                            "Allocating new item: " + item);
-                }
-                item.changes = 0;
-                item.pid = app.pid;
-                item.uid = app.info.uid;
-                if (mService.mPendingProcessChanges.size() == 0) {
-                    if (DEBUG_PROCESS_OBSERVERS) Slog.i(TAG_PROCESS_OBSERVERS,
-                            "*** Enqueueing dispatch processes changed!");
-                    mService.mUiHandler.obtainMessage(DISPATCH_PROCESSES_CHANGED_UI_MSG)
-                            .sendToTarget();
-                }
-                mService.mPendingProcessChanges.add(item);
-            }
-            item.changes |= changes;
+            ActivityManagerService.ProcessChangeItem item =
+                    mService.enqueueProcessChangeItemLocked(app.pid, app.info.uid);
+            item.changes = changes;
             item.foregroundActivities = app.repForegroundActivities;
             if (DEBUG_PROCESS_OBSERVERS) Slog.i(TAG_PROCESS_OBSERVERS,
                     "Item " + Integer.toHexString(System.identityHashCode(item))
diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java
index 51b1ae1..17b244c 100644
--- a/services/core/java/com/android/server/am/ProcessRecord.java
+++ b/services/core/java/com/android/server/am/ProcessRecord.java
@@ -174,6 +174,7 @@
     boolean hasStartedServices; // Are there any started services running in this process?
     private boolean mHasForegroundServices; // Running any services that are foreground?
     private int mFgServiceTypes; // Type of foreground service, if there is a foreground service.
+    private int mRepFgServiceTypes; // Last reported foreground service types.
     private boolean mHasForegroundActivities; // Running any activities that are foreground?
     boolean repForegroundActivities; // Last reported foreground activities.
     boolean systemNoUi;         // This is a system process, but not currently showing UI.
@@ -1079,6 +1080,18 @@
                 && (mFgServiceTypes & ServiceInfo.FOREGROUND_SERVICE_TYPE_LOCATION) != 0;
     }
 
+    int getForegroundServiceTypes() {
+        return mHasForegroundServices ? mFgServiceTypes : 0;
+    }
+
+    int getReportedForegroundServiceTypes() {
+        return mRepFgServiceTypes;
+    }
+
+    void setReportedForegroundServiceTypes(int foregroundServiceTypes) {
+        mRepFgServiceTypes = foregroundServiceTypes;
+    }
+
     void setHasForegroundActivities(boolean hasForegroundActivities) {
         mHasForegroundActivities = hasForegroundActivities;
         mWindowProcessController.setHasForegroundActivities(hasForegroundActivities);
diff --git a/services/core/java/com/android/server/am/UserController.java b/services/core/java/com/android/server/am/UserController.java
index 029c3fb..07c9cca 100644
--- a/services/core/java/com/android/server/am/UserController.java
+++ b/services/core/java/com/android/server/am/UserController.java
@@ -389,14 +389,14 @@
      * Step from {@link UserState#STATE_RUNNING_LOCKED} to
      * {@link UserState#STATE_RUNNING_UNLOCKING}.
      */
-    private void finishUserUnlocking(final UserState uss) {
+    private boolean finishUserUnlocking(final UserState uss) {
         final int userId = uss.mHandle.getIdentifier();
         // Only keep marching forward if user is actually unlocked
-        if (!StorageManager.isUserKeyUnlocked(userId)) return;
+        if (!StorageManager.isUserKeyUnlocked(userId)) return false;
         synchronized (mLock) {
             // Do not proceed if unexpected state or a stale user
             if (mStartedUsers.get(userId) != uss || uss.state != STATE_RUNNING_LOCKED) {
-                return;
+                return false;
             }
         }
         uss.mUnlockProgress.start();
@@ -427,6 +427,7 @@
             mHandler.obtainMessage(SYSTEM_USER_UNLOCK_MSG, userId, 0, uss)
                     .sendToTarget();
         });
+        return true;
     }
 
     /**
@@ -1209,7 +1210,10 @@
             return false;
         }
 
-        finishUserUnlocking(uss);
+        if (!finishUserUnlocking(uss)) {
+            notifyFinished(userId, listener);
+            return false;
+        }
 
         // We just unlocked a user, so let's now attempt to unlock any
         // managed profiles under that user.
diff --git a/services/core/java/com/android/server/appop/AppOpsService.java b/services/core/java/com/android/server/appop/AppOpsService.java
index 9c26526..10b67c1 100644
--- a/services/core/java/com/android/server/appop/AppOpsService.java
+++ b/services/core/java/com/android/server/appop/AppOpsService.java
@@ -1132,7 +1132,7 @@
                 .build();
         Preconditions.checkNotNull(callback, "callback cannot be null");
 
-        mContext.enforcePermission(android.Manifest.permission.GET_APP_OPS_STATS,
+        mContext.enforcePermission(Manifest.permission.MANAGE_APPOPS,
                 Binder.getCallingPid(), Binder.getCallingUid(), "getHistoricalOps");
 
         final String[] opNamesArray = (opNames != null)
@@ -1144,6 +1144,14 @@
     }
 
     @Override
+    public void reloadNonHistoricalState() {
+        mContext.enforcePermission(Manifest.permission.MANAGE_APPOPS,
+                Binder.getCallingPid(), Binder.getCallingUid(), "reloadNonHistoricalState");
+        writeState();
+        readState();
+    }
+
+    @Override
     public List<AppOpsManager.PackageOps> getUidOps(int uid, int[] ops) {
         mContext.enforcePermission(android.Manifest.permission.GET_APP_OPS_STATS,
                 Binder.getCallingPid(), Binder.getCallingUid(), null);
@@ -2998,6 +3006,7 @@
 
                             final LongSparseArray keys = op.collectKeys();
                             if (keys == null || keys.size() <= 0) {
+                                out.endTag(null, "op");
                                 continue;
                             }
 
diff --git a/services/core/java/com/android/server/attention/AttentionManagerService.java b/services/core/java/com/android/server/attention/AttentionManagerService.java
index 7da848c..a8e99da 100644
--- a/services/core/java/com/android/server/attention/AttentionManagerService.java
+++ b/services/core/java/com/android/server/attention/AttentionManagerService.java
@@ -19,7 +19,9 @@
 import static android.provider.DeviceConfig.NAMESPACE_ATTENTION_MANAGER_SERVICE;
 
 import android.Manifest;
+import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.TestApi;
 import android.annotation.UserIdInt;
 import android.app.ActivityManager;
 import android.attention.AttentionManagerInternal;
@@ -59,6 +61,7 @@
 import com.android.internal.util.Preconditions;
 import com.android.server.SystemService;
 
+import java.io.FileDescriptor;
 import java.io.PrintWriter;
 
 /**
@@ -69,6 +72,15 @@
 public class AttentionManagerService extends SystemService {
     private static final String LOG_TAG = "AttentionManagerService";
 
+    /**
+     * DeviceConfig flag name, allows a CTS to inject a fake implementation.
+     *
+     * @hide
+     */
+    @TestApi
+    public static final String COMPONENT_NAME = "component_name";
+
+
     /** Default value in absence of {@link DeviceConfig} override. */
     private static final boolean DEFAULT_SERVICE_ENABLED = true;
 
@@ -80,10 +92,6 @@
 
     /** DeviceConfig flag name, if {@code true}, enables AttentionManagerService features. */
     private static final String SERVICE_ENABLED = "service_enabled";
-
-    /** DeviceConfig flag name, allows a CTS to inject a fake implementation. */
-    private static final String COMPONENT_NAME = "component_name";
-
     private final Context mContext;
     private final PowerManager mPowerManager;
     private final Object mLock;
@@ -103,6 +111,7 @@
 
     @Override
     public void onStart() {
+        publishBinderService(Context.ATTENTION_SERVICE, new BinderService());
         publishLocalService(AttentionManagerInternal.class, new LocalService());
     }
 
@@ -111,6 +120,11 @@
         cancelAndUnbindLocked(peekUserStateLocked(userId));
     }
 
+    /** Returns {@code true} if attention service is configured on this device. */
+    public static boolean isServiceConfigured(Context context) {
+        return !TextUtils.isEmpty(getServiceConfig(context));
+    }
+
     /** Resolves and sets up the attention service if it had not been done yet. */
     private boolean isServiceAvailable() {
         if (mComponentName == null) {
@@ -283,6 +297,10 @@
         return mUserStates.get(userId);
     }
 
+    private static String getServiceConfig(Context context) {
+        return context.getString(R.string.config_defaultAttentionService);
+    }
+
     /**
      * Provides attention service component name at runtime, making sure it's provided by the
      * system.
@@ -291,9 +309,7 @@
         final String flag = DeviceConfig.getProperty(NAMESPACE_ATTENTION_MANAGER_SERVICE,
                 COMPONENT_NAME);
 
-        final String componentNameString = flag != null ? flag : context.getString(
-                R.string.config_defaultAttentionService);
-
+        final String componentNameString = flag != null ? flag : getServiceConfig(context);
         if (TextUtils.isEmpty(componentNameString)) {
             return null;
         }
@@ -329,17 +345,15 @@
         return null;
     }
 
-    private void dumpInternal(PrintWriter pw) {
-        if (!DumpUtils.checkDumpPermission(mContext, LOG_TAG, pw)) return;
-        IndentingPrintWriter ipw = new IndentingPrintWriter(pw, "  ");
-        ipw.println("Attention Manager Service (dumpsys attention)\n");
+    private void dumpInternal(IndentingPrintWriter ipw) {
+        ipw.println("Attention Manager Service (dumpsys attention) state:\n");
 
         ipw.printPair("context", mContext);
-        pw.println();
+        ipw.println();
         synchronized (mLock) {
             int size = mUserStates.size();
             ipw.print("Number user states: ");
-            pw.println(size);
+            ipw.println(size);
             if (size > 0) {
                 ipw.increaseIndent();
                 for (int i = 0; i < size; i++) {
@@ -553,8 +567,8 @@
         }
     }
 
-    private void cancel(UserState userState, @AttentionFailureCodes int failureCode) {
-        if (userState != null && userState.mService != null) {
+    private void cancel(@NonNull UserState userState, @AttentionFailureCodes int failureCode) {
+        if (userState.mService != null) {
             try {
                 userState.mService.cancelAttentionCheck(
                         userState.mCurrentAttentionCheckRequestCode);
@@ -571,6 +585,9 @@
     @GuardedBy("mLock")
     private void cancelAndUnbindLocked(UserState userState) {
         synchronized (mLock) {
+            if (userState == null) {
+                return;
+            }
             cancel(userState, AttentionService.ATTENTION_FAILURE_UNKNOWN);
 
             mContext.unbindService(userState.mConnection);
@@ -591,4 +608,15 @@
             }
         }
     }
+
+    private final class BinderService extends Binder {
+        @Override
+        protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+            if (!DumpUtils.checkDumpPermission(mContext, LOG_TAG, pw)) {
+                return;
+            }
+
+            dumpInternal(new IndentingPrintWriter(pw, "  "));
+        }
+    }
 }
diff --git a/services/core/java/com/android/server/audio/AudioDeviceBroker.java b/services/core/java/com/android/server/audio/AudioDeviceBroker.java
index 69a9e7e..b774647 100644
--- a/services/core/java/com/android/server/audio/AudioDeviceBroker.java
+++ b/services/core/java/com/android/server/audio/AudioDeviceBroker.java
@@ -170,8 +170,15 @@
         }
     }
 
-    /*package*/ void setSpeakerphoneOn(boolean on, String eventSource) {
+    /**
+     * Turns speakerphone on/off
+     * @param on
+     * @param eventSource for logging purposes
+     * @return true if speakerphone state changed
+     */
+    /*package*/ boolean setSpeakerphoneOn(boolean on, String eventSource) {
         synchronized (mDeviceStateLock) {
+            final boolean wasOn = isSpeakerphoneOn();
             if (on) {
                 if (mForcedUseForComm == AudioSystem.FORCE_BT_SCO) {
                     setForceUse_Async(AudioSystem.FOR_RECORD, AudioSystem.FORCE_NONE, eventSource);
@@ -183,6 +190,7 @@
 
             mForcedUseForCommExt = mForcedUseForComm;
             setForceUse_Async(AudioSystem.FOR_COMMUNICATION, mForcedUseForComm, eventSource);
+            return (wasOn != isSpeakerphoneOn());
         }
     }
 
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 68f76ab..152f587 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -78,6 +78,8 @@
 import android.media.IRecordingConfigDispatcher;
 import android.media.IRingtonePlayer;
 import android.media.IVolumeController;
+import android.media.MediaExtractor;
+import android.media.MediaFormat;
 import android.media.MediaPlayer;
 import android.media.MediaPlayer.OnCompletionListener;
 import android.media.MediaPlayer.OnErrorListener;
@@ -94,6 +96,7 @@
 import android.media.audiopolicy.IAudioPolicyCallback;
 import android.media.projection.IMediaProjection;
 import android.media.projection.IMediaProjectionManager;
+import android.net.Uri;
 import android.os.Binder;
 import android.os.Build;
 import android.os.Bundle;
@@ -3331,7 +3334,11 @@
         final String eventSource = new StringBuilder("setSpeakerphoneOn(").append(on)
                 .append(") from u/pid:").append(Binder.getCallingUid()).append("/")
                 .append(Binder.getCallingPid()).toString();
-        mDeviceBroker.setSpeakerphoneOn(on, eventSource);
+        final boolean stateChanged = mDeviceBroker.setSpeakerphoneOn(on, eventSource);
+        if (stateChanged) {
+            mContext.sendBroadcast(new Intent(AudioManager.ACTION_SPEAKERPHONE_STATE_CHANGED)
+                    .setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY));
+        }
     }
 
     /** @see AudioManager#isSpeakerphoneOn() */
@@ -4142,6 +4149,26 @@
         }
     }
 
+    /**
+     * See AudioManager.hasHapticChannels(Uri).
+     */
+    public boolean hasHapticChannels(Uri uri) {
+        MediaExtractor extractor = new MediaExtractor();
+        try {
+            extractor.setDataSource(mContext, uri, null);
+            for (int i = 0; i < extractor.getTrackCount(); i++) {
+                MediaFormat format = extractor.getTrackFormat(i);
+                if (format.containsKey(MediaFormat.KEY_HAPTIC_CHANNEL_COUNT)
+                        && format.getInteger(MediaFormat.KEY_HAPTIC_CHANNEL_COUNT) > 0) {
+                    return true;
+                }
+            }
+        } catch (IOException e) {
+            Log.e(TAG, "hasHapticChannels failure:" + e);
+        }
+        return false;
+    }
+
     ///////////////////////////////////////////////////////////////////////////
     // Inner classes
     ///////////////////////////////////////////////////////////////////////////
diff --git a/services/core/java/com/android/server/biometrics/BiometricService.java b/services/core/java/com/android/server/biometrics/BiometricService.java
index ddd416e..516844d 100644
--- a/services/core/java/com/android/server/biometrics/BiometricService.java
+++ b/services/core/java/com/android/server/biometrics/BiometricService.java
@@ -57,6 +57,7 @@
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.Looper;
+import android.os.Message;
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.UserHandle;
@@ -68,6 +69,7 @@
 import android.util.StatsLog;
 
 import com.android.internal.R;
+import com.android.internal.os.SomeArgs;
 import com.android.internal.statusbar.IStatusBarService;
 import com.android.server.SystemService;
 
@@ -85,22 +87,137 @@
 
     private static final String TAG = "BiometricService";
 
+    private static final int MSG_ON_TASK_STACK_CHANGED = 1;
+    private static final int MSG_ON_AUTHENTICATION_SUCCEEDED = 2;
+    private static final int MSG_ON_AUTHENTICATION_FAILED = 3;
+    private static final int MSG_ON_ERROR = 4;
+    private static final int MSG_ON_ACQUIRED = 5;
+    private static final int MSG_ON_DISMISSED = 6;
+    private static final int MSG_ON_TRY_AGAIN_PRESSED = 7;
+    private static final int MSG_ON_READY_FOR_AUTHENTICATION = 8;
+    private static final int MSG_AUTHENTICATE = 9;
+    private static final int MSG_CANCEL_AUTHENTICATION = 10;
+
     private static final int[] FEATURE_ID = {
         TYPE_FINGERPRINT,
         TYPE_IRIS,
         TYPE_FACE
     };
 
+    /**
+     * Authentication either just called and we have not transitioned to the CALLED state, or
+     * authentication terminated (success or error).
+     */
+    private static final int STATE_AUTH_IDLE = 0;
+    /**
+     * Authentication was called and we are waiting for the <Biometric>Services to return their
+     * cookies before starting the hardware and showing the BiometricPrompt.
+     */
+    private static final int STATE_AUTH_CALLED = 1;
+    /**
+     * Authentication started, BiometricPrompt is showing and the hardware is authenticating.
+     */
+    private static final int STATE_AUTH_STARTED = 2;
+    /**
+     * Authentication is paused, waiting for the user to press "try again" button. Only
+     * passive modalities such as Face or Iris should have this state. Note that for passive
+     * modalities, the HAL enters the idle state after onAuthenticated(false) which differs from
+     * fingerprint.
+     */
+    private static final int STATE_AUTH_PAUSED = 3;
+    /**
+     * Authentication is successful, but we're waiting for the user to press "confirm" button.
+     */
+    private static final int STATE_AUTH_PENDING_CONFIRM = 5;
+
+    private final class AuthSession {
+        // Map of Authenticator/Cookie pairs. We expect to receive the cookies back from
+        // <Biometric>Services before we can start authenticating. Pairs that have been returned
+        // are moved to mModalitiesMatched.
+        final HashMap<Integer, Integer> mModalitiesWaiting;
+        // Pairs that have been matched.
+        final HashMap<Integer, Integer> mModalitiesMatched = new HashMap<>();
+
+        // The following variables are passed to authenticateInternal, which initiates the
+        // appropriate <Biometric>Services.
+        final IBinder mToken;
+        final long mSessionId;
+        final int mUserId;
+        // Original receiver from BiometricPrompt.
+        final IBiometricServiceReceiver mClientReceiver;
+        final String mOpPackageName;
+        // Info to be shown on BiometricDialog when all cookies are returned.
+        final Bundle mBundle;
+        final int mCallingUid;
+        final int mCallingPid;
+        final int mCallingUserId;
+        // Continue authentication with the same modality/modalities after "try again" is
+        // pressed
+        final int mModality;
+        final boolean mRequireConfirmation;
+
+        // The current state, which can be either idle, called, or started
+        private int mState = STATE_AUTH_IDLE;
+        // For explicit confirmation, do not send to keystore until the user has confirmed
+        // the authentication.
+        byte[] mTokenEscrow;
+
+        // Timestamp when hardware authentication occurred
+        private long mAuthenticatedTimeMs;
+
+        AuthSession(HashMap<Integer, Integer> modalities, IBinder token, long sessionId,
+                int userId, IBiometricServiceReceiver receiver, String opPackageName,
+                Bundle bundle, int callingUid, int callingPid, int callingUserId,
+                int modality, boolean requireConfirmation) {
+            mModalitiesWaiting = modalities;
+            mToken = token;
+            mSessionId = sessionId;
+            mUserId = userId;
+            mClientReceiver = receiver;
+            mOpPackageName = opPackageName;
+            mBundle = bundle;
+            mCallingUid = callingUid;
+            mCallingPid = callingPid;
+            mCallingUserId = callingUserId;
+            mModality = modality;
+            mRequireConfirmation = requireConfirmation;
+        }
+
+        boolean isCrypto() {
+            return mSessionId != 0;
+        }
+
+        boolean containsCookie(int cookie) {
+            if (mModalitiesWaiting != null && mModalitiesWaiting.containsValue(cookie)) {
+                return true;
+            }
+            if (mModalitiesMatched != null && mModalitiesMatched.containsValue(cookie)) {
+                return true;
+            }
+            return false;
+        }
+    }
+
+    private final class BiometricTaskStackListener extends TaskStackListener {
+        @Override
+        public void onTaskStackChanged() {
+            mHandler.sendEmptyMessage(MSG_ON_TASK_STACK_CHANGED);
+        }
+    }
+
     private final AppOpsManager mAppOps;
-    private final Handler mHandler;
     private final boolean mHasFeatureFingerprint;
     private final boolean mHasFeatureIris;
     private final boolean mHasFeatureFace;
     private final SettingObserver mSettingObserver;
     private final List<EnabledOnKeyguardCallback> mEnabledOnKeyguardCallbacks;
+    private final BiometricTaskStackListener mTaskStackListener = new BiometricTaskStackListener();
+    private final Random mRandom = new Random();
 
     private IFingerprintService mFingerprintService;
     private IFaceService mFaceService;
+    private IActivityTaskManager mActivityTaskManager;
+    private IStatusBarService mStatusBarService;
 
     // Get and cache the available authenticator (manager) classes. Used since aidl doesn't support
     // polymorphism :/
@@ -113,6 +230,108 @@
     // should be safe.
     private int mCurrentModality;
 
+    // The current authentication session, null if idle/done. We need to track both the current
+    // and pending sessions since errors may be sent to either.
+    private AuthSession mCurrentAuthSession;
+    private AuthSession mPendingAuthSession;
+
+    private final Handler mHandler = new Handler(Looper.getMainLooper()) {
+        @Override
+        public void handleMessage(Message msg) {
+            switch (msg.what) {
+                case MSG_ON_TASK_STACK_CHANGED: {
+                    handleTaskStackChanged();
+                    break;
+                }
+
+                case MSG_ON_AUTHENTICATION_SUCCEEDED: {
+                    SomeArgs args = (SomeArgs) msg.obj;
+                    handleAuthenticationSucceeded(
+                            (boolean) args.arg1 /* requireConfirmation */,
+                            (byte[]) args.arg2 /* token */);
+                    args.recycle();
+                    break;
+                }
+
+                case MSG_ON_AUTHENTICATION_FAILED: {
+                    SomeArgs args = (SomeArgs) msg.obj;
+                    handleAuthenticationFailed(
+                            args.argi1 /* cookie */,
+                            (boolean) args.arg1 /* requireConfirmation */);
+                    args.recycle();
+                    break;
+                }
+
+                case MSG_ON_ERROR: {
+                    SomeArgs args = (SomeArgs) msg.obj;
+                    handleOnError(
+                            args.argi1 /* cookie */,
+                            args.argi2 /* error */,
+                            (String) args.arg1 /* message */);
+                    args.recycle();
+                    break;
+                }
+
+                case MSG_ON_ACQUIRED: {
+                    SomeArgs args = (SomeArgs) msg.obj;
+                    handleOnAcquired(
+                            args.argi1 /* acquiredInfo */,
+                            (String) args.arg1 /* message */);
+                    args.recycle();
+                    break;
+                }
+
+                case MSG_ON_DISMISSED: {
+                    handleOnDismissed(msg.arg1);
+                    break;
+                }
+
+                case MSG_ON_TRY_AGAIN_PRESSED: {
+                    handleOnTryAgainPressed();
+                    break;
+                }
+
+                case MSG_ON_READY_FOR_AUTHENTICATION: {
+                    SomeArgs args = (SomeArgs) msg.obj;
+                    handleOnReadyForAuthentication(
+                            args.argi1 /* cookie */,
+                            (boolean) args.arg1 /* requireConfirmation */,
+                            args.argi2 /* userId */);
+                    args.recycle();
+                    break;
+                }
+
+                case MSG_AUTHENTICATE: {
+                    SomeArgs args = (SomeArgs) msg.obj;
+                    handleAuthenticate(
+                            (IBinder) args.arg1 /* token */,
+                            (long) args.arg2 /* sessionId */,
+                            args.argi1 /* userid */,
+                            (IBiometricServiceReceiver) args.arg3 /* receiver */,
+                            (String) args.arg4 /* opPackageName */,
+                            (Bundle) args.arg5 /* bundle */,
+                            args.argi2 /* callingUid */,
+                            args.argi3 /* callingPid */,
+                            args.argi4 /* callingUserId */);
+                    args.recycle();
+                    break;
+                }
+
+                case MSG_CANCEL_AUTHENTICATION: {
+                    SomeArgs args = (SomeArgs) msg.obj;
+                    handleCancelAuthentication(
+                            (IBinder) args.arg1 /* token */,
+                            (String) args.arg2 /* opPackageName */);
+                    args.recycle();
+                    break;
+                }
+
+                default:
+                    break;
+            }
+        }
+    };
+
     private final class Authenticator {
         int mType;
         BiometricAuthenticator mAuthenticator;
@@ -251,142 +470,62 @@
         }
     }
 
+    // Wrap the client's receiver so we can do things with the BiometricDialog first
+    private final IBiometricServiceReceiverInternal mInternalReceiver =
+            new IBiometricServiceReceiverInternal.Stub() {
+        @Override
+        public void onAuthenticationSucceeded(boolean requireConfirmation, byte[] token)
+                throws RemoteException {
+            SomeArgs args = SomeArgs.obtain();
+            args.arg1 = requireConfirmation;
+            args.arg2 = token;
+            mHandler.obtainMessage(MSG_ON_AUTHENTICATION_SUCCEEDED, args).sendToTarget();
+        }
+
+        @Override
+        public void onAuthenticationFailed(int cookie, boolean requireConfirmation)
+                throws RemoteException {
+            SomeArgs args = SomeArgs.obtain();
+            args.argi1 = cookie;
+            args.arg1 = requireConfirmation;
+            mHandler.obtainMessage(MSG_ON_AUTHENTICATION_FAILED, args).sendToTarget();
+        }
+
+        @Override
+        public void onError(int cookie, int error, String message) throws RemoteException {
+            SomeArgs args = SomeArgs.obtain();
+            args.argi1 = cookie;
+            args.argi2 = error;
+            args.arg1 = message;
+            mHandler.obtainMessage(MSG_ON_ERROR, args).sendToTarget();
+        }
+
+        @Override
+        public void onAcquired(int acquiredInfo, String message) throws RemoteException {
+            SomeArgs args = SomeArgs.obtain();
+            args.argi1 = acquiredInfo;
+            args.arg1 = message;
+            mHandler.obtainMessage(MSG_ON_ACQUIRED, args).sendToTarget();
+        }
+
+        @Override
+        public void onDialogDismissed(int reason) throws RemoteException {
+            mHandler.obtainMessage(MSG_ON_DISMISSED, reason, 0 /* arg2 */).sendToTarget();
+        }
+
+        @Override
+        public void onTryAgainPressed() {
+            mHandler.sendEmptyMessage(MSG_ON_TRY_AGAIN_PRESSED);
+        }
+    };
+
+
     /**
      * This is just a pass-through service that wraps Fingerprint, Iris, Face services. This service
      * should not carry any state. The reality is we need to keep a tiny amount of state so that
      * cancelAuthentication() can go to the right place.
      */
     private final class BiometricServiceWrapper extends IBiometricService.Stub {
-
-        /**
-         * Authentication either just called and we have not transitioned to the CALLED state, or
-         * authentication terminated (success or error).
-         */
-        private static final int STATE_AUTH_IDLE = 0;
-        /**
-         * Authentication was called and we are waiting for the <Biometric>Services to return their
-         * cookies before starting the hardware and showing the BiometricPrompt.
-         */
-        private static final int STATE_AUTH_CALLED = 1;
-        /**
-         * Authentication started, BiometricPrompt is showing and the hardware is authenticating.
-         */
-        private static final int STATE_AUTH_STARTED = 2;
-        /**
-         * Authentication is paused, waiting for the user to press "try again" button. Only
-         * passive modalities such as Face or Iris should have this state. Note that for passive
-         * modalities, the HAL enters the idle state after onAuthenticated(false) which differs from
-         * fingerprint.
-         */
-        private static final int STATE_AUTH_PAUSED = 3;
-        /**
-         * Authentication is successful, but we're waiting for the user to press "confirm" button.
-         */
-        private static final int STATE_AUTH_PENDING_CONFIRM = 5;
-
-        final class AuthSession {
-            // Map of Authenticator/Cookie pairs. We expect to receive the cookies back from
-            // <Biometric>Services before we can start authenticating. Pairs that have been returned
-            // are moved to mModalitiesMatched.
-            final HashMap<Integer, Integer> mModalitiesWaiting;
-            // Pairs that have been matched.
-            final HashMap<Integer, Integer> mModalitiesMatched = new HashMap<>();
-
-            // The following variables are passed to authenticateInternal, which initiates the
-            // appropriate <Biometric>Services.
-            final IBinder mToken;
-            final long mSessionId;
-            final int mUserId;
-            // Original receiver from BiometricPrompt.
-            final IBiometricServiceReceiver mClientReceiver;
-            final String mOpPackageName;
-            // Info to be shown on BiometricDialog when all cookies are returned.
-            final Bundle mBundle;
-            final int mCallingUid;
-            final int mCallingPid;
-            final int mCallingUserId;
-            // Continue authentication with the same modality/modalities after "try again" is
-            // pressed
-            final int mModality;
-            final boolean mRequireConfirmation;
-
-            // The current state, which can be either idle, called, or started
-            private int mState = STATE_AUTH_IDLE;
-            // For explicit confirmation, do not send to keystore until the user has confirmed
-            // the authentication.
-            byte[] mTokenEscrow;
-
-            // Timestamp when hardware authentication occurred
-            private long mAuthenticatedTimeMs;
-
-            AuthSession(HashMap<Integer, Integer> modalities, IBinder token, long sessionId,
-                    int userId, IBiometricServiceReceiver receiver, String opPackageName,
-                    Bundle bundle, int callingUid, int callingPid, int callingUserId,
-                    int modality, boolean requireConfirmation) {
-                mModalitiesWaiting = modalities;
-                mToken = token;
-                mSessionId = sessionId;
-                mUserId = userId;
-                mClientReceiver = receiver;
-                mOpPackageName = opPackageName;
-                mBundle = bundle;
-                mCallingUid = callingUid;
-                mCallingPid = callingPid;
-                mCallingUserId = callingUserId;
-                mModality = modality;
-                mRequireConfirmation = requireConfirmation;
-            }
-
-            boolean isCrypto() {
-                return mSessionId != 0;
-            }
-
-            boolean containsCookie(int cookie) {
-                if (mModalitiesWaiting != null && mModalitiesWaiting.containsValue(cookie)) {
-                    return true;
-                }
-                if (mModalitiesMatched != null && mModalitiesMatched.containsValue(cookie)) {
-                    return true;
-                }
-                return false;
-            }
-        }
-
-        final class BiometricTaskStackListener extends TaskStackListener {
-            @Override
-            public void onTaskStackChanged() {
-                try {
-                    final List<ActivityManager.RunningTaskInfo> runningTasks =
-                            mActivityTaskManager.getTasks(1);
-                    if (!runningTasks.isEmpty()) {
-                        final String topPackage = runningTasks.get(0).topActivity.getPackageName();
-                        if (mCurrentAuthSession != null
-                                && !topPackage.contentEquals(mCurrentAuthSession.mOpPackageName)) {
-                            mStatusBarService.hideBiometricDialog();
-                            mActivityTaskManager.unregisterTaskStackListener(mTaskStackListener);
-                            mCurrentAuthSession.mClientReceiver.onError(
-                                    BiometricConstants.BIOMETRIC_ERROR_CANCELED,
-                                    getContext().getString(
-                                            com.android.internal.R.string.biometric_error_canceled)
-                            );
-                            mCurrentAuthSession.mState = STATE_AUTH_IDLE;
-                            mCurrentAuthSession = null;
-                        }
-                    }
-                } catch (RemoteException e) {
-                    Slog.e(TAG, "Unable to get running tasks", e);
-                }
-            }
-        }
-
-        private final IActivityTaskManager mActivityTaskManager = getContext().getSystemService(
-                ActivityTaskManager.class).getService();
-        private final IStatusBarService mStatusBarService = IStatusBarService.Stub.asInterface(
-                ServiceManager.getService(Context.STATUS_BAR_SERVICE));
-        private final BiometricTaskStackListener mTaskStackListener =
-                new BiometricTaskStackListener();
-        private final Random mRandom = new Random();
-
         // TODO(b/123378871): Remove when moved.
         // When BiometricPrompt#setAllowDeviceCredentials is set to true, we need to store the
         // client (app) receiver. BiometricService internally launches CDCA which invokes
@@ -395,331 +534,15 @@
         // to this receiver.
         private IBiometricServiceReceiver mConfirmDeviceCredentialReceiver;
 
-        // The current authentication session, null if idle/done. We need to track both the current
-        // and pending sessions since errors may be sent to either.
-        private AuthSession mCurrentAuthSession;
-        private AuthSession mPendingAuthSession;
-
-        // Wrap the client's receiver so we can do things with the BiometricDialog first
-        private final IBiometricServiceReceiverInternal mInternalReceiver =
-                new IBiometricServiceReceiverInternal.Stub() {
-            @Override
-            public void onAuthenticationSucceeded(boolean requireConfirmation, byte[] token)
-                    throws RemoteException {
-                try {
-                    // Should never happen, log this to catch bad HAL behavior (e.g. auth succeeded
-                    // after user dismissed/canceled dialog).
-                    if (mCurrentAuthSession == null) {
-                        Slog.e(TAG, "onAuthenticationSucceeded(): Auth session is null");
-                        return;
-                    }
-
-                    if (!requireConfirmation) {
-                        mActivityTaskManager.unregisterTaskStackListener(mTaskStackListener);
-                        KeyStore.getInstance().addAuthToken(token);
-                        mCurrentAuthSession.mClientReceiver.onAuthenticationSucceeded();
-                        mCurrentAuthSession.mState = STATE_AUTH_IDLE;
-                        mCurrentAuthSession = null;
-                    } else {
-                        mCurrentAuthSession.mAuthenticatedTimeMs = System.currentTimeMillis();
-                        // Store the auth token and submit it to keystore after the confirmation
-                        // button has been pressed.
-                        mCurrentAuthSession.mTokenEscrow = token;
-                        mCurrentAuthSession.mState = STATE_AUTH_PENDING_CONFIRM;
-                    }
-
-                    // Notify SysUI that the biometric has been authenticated. SysUI already knows
-                    // the implicit/explicit state and will react accordingly.
-                    mStatusBarService.onBiometricAuthenticated(true);
-                } catch (RemoteException e) {
-                    Slog.e(TAG, "Remote exception", e);
-                }
-            }
-
-            @Override
-            public void onAuthenticationFailed(int cookie, boolean requireConfirmation)
-                    throws RemoteException {
-                try {
-                    // Should never happen, log this to catch bad HAL behavior (e.g. auth succeeded
-                    // after user dismissed/canceled dialog).
-                    if (mCurrentAuthSession == null) {
-                        Slog.e(TAG, "onAuthenticationFailed(): Auth session is null");
-                        return;
-                    }
-
-                    mStatusBarService.onBiometricAuthenticated(false);
-
-                    // TODO: This logic will need to be updated if BP is multi-modal
-                    if ((mCurrentAuthSession.mModality & TYPE_FACE) != 0) {
-                        // Pause authentication. onBiometricAuthenticated(false) causes the
-                        // dialog to show a "try again" button for passive modalities.
-                        mCurrentAuthSession.mState = STATE_AUTH_PAUSED;
-                    }
-
-                    mCurrentAuthSession.mClientReceiver.onAuthenticationFailed();
-                } catch (RemoteException e) {
-                    Slog.e(TAG, "Remote exception", e);
-                }
-            }
-
-            @Override
-            public void onError(int cookie, int error, String message) throws RemoteException {
-                Slog.d(TAG, "Error: " + error + " cookie: " + cookie);
-                // Errors can either be from the current auth session or the pending auth session.
-                // The pending auth session may receive errors such as ERROR_LOCKOUT before
-                // it becomes the current auth session. Similarly, the current auth session may
-                // receive errors such as ERROR_CANCELED while the pending auth session is preparing
-                // to be started. Thus we must match error messages with their cookies to be sure
-                // of their intended receivers.
-                try {
-                    if (mCurrentAuthSession != null && mCurrentAuthSession.containsCookie(cookie)) {
-                        if (mCurrentAuthSession.mState == STATE_AUTH_STARTED) {
-                            mStatusBarService.onBiometricError(message);
-                            if (error == BiometricConstants.BIOMETRIC_ERROR_CANCELED) {
-                                    mActivityTaskManager.unregisterTaskStackListener(
-                                            mTaskStackListener);
-                                    mCurrentAuthSession.mClientReceiver.onError(error, message);
-                                    mCurrentAuthSession.mState = STATE_AUTH_IDLE;
-                                    mCurrentAuthSession = null;
-                                    mStatusBarService.hideBiometricDialog();
-                            } else {
-                                // Send errors after the dialog is dismissed.
-                                mHandler.postDelayed(() -> {
-                                    try {
-                                        if (mCurrentAuthSession != null) {
-                                            mActivityTaskManager.unregisterTaskStackListener(
-                                                    mTaskStackListener);
-                                            mCurrentAuthSession.mClientReceiver.onError(error,
-                                                    message);
-                                            mCurrentAuthSession.mState = STATE_AUTH_IDLE;
-                                            mCurrentAuthSession = null;
-                                        }
-                                    } catch (RemoteException e) {
-                                        Slog.e(TAG, "Remote exception", e);
-                                    }
-                                }, BiometricPrompt.HIDE_DIALOG_DELAY);
-                            }
-                        } else if (mCurrentAuthSession.mState == STATE_AUTH_PAUSED) {
-                            // In the "try again" state, we should forward canceled errors to
-                            // the client and and clean up.
-                            mCurrentAuthSession.mClientReceiver.onError(error, message);
-                            mStatusBarService.onBiometricError(message);
-                            mActivityTaskManager.unregisterTaskStackListener(
-                                    mTaskStackListener);
-                            mCurrentAuthSession.mState = STATE_AUTH_IDLE;
-                            mCurrentAuthSession = null;
-                        } else {
-                            Slog.e(TAG, "Impossible session error state: "
-                                    + mCurrentAuthSession.mState);
-                        }
-                    } else if (mPendingAuthSession != null
-                            && mPendingAuthSession.containsCookie(cookie)) {
-                        if (mPendingAuthSession.mState == STATE_AUTH_CALLED) {
-                            mPendingAuthSession.mClientReceiver.onError(error, message);
-                            mPendingAuthSession.mState = STATE_AUTH_IDLE;
-                            mPendingAuthSession = null;
-                        } else {
-                            Slog.e(TAG, "Impossible pending session error state: "
-                                    + mPendingAuthSession.mState);
-                        }
-                    }
-                } catch (RemoteException e) {
-                    Slog.e(TAG, "Remote exception", e);
-                }
-            }
-
-            @Override
-            public void onAcquired(int acquiredInfo, String message) throws RemoteException {
-                // Should never happen, log this to catch bad HAL behavior (e.g. auth succeeded
-                // after user dismissed/canceled dialog).
-                if (mCurrentAuthSession == null) {
-                    Slog.e(TAG, "onAcquired(): Auth session is null");
-                    return;
-                }
-
-                if (acquiredInfo != BiometricConstants.BIOMETRIC_ACQUIRED_GOOD) {
-                    try {
-                        mStatusBarService.onBiometricHelp(message);
-                    } catch (RemoteException e) {
-                        Slog.e(TAG, "Remote exception", e);
-                    }
-                }
-            }
-
-            @Override
-            public void onDialogDismissed(int reason) throws RemoteException {
-                if (mCurrentAuthSession == null) {
-                    Slog.e(TAG, "onDialogDismissed: " + reason + ", auth session null");
-                    return;
-                }
-
-                logDialogDismissed(reason);
-
-                if (reason != BiometricPrompt.DISMISSED_REASON_POSITIVE) {
-                    // Positive button is used by passive modalities as a "confirm" button,
-                    // do not send to client
-                    mCurrentAuthSession.mClientReceiver.onDialogDismissed(reason);
-                    // Cancel authentication. Skip the token/package check since we are cancelling
-                    // from system server. The interface is permission protected so this is fine.
-                    cancelInternal(null /* token */, null /* package */, false /* fromClient */);
-                }
-                if (reason == BiometricPrompt.DISMISSED_REASON_USER_CANCEL) {
-                    mCurrentAuthSession.mClientReceiver.onError(
-                            BiometricConstants.BIOMETRIC_ERROR_USER_CANCELED,
-                            getContext().getString(
-                                    com.android.internal.R.string.biometric_error_user_canceled));
-                } else if (reason == BiometricPrompt.DISMISSED_REASON_POSITIVE) {
-                    // Have the service send the token to KeyStore, and send onAuthenticated
-                    // to the application
-                    KeyStore.getInstance().addAuthToken(mCurrentAuthSession.mTokenEscrow);
-                    mCurrentAuthSession.mClientReceiver.onAuthenticationSucceeded();
-                }
-                mActivityTaskManager.unregisterTaskStackListener(mTaskStackListener);
-                mCurrentAuthSession.mState = STATE_AUTH_IDLE;
-                mCurrentAuthSession = null;
-            }
-
-            @Override
-            public void onTryAgainPressed() {
-                Slog.d(TAG, "onTryAgainPressed");
-                // No need to check permission, since it can only be invoked by SystemUI
-                // (or system server itself).
-                mHandler.post(() -> {
-                    authenticateInternal(mCurrentAuthSession.mToken,
-                            mCurrentAuthSession.mSessionId,
-                            mCurrentAuthSession.mUserId,
-                            mCurrentAuthSession.mClientReceiver,
-                            mCurrentAuthSession.mOpPackageName,
-                            mCurrentAuthSession.mBundle,
-                            mCurrentAuthSession.mCallingUid,
-                            mCurrentAuthSession.mCallingPid,
-                            mCurrentAuthSession.mCallingUserId,
-                            mCurrentAuthSession.mModality);
-                });
-            }
-
-            private void logDialogDismissed(int reason) {
-                if (reason == BiometricPrompt.DISMISSED_REASON_POSITIVE) {
-                    // Explicit auth, authentication confirmed.
-                    // Latency in this case is authenticated -> confirmed. <Biometric>Service
-                    // should have the first half (first acquired -> authenticated).
-                    final long latency = System.currentTimeMillis()
-                            - mCurrentAuthSession.mAuthenticatedTimeMs;
-
-                    if (LoggableMonitor.DEBUG) {
-                        Slog.v(LoggableMonitor.TAG, "Confirmed! Modality: " + statsModality()
-                                + ", User: " + mCurrentAuthSession.mUserId
-                                + ", IsCrypto: " + mCurrentAuthSession.isCrypto()
-                                + ", Client: " + BiometricsProtoEnums.CLIENT_BIOMETRIC_PROMPT
-                                + ", RequireConfirmation: "
-                                    + mCurrentAuthSession.mRequireConfirmation
-                                + ", State: " + StatsLog.BIOMETRIC_AUTHENTICATED__STATE__CONFIRMED
-                                + ", Latency: " + latency);
-                    }
-
-                    StatsLog.write(StatsLog.BIOMETRIC_AUTHENTICATED,
-                            statsModality(),
-                            mCurrentAuthSession.mUserId,
-                            mCurrentAuthSession.isCrypto(),
-                            BiometricsProtoEnums.CLIENT_BIOMETRIC_PROMPT,
-                            mCurrentAuthSession.mRequireConfirmation,
-                            StatsLog.BIOMETRIC_AUTHENTICATED__STATE__CONFIRMED,
-                            latency);
-                } else {
-                    int error = reason == BiometricPrompt.DISMISSED_REASON_NEGATIVE
-                            ? BiometricConstants.BIOMETRIC_ERROR_NEGATIVE_BUTTON
-                            : reason == BiometricPrompt.DISMISSED_REASON_USER_CANCEL
-                                    ? BiometricConstants.BIOMETRIC_ERROR_USER_CANCELED
-                                    : 0;
-                    if (LoggableMonitor.DEBUG) {
-                        Slog.v(LoggableMonitor.TAG, "Dismissed! Modality: " + statsModality()
-                                + ", User: " + mCurrentAuthSession.mUserId
-                                + ", IsCrypto: " + mCurrentAuthSession.isCrypto()
-                                + ", Action: " + BiometricsProtoEnums.ACTION_AUTHENTICATE
-                                + ", Client: " + BiometricsProtoEnums.CLIENT_BIOMETRIC_PROMPT
-                                + ", Error: " + error);
-                    }
-                    // Auth canceled
-                    StatsLog.write(StatsLog.BIOMETRIC_ERROR_OCCURRED,
-                            statsModality(),
-                            mCurrentAuthSession.mUserId,
-                            mCurrentAuthSession.isCrypto(),
-                            BiometricsProtoEnums.ACTION_AUTHENTICATE,
-                            BiometricsProtoEnums.CLIENT_BIOMETRIC_PROMPT,
-                            error,
-                            0 /* vendorCode */);
-                }
-            }
-
-            private int statsModality() {
-                int modality = 0;
-                if (mCurrentAuthSession == null) {
-                    return BiometricsProtoEnums.MODALITY_UNKNOWN;
-                }
-                if ((mCurrentAuthSession.mModality & BiometricAuthenticator.TYPE_FINGERPRINT)
-                        != 0) {
-                    modality |= BiometricsProtoEnums.MODALITY_FINGERPRINT;
-                }
-                if ((mCurrentAuthSession.mModality & BiometricAuthenticator.TYPE_IRIS) != 0) {
-                    modality |= BiometricsProtoEnums.MODALITY_IRIS;
-                }
-                if ((mCurrentAuthSession.mModality & BiometricAuthenticator.TYPE_FACE) != 0) {
-                    modality |= BiometricsProtoEnums.MODALITY_FACE;
-                }
-                return modality;
-            }
-        };
-
         @Override // Binder call
         public void onReadyForAuthentication(int cookie, boolean requireConfirmation, int userId) {
             checkInternalPermission();
 
-            Iterator it = mPendingAuthSession.mModalitiesWaiting.entrySet().iterator();
-            while (it.hasNext()) {
-                Map.Entry<Integer, Integer> pair = (Map.Entry) it.next();
-                if (pair.getValue() == cookie) {
-                    mPendingAuthSession.mModalitiesMatched.put(pair.getKey(), pair.getValue());
-                    mPendingAuthSession.mModalitiesWaiting.remove(pair.getKey());
-                    Slog.d(TAG, "Matched cookie: " + cookie + ", "
-                            + mPendingAuthSession.mModalitiesWaiting.size() + " remaining");
-                    break;
-                }
-            }
-
-            if (mPendingAuthSession.mModalitiesWaiting.isEmpty()) {
-                final boolean continuing = mCurrentAuthSession != null &&
-                        (mCurrentAuthSession.mState == STATE_AUTH_PAUSED);
-
-                mCurrentAuthSession = mPendingAuthSession;
-                mPendingAuthSession = null;
-
-                mCurrentAuthSession.mState = STATE_AUTH_STARTED;
-                try {
-                    int modality = TYPE_NONE;
-                    it = mCurrentAuthSession.mModalitiesMatched.entrySet().iterator();
-                    while (it.hasNext()) {
-                        Map.Entry<Integer, Integer> pair = (Map.Entry) it.next();
-                        if (pair.getKey() == TYPE_FINGERPRINT) {
-                            mFingerprintService.startPreparedClient(pair.getValue());
-                        } else if (pair.getKey() == TYPE_IRIS) {
-                            Slog.e(TAG, "Iris unsupported");
-                        } else if (pair.getKey() == TYPE_FACE) {
-                            mFaceService.startPreparedClient(pair.getValue());
-                        } else {
-                            Slog.e(TAG, "Unknown modality: " + pair.getKey());
-                        }
-                        modality |= pair.getKey();
-                    }
-
-                    if (!continuing) {
-                        mStatusBarService.showBiometricDialog(mCurrentAuthSession.mBundle,
-                                mInternalReceiver, modality, requireConfirmation, userId);
-                        mActivityTaskManager.registerTaskStackListener(mTaskStackListener);
-                    }
-                } catch (RemoteException e) {
-                    Slog.e(TAG, "Remote exception", e);
-                }
-            }
+            SomeArgs args = SomeArgs.obtain();
+            args.argi1 = cookie;
+            args.arg1 = requireConfirmation;
+            args.argi2 = userId;
+            mHandler.obtainMessage(MSG_ON_READY_FOR_AUTHENTICATION, args).sendToTarget();
         }
 
         @Override // Binder call
@@ -754,25 +577,23 @@
                 checkInternalPermission();
                 // Set the default title if necessary
                 try {
-                    if (useDefaultTitle) {
-                        final List<ActivityManager.RunningAppProcessInfo> procs =
-                                ActivityManager.getService().getRunningAppProcesses();
-                        for (int i = 0; i < procs.size(); i++) {
-                            final ActivityManager.RunningAppProcessInfo info = procs.get(i);
-                            if (info.uid == callingUid
-                                    && info.importance == IMPORTANCE_FOREGROUND) {
-                                PackageManager pm = getContext().getPackageManager();
-                                final CharSequence label = pm.getApplicationLabel(
-                                        pm.getApplicationInfo(info.processName,
-                                                PackageManager.GET_META_DATA));
-                                final String title = getContext()
-                                        .getString(R.string.biometric_dialog_default_title, label);
-                                if (TextUtils.isEmpty(
-                                        bundle.getCharSequence(BiometricPrompt.KEY_TITLE))) {
-                                    bundle.putCharSequence(BiometricPrompt.KEY_TITLE, title);
-                                }
-                                break;
+                    final List<ActivityManager.RunningAppProcessInfo> procs =
+                            ActivityManager.getService().getRunningAppProcesses();
+                    for (int i = 0; i < procs.size(); i++) {
+                        final ActivityManager.RunningAppProcessInfo info = procs.get(i);
+                        if (info.uid == callingUid
+                                && info.importance == IMPORTANCE_FOREGROUND) {
+                            PackageManager pm = getContext().getPackageManager();
+                            final CharSequence label = pm.getApplicationLabel(
+                                    pm.getApplicationInfo(info.processName,
+                                            PackageManager.GET_META_DATA));
+                            final String title = getContext()
+                                    .getString(R.string.biometric_dialog_default_title, label);
+                            if (TextUtils.isEmpty(
+                                    bundle.getCharSequence(BiometricPrompt.KEY_TITLE))) {
+                                bundle.putCharSequence(BiometricPrompt.KEY_TITLE, title);
                             }
+                            break;
                         }
                     }
                 } catch (RemoteException e) {
@@ -792,7 +613,8 @@
                             KeyguardManager.class);
                     if (!kgm.isDeviceSecure()) {
                         try {
-                            receiver.onError(BiometricConstants.BIOMETRIC_ERROR_NO_DEVICE_CREDENTIAL,
+                            receiver.onError(
+                                    BiometricConstants.BIOMETRIC_ERROR_NO_DEVICE_CREDENTIAL,
                                     getContext().getString(
                                             R.string.biometric_error_device_not_secured));
                         } catch (RemoteException e) {
@@ -806,165 +628,71 @@
                             null /* description */);
                     // Then give it the bundle to do magic behavior..
                     intent.putExtra(KeyguardManager.EXTRA_BIOMETRIC_PROMPT_BUNDLE, bundle);
+                    // Create a new task with this activity located at the root.
+                    intent.setFlags(
+                            Intent.FLAG_ACTIVITY_MULTIPLE_TASK | Intent.FLAG_ACTIVITY_NEW_DOCUMENT);
                     getContext().startActivityAsUser(intent, UserHandle.CURRENT);
                 });
                 return;
             }
 
-            mHandler.post(() -> {
-                final Pair<Integer, Integer> result = checkAndGetBiometricModality(userId);
-                final int modality = result.first;
-                final int error = result.second;
+            SomeArgs args = SomeArgs.obtain();
+            args.arg1 = token;
+            args.arg2 = sessionId;
+            args.argi1 = userId;
+            args.arg3 = receiver;
+            args.arg4 = opPackageName;
+            args.arg5 = bundle;
+            args.argi2 = callingUid;
+            args.argi3 = callingPid;
+            args.argi4 = callingUserId;
 
-                // Check for errors, notify callback, and return
-                if (error != BiometricConstants.BIOMETRIC_SUCCESS) {
-                    try {
-                        final String hardwareUnavailable =
-                                getContext().getString(R.string.biometric_error_hw_unavailable);
-                        switch (error) {
-                            case BiometricConstants.BIOMETRIC_ERROR_HW_NOT_PRESENT:
-                                receiver.onError(error, hardwareUnavailable);
-                                break;
-                            case BiometricConstants.BIOMETRIC_ERROR_HW_UNAVAILABLE:
-                                receiver.onError(error, hardwareUnavailable);
-                                break;
-                            case BiometricConstants.BIOMETRIC_ERROR_NO_BIOMETRICS:
-                                receiver.onError(error,
-                                        getErrorString(modality, error, 0 /* vendorCode */));
-                                break;
-                            default:
-                                Slog.e(TAG, "Unhandled error");
-                                break;
-                        }
-                    } catch (RemoteException e) {
-                        Slog.e(TAG, "Unable to send error", e);
-                    }
-                    return;
-                }
-
-                mCurrentModality = modality;
-
-                // Start preparing for authentication. Authentication starts when
-                // all modalities requested have invoked onReadyForAuthentication.
-                authenticateInternal(token, sessionId, userId, receiver, opPackageName, bundle,
-                        callingUid, callingPid, callingUserId, modality);
-            });
+            mHandler.obtainMessage(MSG_AUTHENTICATE, args).sendToTarget();
         }
 
         @Override // Binder call
         public void onConfirmDeviceCredentialSuccess() {
             checkInternalPermission();
-            if (mConfirmDeviceCredentialReceiver == null) {
-                Slog.w(TAG, "onCDCASuccess null!");
-                return;
-            }
-            try {
-                mConfirmDeviceCredentialReceiver.onAuthenticationSucceeded();
-            } catch (RemoteException e) {
-                Slog.e(TAG, "RemoteException", e);
-            }
-            mConfirmDeviceCredentialReceiver = null;
+            mHandler.post(() -> {
+                if (mConfirmDeviceCredentialReceiver == null) {
+                    Slog.w(TAG, "onCDCASuccess null!");
+                    return;
+                }
+                try {
+                    mConfirmDeviceCredentialReceiver.onAuthenticationSucceeded();
+                } catch (RemoteException e) {
+                    Slog.e(TAG, "RemoteException", e);
+                }
+                mConfirmDeviceCredentialReceiver = null;
+            });
         }
 
         @Override // Binder call
         public void onConfirmDeviceCredentialError(int error, String message) {
             checkInternalPermission();
-            if (mConfirmDeviceCredentialReceiver == null) {
-                Slog.w(TAG, "onCDCAError null! Error: " + error + " " + message);
-                return;
-            }
-            try {
-                mConfirmDeviceCredentialReceiver.onError(error, message);
-            } catch (RemoteException e) {
-                Slog.e(TAG, "RemoteException", e);
-            }
-            mConfirmDeviceCredentialReceiver = null;
-        }
-
-        /**
-         * authenticate() (above) which is called from BiometricPrompt determines which
-         * modality/modalities to start authenticating with. authenticateInternal() should only be
-         * used for:
-         * 1) Preparing <Biometric>Services for authentication when BiometricPrompt#authenticate is,
-         *    invoked, shortly after which BiometricPrompt is shown and authentication starts
-         * 2) Preparing <Biometric>Services for authentication when BiometricPrompt is already shown
-         *    and the user has pressed "try again"
-         */
-        private void authenticateInternal(IBinder token, long sessionId, int userId,
-                IBiometricServiceReceiver receiver, String opPackageName, Bundle bundle,
-                int callingUid, int callingPid, int callingUserId, int modality) {
-            try {
-                boolean requireConfirmation = bundle.getBoolean(
-                        BiometricPrompt.KEY_REQUIRE_CONFIRMATION, true /* default */);
-                if ((modality & TYPE_FACE) != 0) {
-                    // Check if the user has forced confirmation to be required in Settings.
-                    requireConfirmation = requireConfirmation
-                            || mSettingObserver.getFaceAlwaysRequireConfirmation();
+            mHandler.post(() -> {
+                if (mConfirmDeviceCredentialReceiver == null) {
+                    Slog.w(TAG, "onCDCAError null! Error: " + error + " " + message);
+                    return;
                 }
-                // Generate random cookies to pass to the services that should prepare to start
-                // authenticating. Store the cookie here and wait for all services to "ack"
-                // with the cookie. Once all cookies are received, we can show the prompt
-                // and let the services start authenticating. The cookie should be non-zero.
-                final int cookie = mRandom.nextInt(Integer.MAX_VALUE - 1) + 1;
-                Slog.d(TAG, "Creating auth session. Modality: " + modality
-                        + ", cookie: " + cookie);
-                final HashMap<Integer, Integer> authenticators = new HashMap<>();
-                authenticators.put(modality, cookie);
-                mPendingAuthSession = new AuthSession(authenticators, token, sessionId, userId,
-                        receiver, opPackageName, bundle, callingUid, callingPid, callingUserId,
-                        modality, requireConfirmation);
-                mPendingAuthSession.mState = STATE_AUTH_CALLED;
-                // No polymorphism :(
-                if ((modality & TYPE_FINGERPRINT) != 0) {
-                    mFingerprintService.prepareForAuthentication(token, sessionId, userId,
-                            mInternalReceiver, opPackageName, cookie,
-                            callingUid, callingPid, callingUserId);
+                try {
+                    mConfirmDeviceCredentialReceiver.onError(error, message);
+                } catch (RemoteException e) {
+                    Slog.e(TAG, "RemoteException", e);
                 }
-                if ((modality & TYPE_IRIS) != 0) {
-                    Slog.w(TAG, "Iris unsupported");
-                }
-                if ((modality & TYPE_FACE) != 0) {
-                    mFaceService.prepareForAuthentication(requireConfirmation,
-                            token, sessionId, userId, mInternalReceiver, opPackageName,
-                            cookie, callingUid, callingPid, callingUserId);
-                }
-            } catch (RemoteException e) {
-                Slog.e(TAG, "Unable to start authentication", e);
-            }
+                mConfirmDeviceCredentialReceiver = null;
+            });
         }
 
         @Override // Binder call
         public void cancelAuthentication(IBinder token, String opPackageName)
                 throws RemoteException {
             checkPermission();
-            if (token == null || opPackageName == null) {
-                Slog.e(TAG, "Unable to cancel, one or more null arguments");
-                return;
-            }
 
-            // We need to check the current authenticators state. If we're pending confirm
-            // or idle, we need to dismiss the dialog and send an ERROR_CANCELED to the client,
-            // since we won't be getting an onError from the driver.
-            if (mCurrentAuthSession != null && mCurrentAuthSession.mState != STATE_AUTH_STARTED) {
-                mHandler.post(() -> {
-                    try {
-                        // Send error to client
-                        mCurrentAuthSession.mClientReceiver.onError(
-                                BiometricConstants.BIOMETRIC_ERROR_CANCELED,
-                                getContext().getString(
-                                        com.android.internal.R.string.biometric_error_user_canceled)
-                        );
-
-                        mCurrentAuthSession.mState = STATE_AUTH_IDLE;
-                        mCurrentAuthSession = null;
-                        mStatusBarService.hideBiometricDialog();
-                    } catch (RemoteException e) {
-                        Slog.e(TAG, "Remote exception", e);
-                    }
-                });
-            } else {
-                cancelInternal(token, opPackageName, true /* fromClient */);
-            }
+            SomeArgs args = SomeArgs.obtain();
+            args.arg1 = token;
+            args.arg2 = opPackageName;
+            mHandler.obtainMessage(MSG_CANCEL_AUTHENTICATION, args).sendToTarget();
         }
 
         @Override // Binder call
@@ -1027,31 +755,6 @@
                 Binder.restoreCallingIdentity(ident);
             }
         }
-
-        void cancelInternal(IBinder token, String opPackageName, boolean fromClient) {
-            final int callingUid = Binder.getCallingUid();
-            final int callingPid = Binder.getCallingPid();
-            final int callingUserId = UserHandle.getCallingUserId();
-            mHandler.post(() -> {
-                try {
-                    // TODO: For multiple modalities, send a single ERROR_CANCELED only when all
-                    // drivers have canceled authentication.
-                    if ((mCurrentModality & TYPE_FINGERPRINT) != 0) {
-                        mFingerprintService.cancelAuthenticationFromService(token, opPackageName,
-                                callingUid, callingPid, callingUserId, fromClient);
-                    }
-                    if ((mCurrentModality & TYPE_IRIS) != 0) {
-                        Slog.w(TAG, "Iris unsupported");
-                    }
-                    if ((mCurrentModality & TYPE_FACE) != 0) {
-                        mFaceService.cancelAuthenticationFromService(token, opPackageName,
-                                callingUid, callingPid, callingUserId, fromClient);
-                    }
-                } catch (RemoteException e) {
-                    Slog.e(TAG, "Unable to cancel authentication");
-                }
-            });
-        }
     }
 
     private void checkAppOp(String opPackageName, int callingUid) {
@@ -1088,7 +791,6 @@
         super(context);
 
         mAppOps = context.getSystemService(AppOpsManager.class);
-        mHandler = new Handler(Looper.getMainLooper());
         mEnabledOnKeyguardCallbacks = new ArrayList<>();
         mSettingObserver = new SettingObserver(mHandler);
 
@@ -1123,6 +825,10 @@
                     ServiceManager.getService(Context.FACE_SERVICE));
         }
 
+        mActivityTaskManager = ActivityTaskManager.getService();
+        mStatusBarService = IStatusBarService.Stub.asInterface(
+                ServiceManager.getService(Context.STATUS_BAR_SERVICE));
+
         // Cache the authenticators
         for (int i = 0; i < FEATURE_ID.length; i++) {
             if (hasFeature(FEATURE_ID[i])) {
@@ -1259,4 +965,491 @@
                 return false;
         }
     }
+
+    private void logDialogDismissed(int reason) {
+        if (reason == BiometricPrompt.DISMISSED_REASON_POSITIVE) {
+            // Explicit auth, authentication confirmed.
+            // Latency in this case is authenticated -> confirmed. <Biometric>Service
+            // should have the first half (first acquired -> authenticated).
+            final long latency = System.currentTimeMillis()
+                    - mCurrentAuthSession.mAuthenticatedTimeMs;
+
+            if (LoggableMonitor.DEBUG) {
+                Slog.v(LoggableMonitor.TAG, "Confirmed! Modality: " + statsModality()
+                        + ", User: " + mCurrentAuthSession.mUserId
+                        + ", IsCrypto: " + mCurrentAuthSession.isCrypto()
+                        + ", Client: " + BiometricsProtoEnums.CLIENT_BIOMETRIC_PROMPT
+                        + ", RequireConfirmation: "
+                        + mCurrentAuthSession.mRequireConfirmation
+                        + ", State: " + StatsLog.BIOMETRIC_AUTHENTICATED__STATE__CONFIRMED
+                        + ", Latency: " + latency);
+            }
+
+            StatsLog.write(StatsLog.BIOMETRIC_AUTHENTICATED,
+                    statsModality(),
+                    mCurrentAuthSession.mUserId,
+                    mCurrentAuthSession.isCrypto(),
+                    BiometricsProtoEnums.CLIENT_BIOMETRIC_PROMPT,
+                    mCurrentAuthSession.mRequireConfirmation,
+                    StatsLog.BIOMETRIC_AUTHENTICATED__STATE__CONFIRMED,
+                    latency);
+        } else {
+            int error = reason == BiometricPrompt.DISMISSED_REASON_NEGATIVE
+                    ? BiometricConstants.BIOMETRIC_ERROR_NEGATIVE_BUTTON
+                    : reason == BiometricPrompt.DISMISSED_REASON_USER_CANCEL
+                            ? BiometricConstants.BIOMETRIC_ERROR_USER_CANCELED
+                            : 0;
+            if (LoggableMonitor.DEBUG) {
+                Slog.v(LoggableMonitor.TAG, "Dismissed! Modality: " + statsModality()
+                        + ", User: " + mCurrentAuthSession.mUserId
+                        + ", IsCrypto: " + mCurrentAuthSession.isCrypto()
+                        + ", Action: " + BiometricsProtoEnums.ACTION_AUTHENTICATE
+                        + ", Client: " + BiometricsProtoEnums.CLIENT_BIOMETRIC_PROMPT
+                        + ", Error: " + error);
+            }
+            // Auth canceled
+            StatsLog.write(StatsLog.BIOMETRIC_ERROR_OCCURRED,
+                    statsModality(),
+                    mCurrentAuthSession.mUserId,
+                    mCurrentAuthSession.isCrypto(),
+                    BiometricsProtoEnums.ACTION_AUTHENTICATE,
+                    BiometricsProtoEnums.CLIENT_BIOMETRIC_PROMPT,
+                    error,
+                    0 /* vendorCode */);
+        }
+    }
+
+    private int statsModality() {
+        int modality = 0;
+        if (mCurrentAuthSession == null) {
+            return BiometricsProtoEnums.MODALITY_UNKNOWN;
+        }
+        if ((mCurrentAuthSession.mModality & BiometricAuthenticator.TYPE_FINGERPRINT)
+                != 0) {
+            modality |= BiometricsProtoEnums.MODALITY_FINGERPRINT;
+        }
+        if ((mCurrentAuthSession.mModality & BiometricAuthenticator.TYPE_IRIS) != 0) {
+            modality |= BiometricsProtoEnums.MODALITY_IRIS;
+        }
+        if ((mCurrentAuthSession.mModality & BiometricAuthenticator.TYPE_FACE) != 0) {
+            modality |= BiometricsProtoEnums.MODALITY_FACE;
+        }
+        return modality;
+    }
+
+    private void handleTaskStackChanged() {
+        try {
+            final List<ActivityManager.RunningTaskInfo> runningTasks =
+                    mActivityTaskManager.getTasks(1);
+            if (!runningTasks.isEmpty()) {
+                final String topPackage = runningTasks.get(0).topActivity.getPackageName();
+                if (mCurrentAuthSession != null
+                        && !topPackage.contentEquals(mCurrentAuthSession.mOpPackageName)) {
+                    mStatusBarService.hideBiometricDialog();
+                    mActivityTaskManager.unregisterTaskStackListener(mTaskStackListener);
+                    mCurrentAuthSession.mClientReceiver.onError(
+                            BiometricConstants.BIOMETRIC_ERROR_CANCELED,
+                            getContext().getString(
+                                    com.android.internal.R.string.biometric_error_canceled)
+                    );
+                    mCurrentAuthSession.mState = STATE_AUTH_IDLE;
+                    mCurrentAuthSession = null;
+                }
+            }
+        } catch (RemoteException e) {
+            Slog.e(TAG, "Unable to get running tasks", e);
+        }
+    }
+
+    private void handleAuthenticationSucceeded(boolean requireConfirmation, byte[] token) {
+
+        try {
+            // Should never happen, log this to catch bad HAL behavior (e.g. auth succeeded
+            // after user dismissed/canceled dialog).
+            if (mCurrentAuthSession == null) {
+                Slog.e(TAG, "onAuthenticationSucceeded(): Auth session is null");
+                return;
+            }
+
+            if (!requireConfirmation) {
+                mActivityTaskManager.unregisterTaskStackListener(mTaskStackListener);
+                KeyStore.getInstance().addAuthToken(token);
+                mCurrentAuthSession.mClientReceiver.onAuthenticationSucceeded();
+                mCurrentAuthSession.mState = STATE_AUTH_IDLE;
+                mCurrentAuthSession = null;
+            } else {
+                mCurrentAuthSession.mAuthenticatedTimeMs = System.currentTimeMillis();
+                // Store the auth token and submit it to keystore after the confirmation
+                // button has been pressed.
+                mCurrentAuthSession.mTokenEscrow = token;
+                mCurrentAuthSession.mState = STATE_AUTH_PENDING_CONFIRM;
+            }
+
+            // Notify SysUI that the biometric has been authenticated. SysUI already knows
+            // the implicit/explicit state and will react accordingly.
+            mStatusBarService.onBiometricAuthenticated(true);
+        } catch (RemoteException e) {
+            Slog.e(TAG, "Remote exception", e);
+        }
+    }
+
+    private void handleAuthenticationFailed(int cookie, boolean requireConfirmation) {
+        try {
+            // Should never happen, log this to catch bad HAL behavior (e.g. auth succeeded
+            // after user dismissed/canceled dialog).
+            if (mCurrentAuthSession == null) {
+                Slog.e(TAG, "onAuthenticationFailed(): Auth session is null");
+                return;
+            }
+
+            mStatusBarService.onBiometricAuthenticated(false);
+
+            // TODO: This logic will need to be updated if BP is multi-modal
+            if ((mCurrentAuthSession.mModality & TYPE_FACE) != 0) {
+                // Pause authentication. onBiometricAuthenticated(false) causes the
+                // dialog to show a "try again" button for passive modalities.
+                mCurrentAuthSession.mState = STATE_AUTH_PAUSED;
+            }
+
+            mCurrentAuthSession.mClientReceiver.onAuthenticationFailed();
+        } catch (RemoteException e) {
+            Slog.e(TAG, "Remote exception", e);
+        }
+    }
+
+    private void handleOnError(int cookie, int error, String message) {
+        Slog.d(TAG, "Error: " + error + " cookie: " + cookie);
+        // Errors can either be from the current auth session or the pending auth session.
+        // The pending auth session may receive errors such as ERROR_LOCKOUT before
+        // it becomes the current auth session. Similarly, the current auth session may
+        // receive errors such as ERROR_CANCELED while the pending auth session is preparing
+        // to be started. Thus we must match error messages with their cookies to be sure
+        // of their intended receivers.
+        try {
+            if (mCurrentAuthSession != null && mCurrentAuthSession.containsCookie(cookie)) {
+                if (mCurrentAuthSession.mState == STATE_AUTH_STARTED) {
+                    mStatusBarService.onBiometricError(message);
+                    if (error == BiometricConstants.BIOMETRIC_ERROR_CANCELED) {
+                        mActivityTaskManager.unregisterTaskStackListener(
+                                mTaskStackListener);
+                        mCurrentAuthSession.mClientReceiver.onError(error, message);
+                        mCurrentAuthSession.mState = STATE_AUTH_IDLE;
+                        mCurrentAuthSession = null;
+                        mStatusBarService.hideBiometricDialog();
+                    } else {
+                        // Send errors after the dialog is dismissed.
+                        mHandler.postDelayed(() -> {
+                            try {
+                                if (mCurrentAuthSession != null) {
+                                    mActivityTaskManager.unregisterTaskStackListener(
+                                            mTaskStackListener);
+                                    mCurrentAuthSession.mClientReceiver.onError(error,
+                                            message);
+                                    mCurrentAuthSession.mState = STATE_AUTH_IDLE;
+                                    mCurrentAuthSession = null;
+                                }
+                            } catch (RemoteException e) {
+                                Slog.e(TAG, "Remote exception", e);
+                            }
+                        }, BiometricPrompt.HIDE_DIALOG_DELAY);
+                    }
+                } else if (mCurrentAuthSession.mState == STATE_AUTH_PAUSED) {
+                    // In the "try again" state, we should forward canceled errors to
+                    // the client and and clean up.
+                    mCurrentAuthSession.mClientReceiver.onError(error, message);
+                    mStatusBarService.onBiometricError(message);
+                    mActivityTaskManager.unregisterTaskStackListener(
+                            mTaskStackListener);
+                    mCurrentAuthSession.mState = STATE_AUTH_IDLE;
+                    mCurrentAuthSession = null;
+                } else {
+                    Slog.e(TAG, "Impossible session error state: "
+                            + mCurrentAuthSession.mState);
+                }
+            } else if (mPendingAuthSession != null
+                    && mPendingAuthSession.containsCookie(cookie)) {
+                if (mPendingAuthSession.mState == STATE_AUTH_CALLED) {
+                    mPendingAuthSession.mClientReceiver.onError(error, message);
+                    mPendingAuthSession.mState = STATE_AUTH_IDLE;
+                    mPendingAuthSession = null;
+                } else {
+                    Slog.e(TAG, "Impossible pending session error state: "
+                            + mPendingAuthSession.mState);
+                }
+            }
+        } catch (RemoteException e) {
+            Slog.e(TAG, "Remote exception", e);
+        }
+    }
+
+    private void handleOnAcquired(int acquiredInfo, String message) {
+        // Should never happen, log this to catch bad HAL behavior (e.g. auth succeeded
+        // after user dismissed/canceled dialog).
+        if (mCurrentAuthSession == null) {
+            Slog.e(TAG, "onAcquired(): Auth session is null");
+            return;
+        }
+
+        if (acquiredInfo != BiometricConstants.BIOMETRIC_ACQUIRED_GOOD) {
+            try {
+                mStatusBarService.onBiometricHelp(message);
+            } catch (RemoteException e) {
+                Slog.e(TAG, "Remote exception", e);
+            }
+        }
+    }
+
+    private void handleOnDismissed(int reason) {
+        if (mCurrentAuthSession == null) {
+            Slog.e(TAG, "onDialogDismissed: " + reason + ", auth session null");
+            return;
+        }
+
+        logDialogDismissed(reason);
+
+        try {
+            if (reason != BiometricPrompt.DISMISSED_REASON_POSITIVE) {
+                // Positive button is used by passive modalities as a "confirm" button,
+                // do not send to client
+                mCurrentAuthSession.mClientReceiver.onDialogDismissed(reason);
+                // Cancel authentication. Skip the token/package check since we are cancelling
+                // from system server. The interface is permission protected so this is fine.
+                cancelInternal(null /* token */, null /* package */, false /* fromClient */);
+            }
+            if (reason == BiometricPrompt.DISMISSED_REASON_USER_CANCEL) {
+                mCurrentAuthSession.mClientReceiver.onError(
+                        BiometricConstants.BIOMETRIC_ERROR_USER_CANCELED,
+                        getContext().getString(
+                                com.android.internal.R.string.biometric_error_user_canceled));
+            } else if (reason == BiometricPrompt.DISMISSED_REASON_POSITIVE) {
+                // Have the service send the token to KeyStore, and send onAuthenticated
+                // to the application
+                KeyStore.getInstance().addAuthToken(mCurrentAuthSession.mTokenEscrow);
+                mCurrentAuthSession.mClientReceiver.onAuthenticationSucceeded();
+            }
+            mActivityTaskManager.unregisterTaskStackListener(mTaskStackListener);
+            mCurrentAuthSession.mState = STATE_AUTH_IDLE;
+            mCurrentAuthSession = null;
+        } catch (RemoteException e) {
+            Slog.e(TAG, "Remote exception", e);
+        }
+    }
+
+    private void handleOnTryAgainPressed() {
+        Slog.d(TAG, "onTryAgainPressed");
+        // No need to check permission, since it can only be invoked by SystemUI
+        // (or system server itself).
+        authenticateInternal(mCurrentAuthSession.mToken,
+                mCurrentAuthSession.mSessionId,
+                mCurrentAuthSession.mUserId,
+                mCurrentAuthSession.mClientReceiver,
+                mCurrentAuthSession.mOpPackageName,
+                mCurrentAuthSession.mBundle,
+                mCurrentAuthSession.mCallingUid,
+                mCurrentAuthSession.mCallingPid,
+                mCurrentAuthSession.mCallingUserId,
+                mCurrentAuthSession.mModality);
+    }
+
+    private void handleOnReadyForAuthentication(int cookie, boolean requireConfirmation,
+            int userId) {
+        Iterator it = mPendingAuthSession.mModalitiesWaiting.entrySet().iterator();
+        while (it.hasNext()) {
+            Map.Entry<Integer, Integer> pair = (Map.Entry) it.next();
+            if (pair.getValue() == cookie) {
+                mPendingAuthSession.mModalitiesMatched.put(pair.getKey(), pair.getValue());
+                mPendingAuthSession.mModalitiesWaiting.remove(pair.getKey());
+                Slog.d(TAG, "Matched cookie: " + cookie + ", "
+                        + mPendingAuthSession.mModalitiesWaiting.size() + " remaining");
+                break;
+            }
+        }
+
+        if (mPendingAuthSession.mModalitiesWaiting.isEmpty()) {
+            final boolean continuing = mCurrentAuthSession != null
+                    && mCurrentAuthSession.mState == STATE_AUTH_PAUSED;
+
+            mCurrentAuthSession = mPendingAuthSession;
+            mPendingAuthSession = null;
+
+            mCurrentAuthSession.mState = STATE_AUTH_STARTED;
+            try {
+                int modality = TYPE_NONE;
+                it = mCurrentAuthSession.mModalitiesMatched.entrySet().iterator();
+                while (it.hasNext()) {
+                    Map.Entry<Integer, Integer> pair = (Map.Entry) it.next();
+                    if (pair.getKey() == TYPE_FINGERPRINT) {
+                        mFingerprintService.startPreparedClient(pair.getValue());
+                    } else if (pair.getKey() == TYPE_IRIS) {
+                        Slog.e(TAG, "Iris unsupported");
+                    } else if (pair.getKey() == TYPE_FACE) {
+                        mFaceService.startPreparedClient(pair.getValue());
+                    } else {
+                        Slog.e(TAG, "Unknown modality: " + pair.getKey());
+                    }
+                    modality |= pair.getKey();
+                }
+
+                if (!continuing) {
+                    mStatusBarService.showBiometricDialog(mCurrentAuthSession.mBundle,
+                            mInternalReceiver, modality, requireConfirmation, userId);
+                    mActivityTaskManager.registerTaskStackListener(mTaskStackListener);
+                }
+            } catch (RemoteException e) {
+                Slog.e(TAG, "Remote exception", e);
+            }
+        }
+    }
+
+    private void handleAuthenticate(IBinder token, long sessionId, int userId,
+            IBiometricServiceReceiver receiver, String opPackageName, Bundle bundle,
+            int callingUid, int callingPid, int callingUserId) {
+
+        mHandler.post(() -> {
+            final Pair<Integer, Integer> result = checkAndGetBiometricModality(userId);
+            final int modality = result.first;
+            final int error = result.second;
+
+            // Check for errors, notify callback, and return
+            if (error != BiometricConstants.BIOMETRIC_SUCCESS) {
+                try {
+                    final String hardwareUnavailable =
+                            getContext().getString(R.string.biometric_error_hw_unavailable);
+                    switch (error) {
+                        case BiometricConstants.BIOMETRIC_ERROR_HW_NOT_PRESENT:
+                            receiver.onError(error, hardwareUnavailable);
+                            break;
+                        case BiometricConstants.BIOMETRIC_ERROR_HW_UNAVAILABLE:
+                            receiver.onError(error, hardwareUnavailable);
+                            break;
+                        case BiometricConstants.BIOMETRIC_ERROR_NO_BIOMETRICS:
+                            receiver.onError(error,
+                                    getErrorString(modality, error, 0 /* vendorCode */));
+                            break;
+                        default:
+                            Slog.e(TAG, "Unhandled error");
+                            break;
+                    }
+                } catch (RemoteException e) {
+                    Slog.e(TAG, "Unable to send error", e);
+                }
+                return;
+            }
+
+            mCurrentModality = modality;
+
+            // Start preparing for authentication. Authentication starts when
+            // all modalities requested have invoked onReadyForAuthentication.
+            authenticateInternal(token, sessionId, userId, receiver, opPackageName, bundle,
+                    callingUid, callingPid, callingUserId, modality);
+        });
+    }
+
+    /**
+     * authenticate() (above) which is called from BiometricPrompt determines which
+     * modality/modalities to start authenticating with. authenticateInternal() should only be
+     * used for:
+     * 1) Preparing <Biometric>Services for authentication when BiometricPrompt#authenticate is,
+     *    invoked, shortly after which BiometricPrompt is shown and authentication starts
+     * 2) Preparing <Biometric>Services for authentication when BiometricPrompt is already shown
+     *    and the user has pressed "try again"
+     */
+    private void authenticateInternal(IBinder token, long sessionId, int userId,
+            IBiometricServiceReceiver receiver, String opPackageName, Bundle bundle,
+            int callingUid, int callingPid, int callingUserId, int modality) {
+        try {
+            boolean requireConfirmation = bundle.getBoolean(
+                    BiometricPrompt.KEY_REQUIRE_CONFIRMATION, true /* default */);
+            if ((modality & TYPE_FACE) != 0) {
+                // Check if the user has forced confirmation to be required in Settings.
+                requireConfirmation = requireConfirmation
+                        || mSettingObserver.getFaceAlwaysRequireConfirmation();
+            }
+            // Generate random cookies to pass to the services that should prepare to start
+            // authenticating. Store the cookie here and wait for all services to "ack"
+            // with the cookie. Once all cookies are received, we can show the prompt
+            // and let the services start authenticating. The cookie should be non-zero.
+            final int cookie = mRandom.nextInt(Integer.MAX_VALUE - 1) + 1;
+            Slog.d(TAG, "Creating auth session. Modality: " + modality
+                    + ", cookie: " + cookie);
+            final HashMap<Integer, Integer> authenticators = new HashMap<>();
+            authenticators.put(modality, cookie);
+            mPendingAuthSession = new AuthSession(authenticators, token, sessionId, userId,
+                    receiver, opPackageName, bundle, callingUid, callingPid, callingUserId,
+                    modality, requireConfirmation);
+            mPendingAuthSession.mState = STATE_AUTH_CALLED;
+            // No polymorphism :(
+            if ((modality & TYPE_FINGERPRINT) != 0) {
+                mFingerprintService.prepareForAuthentication(token, sessionId, userId,
+                        mInternalReceiver, opPackageName, cookie,
+                        callingUid, callingPid, callingUserId);
+            }
+            if ((modality & TYPE_IRIS) != 0) {
+                Slog.w(TAG, "Iris unsupported");
+            }
+            if ((modality & TYPE_FACE) != 0) {
+                mFaceService.prepareForAuthentication(requireConfirmation,
+                        token, sessionId, userId, mInternalReceiver, opPackageName,
+                        cookie, callingUid, callingPid, callingUserId);
+            }
+        } catch (RemoteException e) {
+            Slog.e(TAG, "Unable to start authentication", e);
+        }
+    }
+
+    private void handleCancelAuthentication(IBinder token, String opPackageName) {
+        if (token == null || opPackageName == null) {
+            Slog.e(TAG, "Unable to cancel, one or more null arguments");
+            return;
+        }
+
+        // We need to check the current authenticators state. If we're pending confirm
+        // or idle, we need to dismiss the dialog and send an ERROR_CANCELED to the client,
+        // since we won't be getting an onError from the driver.
+        if (mCurrentAuthSession != null && mCurrentAuthSession.mState != STATE_AUTH_STARTED) {
+            try {
+                // Send error to client
+                mCurrentAuthSession.mClientReceiver.onError(
+                        BiometricConstants.BIOMETRIC_ERROR_CANCELED,
+                        getContext().getString(
+                                com.android.internal.R.string.biometric_error_user_canceled)
+                );
+
+                mCurrentAuthSession.mState = STATE_AUTH_IDLE;
+                mCurrentAuthSession = null;
+                mStatusBarService.hideBiometricDialog();
+            } catch (RemoteException e) {
+                Slog.e(TAG, "Remote exception", e);
+            }
+        } else {
+            cancelInternal(token, opPackageName, true /* fromClient */);
+        }
+    }
+
+
+    void cancelInternal(IBinder token, String opPackageName, boolean fromClient) {
+        final int callingUid = Binder.getCallingUid();
+        final int callingPid = Binder.getCallingPid();
+        final int callingUserId = UserHandle.getCallingUserId();
+        mHandler.post(() -> {
+            try {
+                // TODO: For multiple modalities, send a single ERROR_CANCELED only when all
+                // drivers have canceled authentication.
+                if ((mCurrentModality & TYPE_FINGERPRINT) != 0) {
+                    mFingerprintService.cancelAuthenticationFromService(token, opPackageName,
+                            callingUid, callingPid, callingUserId, fromClient);
+                }
+                if ((mCurrentModality & TYPE_IRIS) != 0) {
+                    Slog.w(TAG, "Iris unsupported");
+                }
+                if ((mCurrentModality & TYPE_FACE) != 0) {
+                    mFaceService.cancelAuthenticationFromService(token, opPackageName,
+                            callingUid, callingPid, callingUserId, fromClient);
+                }
+            } catch (RemoteException e) {
+                Slog.e(TAG, "Unable to cancel authentication");
+            }
+        });
+    }
+
 }
diff --git a/services/core/java/com/android/server/biometrics/BiometricServiceBase.java b/services/core/java/com/android/server/biometrics/BiometricServiceBase.java
index ebb9e06..3e48445 100644
--- a/services/core/java/com/android/server/biometrics/BiometricServiceBase.java
+++ b/services/core/java/com/android/server/biometrics/BiometricServiceBase.java
@@ -1223,6 +1223,9 @@
                     BiometricsProtoEnums.ISSUE_UNKNOWN_TEMPLATE_ENROLLED_HAL);
         } else {
             clearEnumerateState();
+            if (mPendingClient != null) {
+                startClient(mPendingClient, false /* initiatedByClient */);
+            }
         }
     }
 
diff --git a/services/core/java/com/android/server/connectivity/DefaultNetworkMetrics.java b/services/core/java/com/android/server/connectivity/DefaultNetworkMetrics.java
index e43d152..96a202f 100644
--- a/services/core/java/com/android/server/connectivity/DefaultNetworkMetrics.java
+++ b/services/core/java/com/android/server/connectivity/DefaultNetworkMetrics.java
@@ -163,8 +163,8 @@
         LinkProperties lp = nai.linkProperties;
         ev.netId = nai.network().netId;
         ev.transports |= BitUtils.packBits(nai.networkCapabilities.getTransportTypes());
-        ev.ipv4 |= lp.hasIPv4Address() && lp.hasIPv4DefaultRoute();
-        ev.ipv6 |= lp.hasGlobalIPv6Address() && lp.hasIPv6DefaultRoute();
+        ev.ipv4 |= lp.hasIpv4Address() && lp.hasIpv4DefaultRoute();
+        ev.ipv6 |= lp.hasGlobalIpv6Address() && lp.hasIpv6DefaultRoute();
     }
 
     private static void printEvent(long localTimeMs, PrintWriter pw, DefaultNetworkEvent ev) {
diff --git a/services/core/java/com/android/server/connectivity/KeepaliveTracker.java b/services/core/java/com/android/server/connectivity/KeepaliveTracker.java
index 35d6860..0e3d82c 100644
--- a/services/core/java/com/android/server/connectivity/KeepaliveTracker.java
+++ b/services/core/java/com/android/server/connectivity/KeepaliveTracker.java
@@ -42,7 +42,6 @@
 import android.net.SocketKeepalive.InvalidPacketException;
 import android.net.SocketKeepalive.InvalidSocketException;
 import android.net.TcpKeepalivePacketData;
-import android.net.TcpKeepalivePacketData.TcpSocketInfo;
 import android.net.util.IpUtils;
 import android.os.Binder;
 import android.os.Handler;
@@ -492,19 +491,14 @@
             return;
         }
 
-        TcpKeepalivePacketData packet = null;
+        final TcpKeepalivePacketData packet;
         try {
-            TcpSocketInfo tsi = TcpKeepaliveController.switchToRepairMode(fd);
-            packet = TcpKeepalivePacketData.tcpKeepalivePacket(tsi);
+            packet = TcpKeepaliveController.getTcpKeepalivePacket(fd);
         } catch (InvalidPacketException | InvalidSocketException e) {
-            try {
-                TcpKeepaliveController.switchOutOfRepairMode(fd);
-            } catch (ErrnoException e1) {
-                Log.e(TAG, "Couldn't move fd out of repair mode after failure to start keepalive");
-            }
             notifyErrorCallback(cb, e.error);
             return;
         }
+
         KeepaliveInfo ki = new KeepaliveInfo(cb, nai, packet, intervalSeconds,
                 KeepaliveInfo.TYPE_TCP, fd);
         Log.d(TAG, "Created keepalive: " + ki.toString());
diff --git a/services/core/java/com/android/server/connectivity/Nat464Xlat.java b/services/core/java/com/android/server/connectivity/Nat464Xlat.java
index 2646d76..262ba7a 100644
--- a/services/core/java/com/android/server/connectivity/Nat464Xlat.java
+++ b/services/core/java/com/android/server/connectivity/Nat464Xlat.java
@@ -107,8 +107,8 @@
         // Only run clat on networks that have a global IPv6 address and don't have a native IPv4
         // address.
         LinkProperties lp = nai.linkProperties;
-        final boolean isIpv6OnlyNetwork = (lp != null) && lp.hasGlobalIPv6Address()
-                && !lp.hasIPv4Address();
+        final boolean isIpv6OnlyNetwork = (lp != null) && lp.hasGlobalIpv6Address()
+                && !lp.hasIpv4Address();
 
         // If the network tells us it doesn't use clat, respect that.
         final boolean skip464xlat = (nai.netMisc() != null) && nai.netMisc().skip464xlat;
diff --git a/services/core/java/com/android/server/connectivity/NetworkDiagnostics.java b/services/core/java/com/android/server/connectivity/NetworkDiagnostics.java
index c471f0c..948c690 100644
--- a/services/core/java/com/android/server/connectivity/NetworkDiagnostics.java
+++ b/services/core/java/com/android/server/connectivity/NetworkDiagnostics.java
@@ -34,10 +34,12 @@
 
 import com.android.internal.util.IndentingPrintWriter;
 
+import libcore.io.IoUtils;
+
 import java.io.Closeable;
 import java.io.FileDescriptor;
-import java.io.InterruptedIOException;
 import java.io.IOException;
+import java.io.InterruptedIOException;
 import java.net.Inet4Address;
 import java.net.Inet6Address;
 import java.net.InetAddress;
@@ -48,17 +50,13 @@
 import java.net.UnknownHostException;
 import java.nio.ByteBuffer;
 import java.nio.charset.StandardCharsets;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
-import java.util.Arrays;
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.Random;
-
-import libcore.io.IoUtils;
-
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
 
 /**
  * NetworkDiagnostics
@@ -186,7 +184,7 @@
         // TODO: we could use mLinkProperties.isReachable(TEST_DNS6) here, because we won't set any
         // DNS servers for which isReachable() is false, but since this is diagnostic code, be extra
         // careful.
-        if (mLinkProperties.hasGlobalIPv6Address() || mLinkProperties.hasIPv6DefaultRoute()) {
+        if (mLinkProperties.hasGlobalIpv6Address() || mLinkProperties.hasIpv6DefaultRoute()) {
             mLinkProperties.addDnsServer(TEST_DNS6);
         }
 
diff --git a/services/core/java/com/android/server/connectivity/TcpKeepaliveController.java b/services/core/java/com/android/server/connectivity/TcpKeepaliveController.java
index 3e21b5b..f4d9006 100644
--- a/services/core/java/com/android/server/connectivity/TcpKeepaliveController.java
+++ b/services/core/java/com/android/server/connectivity/TcpKeepaliveController.java
@@ -28,8 +28,10 @@
 
 import android.annotation.NonNull;
 import android.net.NetworkUtils;
+import android.net.SocketKeepalive.InvalidPacketException;
 import android.net.SocketKeepalive.InvalidSocketException;
-import android.net.TcpKeepalivePacketData.TcpSocketInfo;
+import android.net.TcpKeepalivePacketData;
+import android.net.TcpKeepalivePacketDataParcelable;
 import android.net.TcpRepairWindow;
 import android.os.Handler;
 import android.os.MessageQueue;
@@ -44,7 +46,6 @@
 import com.android.server.connectivity.KeepaliveTracker.KeepaliveInfo;
 
 import java.io.FileDescriptor;
-import java.net.InetAddress;
 import java.net.InetSocketAddress;
 import java.net.SocketAddress;
 import java.net.SocketException;
@@ -103,26 +104,30 @@
         mFdHandlerQueue = connectivityServiceHandler.getLooper().getQueue();
     }
 
+    /** Build tcp keepalive packet. */
+    public static TcpKeepalivePacketData getTcpKeepalivePacket(@NonNull FileDescriptor fd)
+            throws InvalidPacketException, InvalidSocketException {
+        try {
+            final TcpKeepalivePacketDataParcelable tcpDetails = switchToRepairMode(fd);
+            return TcpKeepalivePacketData.tcpKeepalivePacket(tcpDetails);
+        } catch (InvalidPacketException | InvalidSocketException e) {
+            switchOutOfRepairMode(fd);
+            throw e;
+        }
+    }
     /**
-     * Switch the tcp socket to repair mode and query tcp socket information.
+     * Switch the tcp socket to repair mode and query detail tcp information.
      *
-     * @param fd the fd of socket on which to use keepalive offload
-     * @return a {@link TcpKeepalivePacketData#TcpSocketInfo} object for current
+     * @param fd the fd of socket on which to use keepalive offload.
+     * @return a {@link TcpKeepalivePacketData#TcpKeepalivePacketDataParcelable} object for current
      * tcp/ip information.
      */
-    // TODO : make this private. It's far too confusing that this gets called from outside
-    // at a time that nobody can understand.
-    public static TcpSocketInfo switchToRepairMode(FileDescriptor fd)
+    private static TcpKeepalivePacketDataParcelable switchToRepairMode(FileDescriptor fd)
             throws InvalidSocketException {
         if (DBG) Log.i(TAG, "switchToRepairMode to start tcp keepalive : " + fd);
+        final TcpKeepalivePacketDataParcelable tcpDetails = new TcpKeepalivePacketDataParcelable();
         final SocketAddress srcSockAddr;
         final SocketAddress dstSockAddr;
-        final InetAddress srcAddress;
-        final InetAddress dstAddress;
-        final int srcPort;
-        final int dstPort;
-        int seq;
-        final int ack;
         final TcpRepairWindow trw;
 
         // Query source address and port.
@@ -133,8 +138,8 @@
             throw new InvalidSocketException(ERROR_INVALID_SOCKET, e);
         }
         if (srcSockAddr instanceof InetSocketAddress) {
-            srcAddress = getAddress((InetSocketAddress) srcSockAddr);
-            srcPort = getPort((InetSocketAddress) srcSockAddr);
+            tcpDetails.srcAddress = getAddress((InetSocketAddress) srcSockAddr);
+            tcpDetails.srcPort = getPort((InetSocketAddress) srcSockAddr);
         } else {
             Log.e(TAG, "Invalid or mismatched SocketAddress");
             throw new InvalidSocketException(ERROR_INVALID_SOCKET);
@@ -147,8 +152,8 @@
             throw new InvalidSocketException(ERROR_INVALID_SOCKET, e);
         }
         if (dstSockAddr instanceof InetSocketAddress) {
-            dstAddress = getAddress((InetSocketAddress) dstSockAddr);
-            dstPort = getPort((InetSocketAddress) dstSockAddr);
+            tcpDetails.dstAddress = getAddress((InetSocketAddress) dstSockAddr);
+            tcpDetails.dstPort = getPort((InetSocketAddress) dstSockAddr);
         } else {
             Log.e(TAG, "Invalid or mismatched peer SocketAddress");
             throw new InvalidSocketException(ERROR_INVALID_SOCKET);
@@ -157,28 +162,37 @@
         // Query sequence and ack number
         dropAllIncomingPackets(fd, true);
         try {
-            // Enter tcp repair mode.
+            // Switch to tcp repair mode.
             Os.setsockoptInt(fd, IPPROTO_TCP, TCP_REPAIR, TCP_REPAIR_ON);
+
             // Check if socket is idle.
             if (!isSocketIdle(fd)) {
+                Log.e(TAG, "Socket is not idle");
                 throw new InvalidSocketException(ERROR_SOCKET_NOT_IDLE);
             }
             // Query write sequence number from SEND_QUEUE.
             Os.setsockoptInt(fd, IPPROTO_TCP, TCP_REPAIR_QUEUE, TCP_SEND_QUEUE);
-            seq = Os.getsockoptInt(fd, IPPROTO_TCP, TCP_QUEUE_SEQ);
+            tcpDetails.seq = Os.getsockoptInt(fd, IPPROTO_TCP, TCP_QUEUE_SEQ);
             // Query read sequence number from RECV_QUEUE.
             Os.setsockoptInt(fd, IPPROTO_TCP, TCP_REPAIR_QUEUE, TCP_RECV_QUEUE);
-            ack = Os.getsockoptInt(fd, IPPROTO_TCP, TCP_QUEUE_SEQ);
+            tcpDetails.ack = Os.getsockoptInt(fd, IPPROTO_TCP, TCP_QUEUE_SEQ);
             // Switch to NO_QUEUE to prevent illegal socket read/write in repair mode.
             Os.setsockoptInt(fd, IPPROTO_TCP, TCP_REPAIR_QUEUE, TCP_NO_QUEUE);
             // Finally, check if socket is still idle. TODO : this check needs to move to
             // after starting polling to prevent a race.
-            if (!isSocketIdle(fd)) {
+            if (!isReceiveQueueEmpty(fd)) {
+                Log.e(TAG, "Fatal: receive queue of this socket is not empty");
                 throw new InvalidSocketException(ERROR_INVALID_SOCKET);
             }
+            if (!isSendQueueEmpty(fd)) {
+                Log.e(TAG, "Socket is not idle");
+                throw new InvalidSocketException(ERROR_SOCKET_NOT_IDLE);
+            }
 
             // Query tcp window size.
             trw = NetworkUtils.getTcpRepairWindow(fd);
+            tcpDetails.rcvWnd = trw.rcvWnd;
+            tcpDetails.rcvWndScale = trw.rcvWndScale;
         } catch (ErrnoException e) {
             Log.e(TAG, "Exception reading TCP state from socket", e);
             if (e.errno == ENOPROTOOPT) {
@@ -194,10 +208,9 @@
 
         // Keepalive sequence number is last sequence number - 1. If it couldn't be retrieved,
         // then it must be set to -1, so decrement in all cases.
-        seq = seq - 1;
+        tcpDetails.seq = tcpDetails.seq - 1;
 
-        return new TcpSocketInfo(srcAddress, srcPort, dstAddress, dstPort, seq, ack, trw.rcvWnd,
-                trw.rcvWndScale);
+        return tcpDetails;
     }
 
     /**
@@ -205,10 +218,13 @@
      *
      * @param fd the fd of socket to switch back to normal.
      */
-    // TODO : make this private.
-    public static void switchOutOfRepairMode(@NonNull final FileDescriptor fd)
-            throws ErrnoException {
-        Os.setsockoptInt(fd, IPPROTO_TCP, TCP_REPAIR, TCP_REPAIR_OFF);
+    private static void switchOutOfRepairMode(@NonNull final FileDescriptor fd) {
+        try {
+            Os.setsockoptInt(fd, IPPROTO_TCP, TCP_REPAIR, TCP_REPAIR_OFF);
+        } catch (ErrnoException e) {
+            Log.e(TAG, "Cannot switch socket out of repair mode", e);
+            // Well, there is not much to do here to recover
+        }
     }
 
     /**
@@ -262,17 +278,12 @@
             mListeners.remove(slot);
         }
         mFdHandlerQueue.removeOnFileDescriptorEventListener(fd);
-        try {
-            if (DBG) Log.d(TAG, "Moving socket out of repair mode for stop : " + fd);
-            switchOutOfRepairMode(fd);
-        } catch (ErrnoException e) {
-            Log.e(TAG, "Cannot switch socket out of repair mode", e);
-            // Well, there is not much to do here to recover
-        }
+        if (DBG) Log.d(TAG, "Moving socket out of repair mode for stop : " + fd);
+        switchOutOfRepairMode(fd);
     }
 
-    private static InetAddress getAddress(InetSocketAddress inetAddr) {
-        return inetAddr.getAddress();
+    private static byte [] getAddress(InetSocketAddress inetAddr) {
+        return inetAddr.getAddress().getAddress();
     }
 
     private static int getPort(InetSocketAddress inetAddr) {
diff --git a/services/core/java/com/android/server/connectivity/tethering/IPv6TetheringCoordinator.java b/services/core/java/com/android/server/connectivity/tethering/IPv6TetheringCoordinator.java
index 1000148..38eb0bc 100644
--- a/services/core/java/com/android/server/connectivity/tethering/IPv6TetheringCoordinator.java
+++ b/services/core/java/com/android/server/connectivity/tethering/IPv6TetheringCoordinator.java
@@ -17,7 +17,6 @@
 package com.android.server.connectivity.tethering;
 
 import android.net.ConnectivityManager;
-import android.net.ip.IpServer;
 import android.net.IpPrefix;
 import android.net.LinkAddress;
 import android.net.LinkProperties;
@@ -25,6 +24,7 @@
 import android.net.NetworkCapabilities;
 import android.net.NetworkState;
 import android.net.RouteInfo;
+import android.net.ip.IpServer;
 import android.net.util.NetworkConstants;
 import android.net.util.SharedLog;
 import android.util.Log;
@@ -191,7 +191,7 @@
         if (currentActive != null && currentActive.ipServer == ipServer) {
             final LinkProperties lp = getIPv6OnlyLinkProperties(
                     mUpstreamNetworkState.linkProperties);
-            if (lp.hasIPv6DefaultRoute() && lp.hasGlobalIPv6Address()) {
+            if (lp.hasIpv6DefaultRoute() && lp.hasGlobalIpv6Address()) {
                 return lp;
             }
         }
diff --git a/services/core/java/com/android/server/connectivity/tethering/TetheringInterfaceUtils.java b/services/core/java/com/android/server/connectivity/tethering/TetheringInterfaceUtils.java
index 6c7ff91..0ef3805 100644
--- a/services/core/java/com/android/server/connectivity/tethering/TetheringInterfaceUtils.java
+++ b/services/core/java/com/android/server/connectivity/tethering/TetheringInterfaceUtils.java
@@ -67,14 +67,14 @@
         // because "[t]he 3GPP network allocates each default bearer a unique
         // /64 prefix", per RFC 6459, Section 5.2.
         final boolean canTether =
-                (ns != null) && (ns.network != null) &&
-                (ns.linkProperties != null) && (ns.networkCapabilities != null) &&
+                (ns != null) && (ns.network != null)
+                && (ns.linkProperties != null) && (ns.networkCapabilities != null)
                 // At least one upstream DNS server:
-                ns.linkProperties.hasIPv6DnsServer() &&
+                && ns.linkProperties.hasIpv6DnsServer()
                 // Minimal amount of IPv6 provisioning:
-                ns.linkProperties.hasGlobalIPv6Address() &&
+                && ns.linkProperties.hasGlobalIpv6Address()
                 // Temporary approximation of "dedicated prefix":
-                ns.networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR);
+                && ns.networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR);
 
         return canTether
                 ? getInterfaceForDestination(ns.linkProperties, Inet6Address.ANY)
diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java
index b79ead0..e2ea42e 100644
--- a/services/core/java/com/android/server/display/DisplayPowerController.java
+++ b/services/core/java/com/android/server/display/DisplayPowerController.java
@@ -34,6 +34,7 @@
 import android.hardware.display.BrightnessConfiguration;
 import android.hardware.display.DisplayManagerInternal.DisplayPowerCallbacks;
 import android.hardware.display.DisplayManagerInternal.DisplayPowerRequest;
+import android.metrics.LogMaker;
 import android.net.Uri;
 import android.os.Handler;
 import android.os.Looper;
@@ -51,6 +52,8 @@
 import android.view.Display;
 
 import com.android.internal.app.IBatteryStats;
+import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.server.LocalServices;
 import com.android.server.am.BatteryStatsService;
 import com.android.server.display.whitebalance.DisplayWhiteBalanceController;
@@ -731,6 +734,7 @@
     private void updatePowerState() {
         // Update the power state request.
         final boolean mustNotify;
+        final int previousPolicy;
         boolean mustInitialize = false;
 
         synchronized (mLock) {
@@ -745,12 +749,18 @@
                 mPendingWaitForNegativeProximityLocked = false;
                 mPendingRequestChangedLocked = false;
                 mustInitialize = true;
+                // Assume we're on and bright until told otherwise, since that's the state we turn
+                // on in.
+                previousPolicy = DisplayPowerRequest.POLICY_BRIGHT;
             } else if (mPendingRequestChangedLocked) {
+                previousPolicy = mPowerRequest.policy;
                 mPowerRequest.copyFrom(mPendingRequestLocked);
                 mWaitingForNegativeProximity |= mPendingWaitForNegativeProximityLocked;
                 mPendingWaitForNegativeProximityLocked = false;
                 mPendingRequestChangedLocked = false;
                 mDisplayReadyLocked = false;
+            } else {
+                previousPolicy = mPowerRequest.policy;
             }
 
             mustNotify = !mDisplayReadyLocked;
@@ -1103,6 +1113,10 @@
 
         // Record if dozing for future comparison.
         mDozing = state != Display.STATE_ON;
+
+        if (previousPolicy != mPowerRequest.policy) {
+            logDisplayPolicyChanged(mPowerRequest.policy);
+        }
     }
 
     @Override
@@ -1523,6 +1537,13 @@
         mHandler.post(mOnStateChangedRunnable);
     }
 
+    private void logDisplayPolicyChanged(int newPolicy) {
+        LogMaker log = new LogMaker(MetricsEvent.DISPLAY_POLICY);
+        log.setType(MetricsEvent.TYPE_UPDATE);
+        log.setSubtype(newPolicy);
+        MetricsLogger.action(log);
+    }
+
     private void handleSettingsChange(boolean userSwitch) {
         mPendingScreenBrightnessSetting = getScreenBrightnessSetting();
         if (userSwitch) {
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 45567e5..ed420b7 100644
--- a/services/core/java/com/android/server/display/color/ColorDisplayService.java
+++ b/services/core/java/com/android/server/display/color/ColorDisplayService.java
@@ -1417,7 +1417,7 @@
                 mCurrentColorTemperature = cct;
 
                 // Adapt the display's nominal white point to match the requested CCT value
-                mCurrentColorTemperatureXYZ = ColorSpace.cctToIlluminantdXyz(cct);
+                mCurrentColorTemperatureXYZ = ColorSpace.cctToXyz(cct);
 
                 mChromaticAdaptationMatrix =
                         ColorSpace.chromaticAdaptation(ColorSpace.Adaptation.BRADFORD,
diff --git a/services/core/java/com/android/server/infra/AbstractMasterSystemService.java b/services/core/java/com/android/server/infra/AbstractMasterSystemService.java
index 3c27bf2..430203d 100644
--- a/services/core/java/com/android/server/infra/AbstractMasterSystemService.java
+++ b/services/core/java/com/android/server/infra/AbstractMasterSystemService.java
@@ -332,21 +332,31 @@
      * with the test results.
      *
      * @throws SecurityException if caller is not allowed to manage this service's settings.
+     *
+     * @return whether the enabled state changed.
      */
-    public final void setDefaultServiceEnabled(@UserIdInt int userId, boolean enabled) {
+    public final boolean setDefaultServiceEnabled(@UserIdInt int userId, boolean enabled) {
         Slog.i(mTag, "setDefaultServiceEnabled() for userId " + userId + ": " + enabled);
         enforceCallingPermissionForManagement();
 
         synchronized (mLock) {
+            final boolean changed = mServiceNameResolver.setDefaultServiceEnabled(userId, enabled);
+            if (!changed) {
+                if (verbose) {
+                    Slog.v(mTag, "setDefaultServiceEnabled(" + userId + "): already " + enabled);
+                }
+                return false;
+            }
+
             final S oldService = peekServiceForUserLocked(userId);
             if (oldService != null) {
                 oldService.removeSelfFromCacheLocked();
             }
-            mServiceNameResolver.setDefaultServiceEnabled(userId, enabled);
 
             // Must update the service on cache so its initialization code is triggered
             updateCachedServiceLocked(userId);
         }
+        return true;
     }
 
     /**
diff --git a/services/core/java/com/android/server/infra/AbstractPerUserSystemService.java b/services/core/java/com/android/server/infra/AbstractPerUserSystemService.java
index cd9ebcd..ac07e9d 100644
--- a/services/core/java/com/android/server/infra/AbstractPerUserSystemService.java
+++ b/services/core/java/com/android/server/infra/AbstractPerUserSystemService.java
@@ -327,6 +327,10 @@
     @GuardedBy("mLock")
     protected void dumpLocked(@NonNull String prefix, @NonNull PrintWriter pw) {
         pw.print(prefix); pw.print("User: "); pw.println(mUserId);
+        if (mServiceInfo != null) {
+            pw.print(prefix); pw.print("Service Label: "); pw.println(getServiceLabelLocked());
+            pw.print(prefix); pw.print("Target SDK: "); pw.println(getTargedSdkLocked());
+        }
         if (mMaster.mServiceNameResolver != null) {
             pw.print(prefix); pw.print("Name resolver: ");
             mMaster.mServiceNameResolver.dumpShort(pw, mUserId); pw.println();
diff --git a/services/core/java/com/android/server/infra/FrameworkResourcesServiceNameResolver.java b/services/core/java/com/android/server/infra/FrameworkResourcesServiceNameResolver.java
index 1b23794..d204813 100644
--- a/services/core/java/com/android/server/infra/FrameworkResourcesServiceNameResolver.java
+++ b/services/core/java/com/android/server/infra/FrameworkResourcesServiceNameResolver.java
@@ -174,23 +174,35 @@
     }
 
     @Override
-    public void setDefaultServiceEnabled(int userId, boolean enabled) {
+    public boolean setDefaultServiceEnabled(int userId, boolean enabled) {
         synchronized (mLock) {
+            final boolean currentlyEnabled = isDefaultServiceEnabledLocked(userId);
+            if (currentlyEnabled == enabled) {
+                Slog.i(TAG, "setDefaultServiceEnabled(" + userId + "): already " + enabled);
+                return false;
+            }
             if (enabled) {
+                Slog.i(TAG, "disabling default service for user " + userId);
                 mDefaultServicesDisabled.removeAt(userId);
             } else {
+                Slog.i(TAG, "enabling default service for user " + userId);
                 mDefaultServicesDisabled.put(userId, true);
             }
         }
+        return true;
     }
 
     @Override
     public boolean isDefaultServiceEnabled(int userId) {
         synchronized (mLock) {
-            return !mDefaultServicesDisabled.get(userId);
+            return isDefaultServiceEnabledLocked(userId);
         }
     }
 
+    private boolean isDefaultServiceEnabledLocked(int userId) {
+        return !mDefaultServicesDisabled.get(userId);
+    }
+
     @Override
     public String toString() {
         return "FrameworkResourcesServiceNamer[temps=" + mTemporaryServiceNames + "]";
diff --git a/services/core/java/com/android/server/infra/ServiceNameResolver.java b/services/core/java/com/android/server/infra/ServiceNameResolver.java
index 5b60413..8c348ebb 100644
--- a/services/core/java/com/android/server/infra/ServiceNameResolver.java
+++ b/services/core/java/com/android/server/infra/ServiceNameResolver.java
@@ -115,11 +115,13 @@
      *
      * @param userId user handle
      * @param enabled whether the default service should be used when the temporary service is not
-     * set
+     * set. If the service enabled state is already that value, the command is ignored and this
+     * method return {@code false}.
      *
+     * @return whether the enabled state changed.
      * @throws UnsupportedOperationException if not implemented.
      */
-    default void setDefaultServiceEnabled(@UserIdInt int userId, boolean enabled) {
+    default boolean setDefaultServiceEnabled(@UserIdInt int userId, boolean enabled) {
         throw new UnsupportedOperationException("changing default service not supported");
     }
 
diff --git a/services/core/java/com/android/server/job/JobSchedulerService.java b/services/core/java/com/android/server/job/JobSchedulerService.java
index cefe583..d5883bb 100644
--- a/services/core/java/com/android/server/job/JobSchedulerService.java
+++ b/services/core/java/com/android/server/job/JobSchedulerService.java
@@ -19,6 +19,7 @@
 import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED;
 import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER;
 
+import android.annotation.NonNull;
 import android.annotation.UserIdInt;
 import android.app.Activity;
 import android.app.ActivityManager;
@@ -2494,24 +2495,36 @@
             }
         }
 
-        // The expensive check last: validate that the defined package+service is
+        // The expensive check: validate that the defined package+service is
         // still present & viable.
-        final boolean componentPresent;
+        return isComponentUsable(job);
+    }
+
+    private boolean isComponentUsable(@NonNull JobStatus job) {
+        final ServiceInfo service;
         try {
-            componentPresent = (AppGlobals.getPackageManager().getServiceInfo(
+            // TODO: cache result until we're notified that something in the package changed.
+            service = AppGlobals.getPackageManager().getServiceInfo(
                     job.getServiceComponent(), PackageManager.MATCH_DEBUG_TRIAGED_MISSING,
-                    job.getUserId()) != null);
+                    job.getUserId());
         } catch (RemoteException e) {
             throw e.rethrowAsRuntimeException();
         }
 
-        if (DEBUG) {
-            Slog.v(TAG, "isReadyToBeExecutedLocked: " + job.toShortString()
-                    + " componentPresent=" + componentPresent);
+        if (service == null) {
+            if (DEBUG) {
+                Slog.v(TAG, "isComponentUsable: " + job.toShortString()
+                        + " component not present");
+            }
+            return false;
         }
 
         // Everything else checked out so far, so this is the final yes/no check
-        return componentPresent;
+        final boolean appIsBad = mActivityManagerInternal.isAppBad(service.applicationInfo);
+        if (DEBUG && appIsBad) {
+            Slog.i(TAG, "App is bad for " + job.toShortString() + " so not runnable");
+        }
+        return !appIsBad;
     }
 
     private void evaluateControllerStatesLocked(final JobStatus job) {
@@ -2543,30 +2556,18 @@
             return false;
         }
 
+        if (isJobThermalConstrainedLocked(job)) {
+            return false;
+        }
+
         // Job pending/active doesn't affect the readiness of a job.
 
-        // Skipping the hearbeat check as this will only come into play when using the rolling
+        // Skipping the heartbeat check as this will only come into play when using the rolling
         // window quota management system.
 
-        // The expensive check last: validate that the defined package+service is
+        // The expensive check: validate that the defined package+service is
         // still present & viable.
-        final boolean componentPresent;
-        try {
-            // TODO: cache result until we're notified that something in the package changed.
-            componentPresent = (AppGlobals.getPackageManager().getServiceInfo(
-                    job.getServiceComponent(), PackageManager.MATCH_DEBUG_TRIAGED_MISSING,
-                    job.getUserId()) != null);
-        } catch (RemoteException e) {
-            throw e.rethrowAsRuntimeException();
-        }
-
-        if (DEBUG) {
-            Slog.v(TAG, "areComponentsInPlaceLocked: " + job.toShortString()
-                    + " componentPresent=" + componentPresent);
-        }
-
-        // Everything else checked out so far, so this is the final yes/no check
-        return componentPresent;
+        return isComponentUsable(job);
     }
 
     /**
diff --git a/services/core/java/com/android/server/job/controllers/ConnectivityController.java b/services/core/java/com/android/server/job/controllers/ConnectivityController.java
index aca02bf..c820841 100644
--- a/services/core/java/com/android/server/job/controllers/ConnectivityController.java
+++ b/services/core/java/com/android/server/job/controllers/ConnectivityController.java
@@ -30,6 +30,9 @@
 import android.net.NetworkPolicyManager;
 import android.net.NetworkRequest;
 import android.net.TrafficStats;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
 import android.os.UserHandle;
 import android.text.format.DateUtils;
 import android.util.ArraySet;
@@ -85,8 +88,14 @@
     @GuardedBy("mLock")
     private final ArraySet<Network> mAvailableNetworks = new ArraySet<>();
 
+    private static final int MSG_DATA_SAVER_TOGGLED = 0;
+    private static final int MSG_UID_RULES_CHANGES = 1;
+
+    private final Handler mHandler;
+
     public ConnectivityController(JobSchedulerService service) {
         super(service);
+        mHandler = new CcHandler(mContext.getMainLooper());
 
         mConnManager = mContext.getSystemService(ConnectivityManager.class);
         mNetPolicyManager = mContext.getSystemService(NetworkPolicyManager.class);
@@ -545,11 +554,39 @@
 
     private final INetworkPolicyListener mNetPolicyListener = new NetworkPolicyManager.Listener() {
         @Override
+        public void onRestrictBackgroundChanged(boolean restrictBackground) {
+            if (DEBUG) {
+                Slog.v(TAG, "onRestrictBackgroundChanged: " + restrictBackground);
+            }
+            mHandler.obtainMessage(MSG_DATA_SAVER_TOGGLED).sendToTarget();
+        }
+
+        @Override
         public void onUidRulesChanged(int uid, int uidRules) {
             if (DEBUG) {
                 Slog.v(TAG, "onUidRulesChanged: " + uid);
             }
-            updateTrackedJobs(uid, null);
+            mHandler.obtainMessage(MSG_UID_RULES_CHANGES, uid, 0).sendToTarget();
+        }
+    };
+
+    private class CcHandler extends Handler {
+        CcHandler(Looper looper) {
+            super(looper);
+        }
+
+        @Override
+        public void handleMessage(Message msg) {
+            synchronized (mLock) {
+                switch (msg.what) {
+                    case MSG_DATA_SAVER_TOGGLED:
+                        updateTrackedJobs(-1, null);
+                        break;
+                    case MSG_UID_RULES_CHANGES:
+                        updateTrackedJobs(msg.arg1, null);
+                        break;
+                }
+            }
         }
     };
 
diff --git a/services/core/java/com/android/server/location/GnssLocationProvider.java b/services/core/java/com/android/server/location/GnssLocationProvider.java
index c173d66..8249999 100644
--- a/services/core/java/com/android/server/location/GnssLocationProvider.java
+++ b/services/core/java/com/android/server/location/GnssLocationProvider.java
@@ -166,9 +166,15 @@
     private static final int GPS_CAPABILITY_MSA = 0x0000004;
     private static final int GPS_CAPABILITY_SINGLE_SHOT = 0x0000008;
     private static final int GPS_CAPABILITY_ON_DEMAND_TIME = 0x0000010;
-    private static final int GPS_CAPABILITY_GEOFENCING = 0x0000020;
+
+    // The following three capability flags are removed in IGnssCallback.hal@2.0 and their values
+    // are marked reserved and not reused in 2.0 to avoid confusion with prior versions.
+    public static final int GPS_CAPABILITY_GEOFENCING = 0x0000020;
     public static final int GPS_CAPABILITY_MEASUREMENTS = 0x0000040;
-    private static final int GPS_CAPABILITY_NAV_MESSAGES = 0x0000080;
+    public static final int GPS_CAPABILITY_NAV_MESSAGES = 0x0000080;
+
+    private static final int GPS_CAPABILITY_LOW_POWER_MODE = 0x0000100;
+    private static final int GPS_CAPABILITY_SATELLITE_BLACKLIST = 0x0000200;
 
     // The AGPS SUPL mode
     private static final int AGPS_SUPL_MODE_MSA = 0x02;
@@ -333,7 +339,7 @@
     private boolean mStarted;
 
     // capabilities of the GPS engine
-    private int mEngineCapabilities;
+    private volatile int mEngineCapabilities;
 
     // true if XTRA is supported
     private boolean mSupportsXtra;
@@ -372,6 +378,7 @@
     private final LocationExtras mLocationExtras = new LocationExtras();
     private final GnssStatusListenerHelper mGnssStatusListenerHelper;
     private final GnssMeasurementsProvider mGnssMeasurementsProvider;
+    private final GnssMeasurementCorrectionsProvider mGnssMeasurementCorrectionsProvider;
     private final GnssNavigationMessageProvider mGnssNavigationMessageProvider;
     private final LocationChangeListener mNetworkLocationListener = new NetworkLocationListener();
     private final LocationChangeListener mFusedLocationListener = new FusedLocationListener();
@@ -437,6 +444,10 @@
         return mGnssMeasurementsProvider;
     }
 
+    public GnssMeasurementCorrectionsProvider getGnssMeasurementCorrectionsProvider() {
+        return mGnssMeasurementCorrectionsProvider;
+    }
+
     public GnssNavigationMessageProvider getGnssNavigationMessageProvider() {
         return mGnssNavigationMessageProvider;
     }
@@ -627,6 +638,8 @@
             }
         };
 
+        mGnssMeasurementCorrectionsProvider = new GnssMeasurementCorrectionsProvider(mHandler);
+
         mGnssNavigationMessageProvider = new GnssNavigationMessageProvider(mContext, mHandler) {
             @Override
             protected boolean isGpsEnabled() {
@@ -1258,6 +1271,10 @@
         mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, now + mFixInterval, mWakeupIntent);
     }
 
+    public int getGnssCapabilities() {
+        return mEngineCapabilities;
+    }
+
     private boolean hasCapability(int capability) {
         return ((mEngineCapabilities & capability) != 0);
     }
@@ -1467,22 +1484,27 @@
     }
 
     @NativeEntryPoint
-    private void setEngineCapabilities(final int capabilities) {
+    private void setEngineCapabilities(final int capabilities, boolean hasSubHalCapabilityFlags) {
         // send to handler thread for fast native return, and in-order handling
-        mHandler.post(
-                () -> {
-                    mEngineCapabilities = capabilities;
+        mHandler.post(() -> {
+            mEngineCapabilities = capabilities;
 
-                    if (hasCapability(GPS_CAPABILITY_ON_DEMAND_TIME)) {
-                        mNtpTimeHelper.enablePeriodicTimeInjection();
-                        requestUtcTime();
-                    }
+            if (hasCapability(GPS_CAPABILITY_ON_DEMAND_TIME)) {
+                mNtpTimeHelper.enablePeriodicTimeInjection();
+                requestUtcTime();
+            }
 
-                    mGnssMeasurementsProvider.onCapabilitiesUpdated(capabilities);
-                    mGnssNavigationMessageProvider.onCapabilitiesUpdated(
-                            hasCapability(GPS_CAPABILITY_NAV_MESSAGES));
-                    restartRequests();
-                });
+            mGnssMeasurementsProvider.onCapabilitiesUpdated(capabilities, hasSubHalCapabilityFlags);
+            mGnssNavigationMessageProvider.onCapabilitiesUpdated(capabilities,
+                    hasSubHalCapabilityFlags);
+            restartRequests();
+        });
+    }
+
+    @NativeEntryPoint
+    private void setMeasurementCorrectionsCapabilities(final int capabilities) {
+        mHandler.post(() -> mGnssMeasurementCorrectionsProvider.onCapabilitiesUpdated(
+                capabilities));
     }
 
     private void restartRequests() {
@@ -2122,7 +2144,23 @@
         if (hasCapability(GPS_CAPABILITY_GEOFENCING)) s.append("GEOFENCING ");
         if (hasCapability(GPS_CAPABILITY_MEASUREMENTS)) s.append("MEASUREMENTS ");
         if (hasCapability(GPS_CAPABILITY_NAV_MESSAGES)) s.append("NAV_MESSAGES ");
+        if (hasCapability(GPS_CAPABILITY_LOW_POWER_MODE)) s.append("LOW_POWER_MODE ");
+        if (hasCapability(GPS_CAPABILITY_SATELLITE_BLACKLIST)) s.append("SATELLITE_BLACKLIST ");
         s.append(")\n");
+        if (mGnssGeofenceProvider.isHardwareGeofenceSupported()) {
+            s.append("  hasSubHal=GEOFENCING\n");
+        }
+        if (mGnssMeasurementsProvider.isAvailableInPlatform()) {
+            s.append("  hasSubHal=MEASUREMENTS\n");
+        }
+        if (mGnssNavigationMessageProvider.isAvailableInPlatform()) {
+            s.append("  hasSubHal=NAV_MESSAGES\n");
+        }
+        if (mGnssMeasurementCorrectionsProvider.isAvailableInPlatform()) {
+            s.append("  hasSubHal=MEASUREMENT_CORRECTIONS [");
+            s.append(mGnssMeasurementCorrectionsProvider.toStringCapabilities());
+            s.append("]\n");
+        }
         s.append(mGnssMetrics.dumpGnssMetricsAsText());
         s.append("  native internal state: ").append(native_get_internal_state());
         s.append("\n");
diff --git a/services/core/java/com/android/server/location/GnssMeasurementCorrectionsProvider.java b/services/core/java/com/android/server/location/GnssMeasurementCorrectionsProvider.java
new file mode 100644
index 0000000..2162787
--- /dev/null
+++ b/services/core/java/com/android/server/location/GnssMeasurementCorrectionsProvider.java
@@ -0,0 +1,149 @@
+/*
+ * 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.server.location;
+
+import android.location.GnssMeasurementCorrections;
+import android.os.Handler;
+import android.util.Log;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+/**
+ * Manages GNSS measurement corrections.
+ *
+ * <p>Implements the framework side of the GNSS HAL interfaces {@code IMeasurementCorrections.hal}
+ * and {@code IMeasurementCorrectionsCallback.hal).
+ *
+ * @hide
+ */
+public class GnssMeasurementCorrectionsProvider {
+    private static final String TAG = "GnssMeasurementCorrectionsProvider";
+
+    // These must match with the Capabilities enum in IMeasurementCorrectionsCallback.hal.
+    private static final int CAPABILITY_LOS_SATS = 0x0000001;
+    private static final int CAPABILITY_EXCESS_PATH_LENGTH = 0x0000002;
+    private static final int CAPABILITY_REFLECTING_PLANE = 0x0000004;
+
+    private static final int INVALID_CAPABILITIES = 1 << 31;
+
+    private final Handler mHandler;
+    private final GnssMeasurementCorrectionsProviderNative mNative;
+    private volatile int mCapabilities = INVALID_CAPABILITIES;
+
+    GnssMeasurementCorrectionsProvider(Handler handler) {
+        this(handler, new GnssMeasurementCorrectionsProviderNative());
+    }
+
+    @VisibleForTesting
+    GnssMeasurementCorrectionsProvider(Handler handler,
+            GnssMeasurementCorrectionsProviderNative aNative) {
+        mHandler = handler;
+        mNative = aNative;
+    }
+
+    /**
+     * Returns {@code true} if the GNSS HAL implementation supports measurement corrections.
+     */
+    public boolean isAvailableInPlatform() {
+        return mNative.isMeasurementCorrectionsSupported();
+    }
+
+    /**
+     * Injects GNSS measurement corrections into the GNSS chipset.
+     *
+     * @param measurementCorrections a {@link GnssMeasurementCorrections} object with the GNSS
+     *     measurement corrections to be injected into the GNSS chipset.
+     */
+    public void injectGnssMeasurementCorrections(
+            GnssMeasurementCorrections measurementCorrections) {
+        if (!isCapabilitiesReceived()) {
+            Log.w(TAG, "Failed to inject GNSS measurement corrections. Capabilities "
+                    + "not received yet.");
+            return;
+        }
+        mHandler.post(() -> {
+            if (!mNative.injectGnssMeasurementCorrections(measurementCorrections)) {
+                Log.e(TAG, "Failure in injecting GNSS corrections.");
+            }
+        });
+    }
+
+    /** Handle measurement corrections capabilities update from the GNSS HAL implementation. */
+    void onCapabilitiesUpdated(int capabilities) {
+        if (hasCapability(capabilities, CAPABILITY_LOS_SATS) || hasCapability(capabilities,
+                CAPABILITY_EXCESS_PATH_LENGTH)) {
+            mCapabilities = capabilities;
+        } else {
+            Log.e(TAG, "Failed to set capabilities. Received capabilities 0x"
+                    + Integer.toHexString(capabilities) + " does not contain the mandatory "
+                    + "LOS_SATS or the EXCESS_PATH_LENGTH capability.");
+        }
+    }
+
+    /**
+     * Returns the measurement corrections specific capabilities of the GNSS HAL implementation.
+     */
+    public int getCapabilities() {
+        return mCapabilities;
+    }
+
+    /**
+     * Returns the string representation of the GNSS measurement capabilities.
+     */
+    String toStringCapabilities() {
+        final int capabilities = getCapabilities();
+        StringBuilder s = new StringBuilder();
+        s.append("mCapabilities=0x").append(Integer.toHexString(capabilities));
+        s.append(" ( ");
+        if (hasCapability(capabilities, CAPABILITY_LOS_SATS)) {
+            s.append("LOS_SATS ");
+        }
+        if (hasCapability(capabilities, CAPABILITY_EXCESS_PATH_LENGTH)) {
+            s.append("EXCESS_PATH_LENGTH ");
+        }
+        if (hasCapability(capabilities, CAPABILITY_REFLECTING_PLANE)) {
+            s.append("REFLECTING_PLANE ");
+        }
+        s.append(")");
+        return s.toString();
+    }
+
+    private boolean isCapabilitiesReceived() {
+        return mCapabilities != INVALID_CAPABILITIES;
+    }
+
+    private static  boolean hasCapability(int halCapabilities, int capability) {
+        return (halCapabilities & capability) != 0;
+    }
+
+    @VisibleForTesting
+    static class GnssMeasurementCorrectionsProviderNative {
+        public boolean isMeasurementCorrectionsSupported() {
+            return native_is_measurement_corrections_supported();
+        }
+
+        public boolean injectGnssMeasurementCorrections(
+                GnssMeasurementCorrections measurementCorrections) {
+            return native_inject_gnss_measurement_corrections(measurementCorrections);
+        }
+    }
+
+    private static native boolean native_is_measurement_corrections_supported();
+
+    private static native boolean native_inject_gnss_measurement_corrections(
+            GnssMeasurementCorrections measurementCorrections);
+}
diff --git a/services/core/java/com/android/server/location/GnssMeasurementsProvider.java b/services/core/java/com/android/server/location/GnssMeasurementsProvider.java
index 1fc7192..844735a 100644
--- a/services/core/java/com/android/server/location/GnssMeasurementsProvider.java
+++ b/services/core/java/com/android/server/location/GnssMeasurementsProvider.java
@@ -11,13 +11,12 @@
  * 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 com.android.server.location;
 
 import android.content.Context;
-import android.location.GnssMeasurementCorrections;
 import android.location.GnssMeasurementsEvent;
 import android.location.IGnssMeasurementsListener;
 import android.os.Handler;
@@ -42,7 +41,6 @@
 
     private boolean mIsCollectionStarted;
     private boolean mEnableFullTracking;
-    private int mGnssEngineCapabilities;
 
     protected GnssMeasurementsProvider(Context context, Handler handler) {
         this(context, handler, new GnssMeasurementProviderNative());
@@ -87,21 +85,6 @@
         }
     }
 
-    /**
-     * Injects GNSS measurement corrections into the GNSS chipset.
-     *
-     * @param measurementCorrections a {@link GnssMeasurementCorrections} object with the GNSS
-     *     measurement corrections to be injected into the GNSS chipset.
-     */
-    public void injectGnssMeasurementCorrections(
-            GnssMeasurementCorrections measurementCorrections) {
-        mHandler.post(() -> {
-            if (!mNative.injectGnssMeasurementCorrections(measurementCorrections)) {
-                Log.e(TAG, "Failure in injecting GNSS corrections.");
-            }
-        });
-    }
-
     @Override
     protected void unregisterFromService() {
         boolean stopped = mNative.stopMeasurementCollection();
@@ -121,20 +104,20 @@
         });
     }
 
-    /** Updates the framework about the capabilities of the GNSS chipset */
-    public void onCapabilitiesUpdated(int capabilities) {
-        mGnssEngineCapabilities = capabilities;
-        boolean isGnssMeasurementsSupported =
-                (capabilities & GnssLocationProvider.GPS_CAPABILITY_MEASUREMENTS) != 0;
+    /** Handle GNSS capabilities update from the GNSS HAL implementation. */
+    public void onCapabilitiesUpdated(int capabilities, boolean hasSubHalCapabilityFlags) {
+        // The IGnssCallback.hal@2.0 removed sub-HAL capability flags from the Capabilities enum
+        // and instead uses the sub-HAL non-null handle returned from IGnss.hal@2.0 to indicate
+        // support. Therefore, the 'hasSubHalCapabilityFlags' parameter is needed to tell if the
+        // 'capabilities' parameter includes the sub-HAL capability flags or not. Old HALs
+        // which explicitly set the sub-HAL capability bits must continue to work.
+        final boolean isGnssMeasurementsSupported = hasSubHalCapabilityFlags
+                ? (capabilities & GnssLocationProvider.GPS_CAPABILITY_MEASUREMENTS) != 0
+                : mNative.isMeasurementSupported();
         setSupported(isGnssMeasurementsSupported);
         updateResult();
     }
 
-    /** Obtains the GNSS engine capabilities. */
-    public int getGnssCapabilities() {
-        return mGnssEngineCapabilities;
-    }
-
     public void onGpsEnabledChanged() {
         tryUpdateRegistrationWithService();
         updateResult();
@@ -195,11 +178,6 @@
         public boolean stopMeasurementCollection() {
             return native_stop_measurement_collection();
         }
-
-        public boolean injectGnssMeasurementCorrections(
-                GnssMeasurementCorrections measurementCorrections) {
-            return native_inject_gnss_measurement_corrections(measurementCorrections);
-        }
     }
 
     private static native boolean native_is_measurement_supported();
@@ -207,7 +185,4 @@
     private static native boolean native_start_measurement_collection(boolean enableFullTracking);
 
     private static native boolean native_stop_measurement_collection();
-
-    private static native boolean native_inject_gnss_measurement_corrections(
-            GnssMeasurementCorrections measurementCorrections);
 }
diff --git a/services/core/java/com/android/server/location/GnssNavigationMessageProvider.java b/services/core/java/com/android/server/location/GnssNavigationMessageProvider.java
index 80a3f9b..7e8b599 100644
--- a/services/core/java/com/android/server/location/GnssNavigationMessageProvider.java
+++ b/services/core/java/com/android/server/location/GnssNavigationMessageProvider.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 com.android.server.location;
@@ -51,7 +51,6 @@
         mNative = aNative;
     }
 
-    // TODO(b/37460011): Use this with death recovery logic.
     void resumeIfStarted() {
         if (DEBUG) {
             Log.d(TAG, "resumeIfStarted");
@@ -92,7 +91,16 @@
         );
     }
 
-    public void onCapabilitiesUpdated(boolean isGnssNavigationMessageSupported) {
+    /** Handle GNSS capabilities update from the GNSS HAL implementation */
+    public void onCapabilitiesUpdated(int capabilities, boolean hasSubHalCapabilityFlags) {
+        // The IGnssCallback.hal@2.0 removed sub-HAL capability flags from the Capabilities enum
+        // and instead uses the sub-HAL non-null handle returned from IGnss.hal@2.0 to indicate
+        // support. Therefore, the 'hasSubHalCapabilityFlags' parameter is needed to tell if the
+        // 'capabilities' parameter includes the sub-HAL capability flags or not. Old HALs
+        // which explicitly set the sub-HAL capability bits must continue to work.
+        final boolean isGnssNavigationMessageSupported = hasSubHalCapabilityFlags
+                ? (capabilities & GnssLocationProvider.GPS_CAPABILITY_NAV_MESSAGES) != 0
+                : mNative.isNavigationMessageSupported();
         setSupported(isGnssNavigationMessageSupported);
         updateResult();
     }
diff --git a/services/core/java/com/android/server/locksettings/LockSettingsService.java b/services/core/java/com/android/server/locksettings/LockSettingsService.java
index a53ab84..293813a 100644
--- a/services/core/java/com/android/server/locksettings/LockSettingsService.java
+++ b/services/core/java/com/android/server/locksettings/LockSettingsService.java
@@ -2699,6 +2699,14 @@
         }
     }
 
+    @Override
+    public boolean hasPendingEscrowToken(int userId) {
+        checkPasswordReadPermission(userId);
+        synchronized (mSpManager) {
+            return !mSpManager.getPendingTokensForUser(userId).isEmpty();
+        }
+    }
+
     private boolean removeEscrowToken(long handle, int userId) {
         synchronized (mSpManager) {
             if (handle == getSyntheticPasswordHandleLocked(userId)) {
diff --git a/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java b/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java
index 142ad53..1ba0e8c 100644
--- a/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java
+++ b/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java
@@ -751,7 +751,7 @@
 
     /**
      * Create a token based Synthetic password for the given user.
-     * @return
+     * @return the handle of the token
      */
     public long createTokenBasedSyntheticPassword(byte[] token, int userId,
             @Nullable EscrowTokenStateChangeCallback changeCallback) {
diff --git a/services/core/java/com/android/server/media/MediaSessionRecord.java b/services/core/java/com/android/server/media/MediaSessionRecord.java
index 192ad6d..7b691b4 100644
--- a/services/core/java/com/android/server/media/MediaSessionRecord.java
+++ b/services/core/java/com/android/server/media/MediaSessionRecord.java
@@ -28,6 +28,7 @@
 import android.media.Rating;
 import android.media.VolumeProvider;
 import android.media.session.ControllerCallbackLink;
+import android.media.session.ISession;
 import android.media.session.ISessionController;
 import android.media.session.MediaController;
 import android.media.session.MediaController.PlaybackInfo;
@@ -35,7 +36,6 @@
 import android.media.session.MediaSession.QueueItem;
 import android.media.session.PlaybackState;
 import android.media.session.SessionCallbackLink;
-import android.media.session.SessionLink;
 import android.net.Uri;
 import android.os.Binder;
 import android.os.Bundle;
@@ -45,6 +45,7 @@
 import android.os.Looper;
 import android.os.Message;
 import android.os.Process;
+import android.os.RemoteException;
 import android.os.ResultReceiver;
 import android.os.SystemClock;
 import android.util.Log;
@@ -81,7 +82,7 @@
     private final Bundle mSessionInfo;
     private final ControllerStub mController;
     private final MediaSession.Token mSessionToken;
-    private final SessionLink mSession;
+    private final SessionStub mSession;
     private final SessionCb mSessionCb;
     private final MediaSessionService.ServiceImpl mService;
     private final Context mContext;
@@ -133,7 +134,7 @@
         mSessionInfo = sessionInfo;
         mController = new ControllerStub();
         mSessionToken = new MediaSession.Token(mController);
-        mSession = new SessionLink(new SessionStub());
+        mSession = new SessionStub();
         mSessionCb = new SessionCb(cb);
         mService = service;
         mContext = mService.getContext();
@@ -144,11 +145,11 @@
     }
 
     /**
-     * Get the session link for the {@link MediaSession}.
+     * Get the session binder for the {@link MediaSession}.
      *
-     * @return The session link apps talk to.
+     * @return The session binder apps talk to.
      */
-    public SessionLink getSessionBinder() {
+    public ISession getSessionBinder() {
         return mSession;
     }
 
@@ -818,9 +819,9 @@
         }
     };
 
-    private final class SessionStub extends SessionLink.SessionStub {
+    private final class SessionStub extends ISession.Stub {
         @Override
-        public void destroySession() {
+        public void destroySession() throws RemoteException {
             final long token = Binder.clearCallingIdentity();
             try {
                 mService.destroySession(MediaSessionRecord.this);
@@ -830,18 +831,18 @@
         }
 
         @Override
-        public void sendEvent(String event, Bundle data) {
+        public void sendEvent(String event, Bundle data) throws RemoteException {
             mHandler.post(MessageHandler.MSG_SEND_EVENT, event,
                     data == null ? null : new Bundle(data));
         }
 
         @Override
-        public ISessionController getController() {
+        public ISessionController getController() throws RemoteException {
             return mController;
         }
 
         @Override
-        public void setActive(boolean active) {
+        public void setActive(boolean active) throws RemoteException {
             mIsActive = active;
             final long token = Binder.clearCallingIdentity();
             try {
@@ -853,7 +854,7 @@
         }
 
         @Override
-        public void setFlags(int flags) {
+        public void setFlags(int flags) throws RemoteException {
             if ((flags & MediaSession.FLAG_EXCLUSIVE_GLOBAL_PRIORITY) != 0) {
                 int pid = Binder.getCallingPid();
                 int uid = Binder.getCallingUid();
@@ -872,7 +873,7 @@
         }
 
         @Override
-        public void setMediaButtonReceiver(PendingIntent pi) {
+        public void setMediaButtonReceiver(PendingIntent pi) throws RemoteException {
             mMediaButtonReceiver = pi;
             final long token = Binder.clearCallingIdentity();
             try {
@@ -883,12 +884,13 @@
         }
 
         @Override
-        public void setLaunchPendingIntent(PendingIntent pi) {
+        public void setLaunchPendingIntent(PendingIntent pi) throws RemoteException {
             mLaunchIntent = pi;
         }
 
         @Override
-        public void setMetadata(MediaMetadata metadata, long duration, String metadataDescription) {
+        public void setMetadata(MediaMetadata metadata, long duration, String metadataDescription)
+                throws RemoteException {
             synchronized (mLock) {
                 MediaMetadata temp = metadata == null ? null : new MediaMetadata.Builder(metadata)
                         .build();
@@ -906,7 +908,7 @@
         }
 
         @Override
-        public void setPlaybackState(PlaybackState state) {
+        public void setPlaybackState(PlaybackState state) throws RemoteException {
             int oldState = mPlaybackState == null
                     ? PlaybackState.STATE_NONE : mPlaybackState.getState();
             int newState = state == null
@@ -924,21 +926,21 @@
         }
 
         @Override
-        public void setQueue(List<QueueItem> queue) {
+        public void setQueue(MediaParceledListSlice queue) throws RemoteException {
             synchronized (mLock) {
-                mQueue = queue;
+                mQueue = queue == null ? null : (List<QueueItem>) queue.getList();
             }
             mHandler.post(MessageHandler.MSG_UPDATE_QUEUE);
         }
 
         @Override
-        public void setQueueTitle(CharSequence title) {
+        public void setQueueTitle(CharSequence title) throws RemoteException {
             mQueueTitle = title;
             mHandler.post(MessageHandler.MSG_UPDATE_QUEUE_TITLE);
         }
 
         @Override
-        public void setExtras(Bundle extras) {
+        public void setExtras(Bundle extras) throws RemoteException {
             synchronized (mLock) {
                 mExtras = extras == null ? null : new Bundle(extras);
             }
@@ -946,18 +948,18 @@
         }
 
         @Override
-        public void setRatingType(int type) {
+        public void setRatingType(int type) throws RemoteException {
             mRatingType = type;
         }
 
         @Override
-        public void setCurrentVolume(int volume) {
+        public void setCurrentVolume(int volume) throws RemoteException {
             mCurrentVolume = volume;
             mHandler.post(MessageHandler.MSG_UPDATE_VOLUME);
         }
 
         @Override
-        public void setPlaybackToLocal(AudioAttributes attributes) {
+        public void setPlaybackToLocal(AudioAttributes attributes) throws RemoteException {
             boolean typeChanged;
             synchronized (mLock) {
                 typeChanged = mVolumeType == PlaybackInfo.PLAYBACK_TYPE_REMOTE;
@@ -980,7 +982,7 @@
         }
 
         @Override
-        public void setPlaybackToRemote(int control, int max) {
+        public void setPlaybackToRemote(int control, int max) throws RemoteException {
             boolean typeChanged;
             synchronized (mLock) {
                 typeChanged = mVolumeType == PlaybackInfo.PLAYBACK_TYPE_LOCAL;
diff --git a/services/core/java/com/android/server/media/MediaSessionServiceImpl.java b/services/core/java/com/android/server/media/MediaSessionServiceImpl.java
index 94f289f..7c8dc74 100644
--- a/services/core/java/com/android/server/media/MediaSessionServiceImpl.java
+++ b/services/core/java/com/android/server/media/MediaSessionServiceImpl.java
@@ -49,12 +49,12 @@
 import android.media.session.ICallback;
 import android.media.session.IOnMediaKeyListener;
 import android.media.session.IOnVolumeKeyLongPressListener;
+import android.media.session.ISession;
 import android.media.session.ISession2TokensListener;
 import android.media.session.ISessionManager;
 import android.media.session.MediaSession;
 import android.media.session.MediaSessionManager;
 import android.media.session.SessionCallbackLink;
-import android.media.session.SessionLink;
 import android.net.Uri;
 import android.os.Binder;
 import android.os.Bundle;
@@ -1001,7 +1001,7 @@
         private boolean mVoiceButtonHandled = false;
 
         @Override
-        public SessionLink createSession(String packageName, SessionCallbackLink cb, String tag,
+        public ISession createSession(String packageName, SessionCallbackLink cb, String tag,
                 Bundle sessionInfo, int userId) throws RemoteException {
             final int pid = Binder.getCallingPid();
             final int uid = Binder.getCallingUid();
diff --git a/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java b/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java
index 270fbc6..3872523 100644
--- a/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java
+++ b/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java
@@ -17,9 +17,14 @@
 package com.android.server.media.projection;
 
 import android.Manifest;
+import android.app.ActivityManagerInternal;
 import android.app.AppOpsManager;
+import android.app.IProcessObserver;
 import android.content.Context;
+import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.pm.ServiceInfo;
 import android.hardware.display.DisplayManager;
 import android.media.MediaRouter;
 import android.media.projection.IMediaProjection;
@@ -29,6 +34,8 @@
 import android.media.projection.MediaProjectionInfo;
 import android.media.projection.MediaProjectionManager;
 import android.os.Binder;
+import android.os.Build;
+import android.os.Build.VERSION_CODES;
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.Looper;
@@ -38,6 +45,7 @@
 import android.util.Slog;
 
 import com.android.internal.util.DumpUtils;
+import com.android.server.LocalServices;
 import com.android.server.SystemService;
 import com.android.server.Watchdog;
 
@@ -63,6 +71,8 @@
 
     private final Context mContext;
     private final AppOpsManager mAppOps;
+    private final ActivityManagerInternal mActivityManagerInternal;
+    private final PackageManager mPackageManager;
 
     private final MediaRouter mMediaRouter;
     private final MediaRouterCallback mMediaRouterCallback;
@@ -77,6 +87,8 @@
         mDeathEaters = new ArrayMap<IBinder, IBinder.DeathRecipient>();
         mCallbackDelegate = new CallbackDelegate();
         mAppOps = (AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE);
+        mActivityManagerInternal = LocalServices.getService(ActivityManagerInternal.class);
+        mPackageManager = mContext.getPackageManager();
         mMediaRouter = (MediaRouter) mContext.getSystemService(Context.MEDIA_ROUTER_SERVICE);
         mMediaRouterCallback = new MediaRouterCallback();
         Watchdog.getInstance().addMonitor(this);
@@ -88,6 +100,21 @@
                 false /*allowIsolated*/);
         mMediaRouter.addCallback(MediaRouter.ROUTE_TYPE_REMOTE_DISPLAY, mMediaRouterCallback,
                 MediaRouter.CALLBACK_FLAG_PASSIVE_DISCOVERY);
+        mActivityManagerInternal.registerProcessObserver(new IProcessObserver.Stub() {
+            @Override
+            public void onForegroundActivitiesChanged(int pid, int uid, boolean fg) {
+            }
+
+            @Override
+            public void onForegroundServicesChanged(int pid, int uid, int serviceTypes) {
+                MediaProjectionManagerService.this.handleForegroundServicesChanged(pid, uid,
+                        serviceTypes);
+            }
+
+            @Override
+            public void onProcessDied(int pid, int uid) {
+            }
+        });
     }
 
     @Override
@@ -105,6 +132,29 @@
         synchronized (mLock) { /* check for deadlock */ }
     }
 
+    /**
+     * Called when the set of active foreground service types for a given {@code uid / pid} changes.
+     * We will stop the active projection grant if its owner targets {@code Q} or higher and has no
+     * started foreground services of type {@code FOREGROUND_SERVICE_TYPE_MEDIA_PROJECTION}.
+     */
+    private void handleForegroundServicesChanged(int pid, int uid, int serviceTypes) {
+        synchronized (mLock) {
+            if (mProjectionGrant == null || mProjectionGrant.uid != uid) {
+                return;
+            }
+
+            if (mProjectionGrant.targetSdkVersion < VERSION_CODES.Q) {
+                return;
+            }
+
+            if ((serviceTypes & ServiceInfo.FOREGROUND_SERVICE_TYPE_MEDIA_PROJECTION) != 0) {
+                return;
+            }
+
+            mProjectionGrant.stop();
+        }
+    }
+
     private void startProjectionLocked(final MediaProjection projection) {
         if (mProjectionGrant != null) {
             mProjectionGrant.stop();
@@ -229,10 +279,19 @@
             if (packageName == null || packageName.isEmpty()) {
                 throw new IllegalArgumentException("package name must not be empty");
             }
+
             long callingToken = Binder.clearCallingIdentity();
+
             MediaProjection projection;
             try {
-                projection = new MediaProjection(type, uid, packageName);
+                ApplicationInfo ai;
+                try {
+                    ai = mPackageManager.getApplicationInfo(packageName, 0);
+                } catch (NameNotFoundException e) {
+                    throw new IllegalArgumentException("No package matching :" + packageName);
+                }
+
+                projection = new MediaProjection(type, uid, packageName, ai.targetSdkVersion);
                 if (isPermanentGrant) {
                     mAppOps.setMode(AppOpsManager.OP_PROJECT_MEDIA,
                             projection.uid, projection.packageName, AppOpsManager.MODE_ALLOWED);
@@ -334,17 +393,19 @@
         public final int uid;
         public final String packageName;
         public final UserHandle userHandle;
+        public final int targetSdkVersion;
 
         private IMediaProjectionCallback mCallback;
         private IBinder mToken;
         private IBinder.DeathRecipient mDeathEater;
         private int mType;
 
-        public MediaProjection(int type, int uid, String packageName) {
+        MediaProjection(int type, int uid, String packageName, int targetSdkVersion) {
             mType = type;
             this.uid = uid;
             this.packageName = packageName;
             userHandle = new UserHandle(UserHandle.getUserId(uid));
+            this.targetSdkVersion = targetSdkVersion;
         }
 
         @Override // Binder call
@@ -400,6 +461,14 @@
                             + " attempted to start already started MediaProjection");
                     return;
                 }
+
+                if (targetSdkVersion >= Build.VERSION_CODES.Q
+                        && !mActivityManagerInternal.hasRunningForegroundService(
+                                uid, ServiceInfo.FOREGROUND_SERVICE_TYPE_MEDIA_PROJECTION)) {
+                    throw new SecurityException("Media projections require a foreground service"
+                            + " of type ServiceInfo.FOREGROUND_SERVICE_TYPE_MEDIA_PROJECTION");
+                }
+
                 mCallback = callback;
                 registerCallback(mCallback);
                 try {
diff --git a/services/core/java/com/android/server/notification/ManagedServices.java b/services/core/java/com/android/server/notification/ManagedServices.java
index 0c0c23a..0488d3a 100644
--- a/services/core/java/com/android/server/notification/ManagedServices.java
+++ b/services/core/java/com/android/server/notification/ManagedServices.java
@@ -347,6 +347,9 @@
                 }
             }
         }
+
+        writeExtraXmlTags(out);
+
         out.endTag(null, getConfig().xmlTag);
     }
 
@@ -355,6 +358,16 @@
      */
     protected void writeExtraAttributes(XmlSerializer out, int userId) throws IOException {}
 
+    /**
+     * Writes extra xml tags within the parent tag specified in {@link Config#xmlTag}.
+     */
+    protected void writeExtraXmlTags(XmlSerializer out) throws IOException {}
+
+    /**
+     * This is called to process tags other than {@link #TAG_MANAGED_SERVICES}.
+     */
+    protected void readExtraTag(String tag, XmlPullParser parser) throws IOException {}
+
     protected void migrateToXml() {
         loadAllowedComponentsFromSettings();
     }
@@ -391,6 +404,8 @@
                         }
                         mUseXml = true;
                     }
+                } else {
+                    readExtraTag(tag, parser);
                 }
             }
         }
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 4a215cf..ca3c826 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -294,6 +294,12 @@
 
     static final boolean ENABLE_BLOCKED_TOASTS = true;
 
+    static final String[] DEFAULT_ALLOWED_ADJUSTMENTS = new String[] {
+            Adjustment.KEY_IMPORTANCE,
+            Adjustment.KEY_CONTEXTUAL_ACTIONS,
+            Adjustment.KEY_TEXT_REPLIES,
+            Adjustment.KEY_USER_SENTIMENT};
+
     // When #matchesCallFilter is called from the ringer, wait at most
     // 3s to resolve the contacts. This timeout is required since
     // ContactsProvider might take a long time to start up.
@@ -2513,6 +2519,9 @@
                         android.Manifest.permission.INTERACT_ACROSS_USERS,
                         "canNotifyAsPackage for user " + userId);
             }
+            if (callingPkg.equals(targetPkg)) {
+                return true;
+            }
             try {
                 ApplicationInfo info =
                         mPackageManager.getApplicationInfo(targetPkg,
@@ -2582,10 +2591,21 @@
         }
 
         @Override
-        public NotificationChannel getNotificationChannel(String pkg, String channelId) {
-            checkCallerIsSystemOrSameApp(pkg);
-            return mPreferencesHelper.getNotificationChannel(
-                    pkg, Binder.getCallingUid(), channelId, false /* includeDeleted */);
+        public NotificationChannel getNotificationChannel(String callingPkg, int userId,
+                String targetPkg, String channelId) {
+            if (canNotifyAsPackage(callingPkg, targetPkg, userId)
+                    || isCallingUidSystem()) {
+                int targetUid = -1;
+                try {
+                    targetUid = mPackageManagerClient.getPackageUidAsUser(targetPkg, userId);
+                } catch (NameNotFoundException e) {
+                    /* ignore */
+                }
+                return mPreferencesHelper.getNotificationChannel(
+                        targetPkg, targetUid, channelId, false /* includeDeleted */);
+            }
+            throw new SecurityException("Pkg " + callingPkg
+                    + " cannot read channels for " + targetPkg + " in " + userId);
         }
 
         @Override
@@ -2720,10 +2740,21 @@
         }
 
         @Override
-        public ParceledListSlice<NotificationChannel> getNotificationChannels(String pkg) {
-            checkCallerIsSystemOrSameApp(pkg);
-            return mPreferencesHelper.getNotificationChannels(
-                    pkg, Binder.getCallingUid(), false /* includeDeleted */);
+        public ParceledListSlice<NotificationChannel> getNotificationChannels(
+                String callingPkg, String targetPkg, int userId) {
+            if (canNotifyAsPackage(callingPkg, targetPkg, userId)
+                || isCallingUidSystem()) {
+                int targetUid = -1;
+                try {
+                    targetUid = mPackageManagerClient.getPackageUidAsUser(targetPkg, userId);
+                } catch (NameNotFoundException e) {
+                    /* ignore */
+                }
+                return mPreferencesHelper.getNotificationChannels(
+                        targetPkg, targetUid, false /* includeDeleted */);
+            }
+            throw new SecurityException("Pkg " + callingPkg
+                    + " cannot read channels for " + targetPkg + " in " + userId);
         }
 
         @Override
@@ -2790,6 +2821,33 @@
             handleSavePolicyFile();
         }
 
+        @Override
+        public List<String> getAllowedAssistantCapabilities(String pkg) {
+            checkCallerIsSystemOrSameApp(pkg);
+
+            if (!isCallerSystemOrPhone()
+                    && !mAssistants.isPackageAllowed(pkg, UserHandle.getCallingUserId())) {
+                    throw new SecurityException("Not currently an assistant");
+            }
+
+            return mAssistants.getAllowedAssistantCapabilities();
+        }
+
+        @Override
+        public void allowAssistantCapability(String adjustmentType) {
+            checkCallerIsSystemOrShell();
+            mAssistants.allowAdjustmentType(adjustmentType);
+
+            handleSavePolicyFile();
+        }
+
+        @Override
+        public void disallowAssistantCapability(String adjustmentType) {
+            checkCallerIsSystemOrShell();
+            mAssistants.disallowAdjustmentType(adjustmentType);
+
+            handleSavePolicyFile();
+        }
 
         /**
          * System-only API for getting a list of current (i.e. not cleared) notifications.
@@ -7143,15 +7201,26 @@
         static final String TAG_ENABLED_NOTIFICATION_ASSISTANTS = "enabled_assistants";
 
         private static final String ATT_USER_SET = "user_set";
+        // TODO: STOPSHIP (b/127994217) switch to final value when onboarding flow is implemented
+        private static final String TAG_ALLOWED_ADJUSTMENT_TYPES = "allowed_adjustments_tmp";
+        private static final String ATT_TYPES = "types";
 
         private final Object mLock = new Object();
 
         @GuardedBy("mLock")
         private ArrayMap<Integer, Boolean> mUserSetMap = new ArrayMap<>();
+        private List<String> mAllowedAdjustments = new ArrayList<>();
 
         public NotificationAssistants(Context context, Object lock, UserProfiles up,
                 IPackageManager pm) {
             super(context, lock, up, pm);
+
+            // TODO: STOPSHIP (b/127994217) remove when the onboarding flow is implemented
+            // Add all default allowed adjustment types. Will be overwritten by values in xml,
+            // if they exist
+            for (int i = 0; i < DEFAULT_ALLOWED_ADJUSTMENTS.length; i++) {
+                mAllowedAdjustments.add(DEFAULT_ALLOWED_ADJUSTMENTS[i]);
+            }
         }
 
         @Override
@@ -7202,6 +7271,48 @@
             return android.Manifest.permission.REQUEST_NOTIFICATION_ASSISTANT_SERVICE;
         }
 
+        @Override
+        protected void writeExtraXmlTags(XmlSerializer out) throws IOException {
+            synchronized (mLock) {
+                out.startTag(null, TAG_ALLOWED_ADJUSTMENT_TYPES);
+                out.attribute(null, ATT_TYPES, TextUtils.join(",", mAllowedAdjustments));
+                out.endTag(null, TAG_ALLOWED_ADJUSTMENT_TYPES);
+            }
+        }
+
+        @Override
+        protected void readExtraTag(String tag, XmlPullParser parser) throws IOException {
+            if (TAG_ALLOWED_ADJUSTMENT_TYPES.equals(tag)) {
+                final String types = XmlUtils.readStringAttribute(parser, ATT_TYPES);
+                if (!TextUtils.isEmpty(types)) {
+                    synchronized (mLock) {
+                        mAllowedAdjustments.clear();
+                        mAllowedAdjustments.addAll(Arrays.asList(types.split(",")));
+                    }
+                }
+            }
+        }
+
+        protected void allowAdjustmentType(String type) {
+            synchronized (mLock) {
+                mAllowedAdjustments.add(type);
+            }
+        }
+
+        protected void disallowAdjustmentType(String type) {
+            synchronized (mLock) {
+                mAllowedAdjustments.remove(type);
+            }
+        }
+
+        protected List<String> getAllowedAssistantCapabilities() {
+            synchronized (mLock) {
+                List<String> types = new ArrayList<>();
+                types.addAll(mAllowedAdjustments);
+                return types;
+            }
+        }
+
         protected void onNotificationsSeenLocked(ArrayList<NotificationRecord> records) {
             // There should be only one, but it's a list, so while we enforce
             // singularity elsewhere, we keep it general here, to avoid surprises.
diff --git a/services/core/java/com/android/server/notification/NotificationRecord.java b/services/core/java/com/android/server/notification/NotificationRecord.java
index d9ab132..de93120 100644
--- a/services/core/java/com/android/server/notification/NotificationRecord.java
+++ b/services/core/java/com/android/server/notification/NotificationRecord.java
@@ -438,6 +438,8 @@
         if (getAudioAttributes() != null) {
             getAudioAttributes().writeToProto(proto, NotificationRecordProto.AUDIO_ATTRIBUTES);
         }
+        proto.write(NotificationRecordProto.PACKAGE, sbn.getPackageName());
+        proto.write(NotificationRecordProto.DELEGATE_PACKAGE, sbn.getOpPkg());
 
         proto.end(token);
     }
@@ -458,6 +460,7 @@
         pw.println(prefix + this);
         prefix = prefix + "  ";
         pw.println(prefix + "uid=" + sbn.getUid() + " userId=" + sbn.getUserId());
+        pw.println(prefix + "opPkg=" + sbn.getOpPkg());
         pw.println(prefix + "icon=" + iconStr);
         pw.println(prefix + "flags=0x" + Integer.toHexString(notification.flags));
         pw.println(prefix + "pri=" + notification.priority);
diff --git a/services/core/java/com/android/server/om/OverlayManagerService.java b/services/core/java/com/android/server/om/OverlayManagerService.java
index 8905eb9..37dd63a 100644
--- a/services/core/java/com/android/server/om/OverlayManagerService.java
+++ b/services/core/java/com/android/server/om/OverlayManagerService.java
@@ -758,7 +758,7 @@
          * @throws SecurityException if the permission check fails
          */
         private void enforceChangeOverlayPackagesPermission(@NonNull final String message) {
-            getContext().enforceCallingPermission(
+            getContext().enforceCallingOrSelfPermission(
                     android.Manifest.permission.CHANGE_OVERLAY_PACKAGES, message);
         }
 
@@ -769,7 +769,7 @@
          * @throws SecurityException if the permission check fails
          */
         private void enforceDumpPermission(@NonNull final String message) {
-            getContext().enforceCallingPermission(android.Manifest.permission.DUMP, message);
+            getContext().enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, message);
         }
     };
 
diff --git a/services/core/java/com/android/server/pm/LauncherAppsService.java b/services/core/java/com/android/server/pm/LauncherAppsService.java
index 7f057f0..18cfa4a 100644
--- a/services/core/java/com/android/server/pm/LauncherAppsService.java
+++ b/services/core/java/com/android/server/pm/LauncherAppsService.java
@@ -45,8 +45,6 @@
 import android.content.pm.ShortcutInfo;
 import android.content.pm.ShortcutServiceInternal;
 import android.content.pm.ShortcutServiceInternal.ShortcutChangeListener;
-import android.content.pm.Signature;
-import android.content.pm.SigningInfo;
 import android.content.pm.UserInfo;
 import android.graphics.Rect;
 import android.net.Uri;
@@ -62,31 +60,21 @@
 import android.os.UserManager;
 import android.os.UserManagerInternal;
 import android.provider.Settings;
-import android.util.ByteStringUtils;
 import android.util.Log;
 import android.util.Slog;
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.content.PackageMonitor;
 import com.android.internal.os.BackgroundThread;
-import com.android.internal.util.DumpUtils;
 import com.android.internal.util.Preconditions;
-import com.android.internal.util.StatLogger;
 import com.android.server.LocalServices;
 import com.android.server.SystemService;
 import com.android.server.wm.ActivityTaskManagerInternal;
 
-import java.io.FileDescriptor;
-import java.io.PrintWriter;
-import java.security.MessageDigest;
-import java.security.NoSuchAlgorithmException;
 import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.Collections;
 import java.util.HashSet;
 import java.util.List;
-import java.util.Set;
-import java.util.concurrent.ConcurrentHashMap;
 
 /**
  * Service that manages requests and callbacks for launchers that support
@@ -125,16 +113,6 @@
         private static final boolean DEBUG = false;
         private static final String TAG = "LauncherAppsService";
 
-        // Stats
-        @VisibleForTesting
-        interface Stats {
-            int INIT_VOUCHED_SIGNATURES = 0;
-            int COUNT = INIT_VOUCHED_SIGNATURES + 1;
-        }
-        private final StatLogger mStatLogger = new StatLogger(new String[] {
-                "initVouchedSignatures"
-        });
-
         private final Context mContext;
         private final UserManager mUm;
         private final UserManagerInternal mUserManagerInternal;
@@ -145,16 +123,11 @@
         private final PackageCallbackList<IOnAppsChangedListener> mListeners
                 = new PackageCallbackList<IOnAppsChangedListener>();
         private final DevicePolicyManager mDpm;
-        private final ConcurrentHashMap<UserHandle, Set<String>> mVouchedSignaturesByUser;
-        private final Set<String> mVouchProviders;
 
         private final MyPackageMonitor mPackageMonitor = new MyPackageMonitor();
-        private final VouchesChangedMonitor mVouchesChangedMonitor = new VouchesChangedMonitor();
 
         private final Handler mCallbackHandler;
 
-        private final Object mVouchedSignaturesLocked = new Object();
-
         private PackageInstallerService mPackageInstallerService;
 
         public LauncherAppsImpl(Context context) {
@@ -173,9 +146,6 @@
             mShortcutServiceInternal.addListener(mPackageMonitor);
             mCallbackHandler = BackgroundThread.getHandler();
             mDpm = (DevicePolicyManager) mContext.getSystemService(Context.DEVICE_POLICY_SERVICE);
-            mVouchedSignaturesByUser = new ConcurrentHashMap<>();
-            mVouchProviders = Collections.newSetFromMap(new ConcurrentHashMap<String, Boolean>());
-            mVouchesChangedMonitor.register(mContext, UserHandle.ALL, true, mCallbackHandler);
         }
 
         @VisibleForTesting
@@ -468,32 +438,9 @@
             if (appInfo == null || appInfo.isSystemApp() || appInfo.isUpdatedSystemApp()) {
                 return false;
             }
-            if (!mVouchedSignaturesByUser.containsKey(user)) {
-                initVouchedSignatures(user);
-            }
             if (isManagedProfileAdmin(user, appInfo.packageName)) {
                 return false;
             }
-            if (mVouchProviders.contains(appInfo.packageName)) {
-                // If it's a vouching packages then we must show hidden app
-                return true;
-            }
-            // If app's signature is in vouch list, do not show hidden app
-            final Set<String> vouches = mVouchedSignaturesByUser.get(user);
-            try {
-                final PackageInfo pkgInfo = mContext.getPackageManager().getPackageInfo(
-                        appInfo.packageName, PackageManager.GET_SIGNING_CERTIFICATES);
-                final Signature[] signatures = getLatestSignatures(pkgInfo.signingInfo);
-                // If any of the signatures appears in vouches, then we don't show hidden app
-                for (Signature signature : signatures) {
-                    final String certDigest = computePackageCertDigest(signature);
-                    if (vouches.contains(certDigest)) {
-                        return false;
-                    }
-                }
-            } catch (PackageManager.NameNotFoundException e) {
-                // Should not happen
-            }
             return true;
         }
 
@@ -515,100 +462,6 @@
             return false;
         }
 
-        @VisibleForTesting
-        static String computePackageCertDigest(Signature signature) {
-            MessageDigest messageDigest;
-            try {
-                messageDigest = MessageDigest.getInstance("SHA1");
-            } catch (NoSuchAlgorithmException e) {
-                // Should not happen
-                return null;
-            }
-            messageDigest.update(signature.toByteArray());
-            final byte[] digest = messageDigest.digest();
-            return ByteStringUtils.toHexString(digest);
-        }
-
-        @VisibleForTesting
-        static Signature[] getLatestSignatures(SigningInfo signingInfo) {
-            if (signingInfo.hasMultipleSigners()) {
-                return signingInfo.getApkContentsSigners();
-            } else {
-                final Signature[] signatures = signingInfo.getSigningCertificateHistory();
-                return new Signature[]{signatures[0]};
-            }
-        }
-
-        private void updateVouches(String packageName, UserHandle user) {
-            final PackageManagerInternal pmInt =
-                    LocalServices.getService(PackageManagerInternal.class);
-            ApplicationInfo appInfo = pmInt.getApplicationInfo(packageName,
-                    PackageManager.GET_META_DATA, Binder.getCallingUid(), user.getIdentifier());
-            if (appInfo == null) {
-                Log.w(TAG, "appInfo " + packageName + " is null");
-                return;
-            }
-            updateVouches(appInfo, user);
-        }
-
-        private void updateVouches(ApplicationInfo appInfo, UserHandle user) {
-            if (appInfo == null || appInfo.metaData == null) {
-                // No meta-data
-                return;
-            }
-            int tokenResourceId = appInfo.metaData.getInt(LauncherApps.VOUCHED_CERTS_KEY);
-            if (tokenResourceId == 0) {
-                // No xml file
-                return;
-            }
-            mVouchProviders.add(appInfo.packageName);
-            Set<String> vouches = mVouchedSignaturesByUser.get(user);
-            try {
-                List<String> signatures = Arrays.asList(
-                        mContext.getPackageManager().getResourcesForApplication(
-                                appInfo.packageName).getStringArray(tokenResourceId));
-                for (String signature : signatures) {
-                    vouches.add(signature.toUpperCase());
-                }
-            } catch (PackageManager.NameNotFoundException e) {
-                // Should not happen
-            }
-        }
-
-        private void initVouchedSignatures(UserHandle user) {
-            synchronized (mVouchedSignaturesLocked) {
-                if (mVouchedSignaturesByUser.contains(user)) {
-                    return;
-                }
-                final long startTime = mStatLogger.getTime();
-
-                Set<String> vouches = Collections.newSetFromMap(
-                        new ConcurrentHashMap<String, Boolean>());
-
-                final int callingUid = injectBinderCallingUid();
-                long ident = Binder.clearCallingIdentity();
-                try {
-                    final PackageManagerInternal pmInt =
-                            LocalServices.getService(PackageManagerInternal.class);
-                    List<ApplicationInfo> installedPackages = pmInt.getInstalledApplications(
-                            PackageManager.GET_META_DATA, user.getIdentifier(), callingUid);
-                    for (ApplicationInfo appInfo : installedPackages) {
-                        updateVouches(appInfo, user);
-                    }
-                } finally {
-                    Binder.restoreCallingIdentity(ident);
-                }
-                mVouchedSignaturesByUser.putIfAbsent(user, vouches);
-                mStatLogger.logDurationStat(Stats.INIT_VOUCHED_SIGNATURES, startTime);
-            }
-        }
-
-        @Override
-        public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
-            if (!DumpUtils.checkDumpAndUsageStatsPermission(mContext, TAG, pw)) return;
-            mStatLogger.dump(pw, "  ");
-        }
-
         @Override
         public ActivityInfo resolveActivity(
                 String callingPackage, ComponentName component, UserHandle user)
@@ -1022,18 +875,6 @@
             mCallbackHandler.post(r);
         }
 
-        private class VouchesChangedMonitor extends PackageMonitor {
-            @Override
-            public void onPackageAdded(String packageName, int uid) {
-                updateVouches(packageName, new UserHandle(getChangingUserId()));
-            }
-
-            @Override
-            public void onPackageModified(String packageName) {
-                updateVouches(packageName, new UserHandle(getChangingUserId()));
-            }
-        }
-
         private class MyPackageMonitor extends PackageMonitor implements ShortcutChangeListener {
 
             // TODO Simplify with lambdas.
diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java
index 181b7a2..ad17549 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerService.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerService.java
@@ -123,6 +123,8 @@
 
     /** Automatically destroy sessions older than this */
     private static final long MAX_AGE_MILLIS = 3 * DateUtils.DAY_IN_MILLIS;
+    /** Automatically destroy staged sessions that have not changed state in this time */
+    private static final long MAX_TIME_SINCE_UPDATE_MILLIS = 7 * DateUtils.DAY_IN_MILLIS;
     /** Upper bound on number of active sessions for a UID */
     private static final long MAX_ACTIVE_SESSIONS = 1024;
     /** Upper bound on number of historical sessions for a UID */
@@ -357,11 +359,19 @@
                         }
 
                         final long age = System.currentTimeMillis() - session.createdMillis;
-
+                        final long timeSinceUpdate =
+                                System.currentTimeMillis() - session.updatedMillis;
                         final boolean valid;
-                        if (age >= MAX_AGE_MILLIS) {
-                            Slog.w(TAG, "Abandoning old session first created at "
-                                    + session.createdMillis);
+                        if (session.isStaged()) {
+                            if (timeSinceUpdate >= MAX_TIME_SINCE_UPDATE_MILLIS
+                                    && session.isStagedAndInTerminalState()) {
+                                valid = false;
+                            } else {
+                                valid = true;
+                            }
+                        } else if (age >= MAX_AGE_MILLIS) {
+                            Slog.w(TAG, "Abandoning old session created at "
+                                        + session.createdMillis);
                             valid = false;
                         } else {
                             valid = true;
@@ -1196,6 +1206,7 @@
         }
 
         public void onStagedSessionChanged(PackageInstallerSession session) {
+            session.markUpdated();
             writeSessionsAsync();
             if (mOkToSendBroadcasts) {
                 mPm.sendSessionUpdatedBroadcast(session.generateInfo(false),
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index 6451b56..66b530f 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -144,6 +144,7 @@
     private static final String ATTR_INSTALLER_PACKAGE_NAME = "installerPackageName";
     private static final String ATTR_INSTALLER_UID = "installerUid";
     private static final String ATTR_CREATED_MILLIS = "createdMillis";
+    private static final String ATTR_UPDATED_MILLIS = "updatedMillis";
     private static final String ATTR_SESSION_STAGE_DIR = "sessionStageDir";
     private static final String ATTR_SESSION_STAGE_CID = "sessionStageCid";
     private static final String ATTR_PREPARED = "prepared";
@@ -199,6 +200,10 @@
 
     private final Object mLock = new Object();
 
+    /** Timestamp of the last time this session changed state  */
+    @GuardedBy("mLock")
+    long updatedMillis;
+
     /** Uid of the creator of this session. */
     private final int mOriginalInstallerUid;
 
@@ -422,6 +427,7 @@
         mInstallerUid = installerUid;
         this.params = params;
         this.createdMillis = createdMillis;
+        this.updatedMillis = createdMillis;
         this.stageDir = stageDir;
         this.stageCid = stageCid;
         if (childSessionIds != null) {
@@ -521,6 +527,13 @@
         }
     }
 
+    /** Returns true if a staged session has reached a final state and can be forgotten about  */
+    public boolean isStagedAndInTerminalState() {
+        synchronized (mLock) {
+            return params.isStaged && (mStagedSessionApplied || mStagedSessionFailed);
+        }
+    }
+
     @GuardedBy("mLock")
     private void assertPreparedAndNotSealedLocked(String cookie) {
         assertPreparedAndNotCommittedOrDestroyedLocked(cookie);
@@ -1034,6 +1047,13 @@
         }
     }
 
+    /** Update the timestamp of when the staged session last changed state */
+    public void markUpdated() {
+        synchronized (mLock) {
+            this.updatedMillis = System.currentTimeMillis();
+        }
+    }
+
     @Override
     public void transfer(String packageName) {
         Preconditions.checkNotNull(packageName);
@@ -2114,7 +2134,7 @@
     private void destroyInternal() {
         synchronized (mLock) {
             mSealed = true;
-            if (!params.isStaged) {
+            if (!params.isStaged || isStagedAndInTerminalState()) {
                 mDestroyed = true;
             }
             // Force shut down all bridges
@@ -2224,6 +2244,7 @@
                     mInstallerPackageName);
             writeIntAttribute(out, ATTR_INSTALLER_UID, mInstallerUid);
             writeLongAttribute(out, ATTR_CREATED_MILLIS, createdMillis);
+            writeLongAttribute(out, ATTR_UPDATED_MILLIS, updatedMillis);
             if (stageDir != null) {
                 writeStringAttribute(out, ATTR_SESSION_STAGE_DIR,
                         stageDir.getAbsolutePath());
@@ -2326,6 +2347,7 @@
         final int installerUid = readIntAttribute(in, ATTR_INSTALLER_UID, pm.getPackageUid(
                 installerPackageName, PackageManager.MATCH_UNINSTALLED_PACKAGES, userId));
         final long createdMillis = readLongAttribute(in, ATTR_CREATED_MILLIS);
+        long updatedMillis = readLongAttribute(in, ATTR_UPDATED_MILLIS);
         final String stageDirRaw = readStringAttribute(in, ATTR_SESSION_STAGE_DIR);
         final File stageDir = (stageDirRaw != null) ? new File(stageDirRaw) : null;
         final String stageCid = readStringAttribute(in, ATTR_SESSION_STAGE_CID);
diff --git a/services/core/java/com/android/server/pm/PackageKeySetData.java b/services/core/java/com/android/server/pm/PackageKeySetData.java
index a9126c0..031b5ce 100644
--- a/services/core/java/com/android/server/pm/PackageKeySetData.java
+++ b/services/core/java/com/android/server/pm/PackageKeySetData.java
@@ -107,10 +107,7 @@
     }
 
     protected void removeAllDefinedKeySets() {
-        final int aliasSize = mKeySetAliases.size();
-        for (int i = 0; i < aliasSize; i++) {
-            mKeySetAliases.removeAt(i);
-        }
+        mKeySetAliases.erase();
     }
 
     protected boolean isUsingDefinedKeySets() {
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index e5b6397..ec2ff28 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -160,9 +160,9 @@
 import android.content.pm.InstantAppRequest;
 import android.content.pm.InstrumentationInfo;
 import android.content.pm.IntentFilterVerificationInfo;
-import android.content.pm.PackageBackwardCompatibility;
 import android.content.pm.KeySet;
 import android.content.pm.ModuleInfo;
+import android.content.pm.PackageBackwardCompatibility;
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageInfoLite;
 import android.content.pm.PackageInstaller;
@@ -232,6 +232,7 @@
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.os.UserManagerInternal;
+import android.os.storage.DiskInfo;
 import android.os.storage.IStorageManager;
 import android.os.storage.StorageEventListener;
 import android.os.storage.StorageManager;
@@ -245,6 +246,7 @@
 import android.security.KeyStore;
 import android.security.SystemKeyStore;
 import android.service.pm.PackageServiceDumpProto;
+import android.stats.storage.StorageEnums;
 import android.system.ErrnoException;
 import android.system.Os;
 import android.text.TextUtils;
@@ -269,6 +271,7 @@
 import android.util.SparseArray;
 import android.util.SparseBooleanArray;
 import android.util.SparseIntArray;
+import android.util.StatsLog;
 import android.util.TimingsTraceLog;
 import android.util.Xml;
 import android.util.jar.StrictJarFile;
@@ -549,10 +552,21 @@
     private static final long DEFAULT_VERIFICATION_TIMEOUT = 10 * 1000;
 
     /**
+     * Timeout duration in milliseconds for enabling package rollback. If we fail to enable
+     * rollback within that period, the install will proceed without rollback enabled.
+     *
+     * <p>If flag value is negative, the default value will be assigned.
+     *
+     * Flag type: {@code long}
+     * Namespace: NAMESPACE_ROLLBACK
+     */
+    private static final String PROPERTY_ENABLE_ROLLBACK_TIMEOUT_MILLIS = "enable_rollback_timeout";
+
+    /**
      * The default duration to wait for rollback to be enabled in
      * milliseconds.
      */
-    private static final long DEFAULT_ENABLE_ROLLBACK_TIMEOUT = 10 * 1000;
+    private static final long DEFAULT_ENABLE_ROLLBACK_TIMEOUT_MILLIS = 10 * 1000;
 
     /**
      * The default response for package verification timeout.
@@ -1912,6 +1926,15 @@
 
                 // Send broadcast package appeared if external for all users
                 if (isExternal(res.pkg)) {
+                    if (!update) {
+                        int packageExternalStorageType =
+                                getPackageExternalStorageType(res.pkg);
+                        // If the package was installed externally, log it.
+                        if (packageExternalStorageType != StorageEnums.UNKNOWN) {
+                            StatsLog.write(StatsLog.APP_INSTALL_ON_EXTERNAL_STORAGE_REPORTED,
+                                    packageExternalStorageType, res.pkg.packageName);
+                        }
+                    }
                     if (DEBUG_INSTALL) {
                         Slog.i(TAG, "upgrading pkg " + res.pkg + " is external");
                     }
@@ -2000,6 +2023,32 @@
         }
     }
 
+    /**
+     * Gets the type of the external storage a package is installed on.
+     * @param pkg The package for which to get the external storage type.
+     * @return {@link StorageEnum#TYPE_UNKNOWN} if it is not stored externally or the corresponding
+     * {@link StorageEnum} storage type value if it is.
+     */
+    private int getPackageExternalStorageType(PackageParser.Package pkg) {
+        final StorageManager storage = mContext.getSystemService(StorageManager.class);
+        VolumeInfo volume = storage.findVolumeByUuid(pkg.applicationInfo.storageUuid.toString());
+        if (volume != null) {
+            DiskInfo disk = volume.getDisk();
+            if (disk != null) {
+                if (disk.isSd()) {
+                    return StorageEnums.SD_CARD;
+                }
+                if (disk.isUsb()) {
+                    return StorageEnums.USB;
+                }
+                if (isExternal(pkg)) {
+                    return StorageEnums.OTHER;
+                }
+            }
+        }
+        return StorageEnums.UNKNOWN;
+    }
+
     private StorageEventListener mStorageListener = new StorageEventListener() {
         @Override
         public void onVolumeStateChanged(VolumeInfo vol, int oldState, int newState) {
@@ -14716,11 +14765,11 @@
                                 public void onReceive(Context context, Intent intent) {
                                     // the duration to wait for rollback to be enabled, in millis
                                     long rollbackTimeout = DeviceConfig.getLong(
-                                            DeviceConfig.Rollback.NAMESPACE,
-                                            DeviceConfig.Rollback.ENABLE_ROLLBACK_TIMEOUT,
-                                            DEFAULT_ENABLE_ROLLBACK_TIMEOUT);
+                                            DeviceConfig.NAMESPACE_ROLLBACK,
+                                            PROPERTY_ENABLE_ROLLBACK_TIMEOUT_MILLIS,
+                                            DEFAULT_ENABLE_ROLLBACK_TIMEOUT_MILLIS);
                                     if (rollbackTimeout < 0) {
-                                        rollbackTimeout = DEFAULT_ENABLE_ROLLBACK_TIMEOUT;
+                                        rollbackTimeout = DEFAULT_ENABLE_ROLLBACK_TIMEOUT_MILLIS;
                                     }
                                     final Message msg = mHandler.obtainMessage(
                                             ENABLE_ROLLBACK_TIMEOUT);
@@ -20124,21 +20173,20 @@
     }
 
     @Override
-    public String getContentCaptureServicePackageName() {
-        String contentCaptureServiceName =
-                mContext.getString(R.string.config_defaultContentCaptureService);
+    public String getSystemCaptionsServicePackageName() {
+        String flattenedSystemCaptionsServiceComponentName =
+                mContext.getString(R.string.config_defaultSystemCaptionsService);
 
-        if (TextUtils.isEmpty(contentCaptureServiceName)) {
+        if (TextUtils.isEmpty(flattenedSystemCaptionsServiceComponentName)) {
             return null;
         }
 
-        int separatorIndex = contentCaptureServiceName.indexOf("/");
-
-        if (separatorIndex < 0) {
+        ComponentName systemCaptionsServiceComponentName =
+                ComponentName.unflattenFromString(flattenedSystemCaptionsServiceComponentName);
+        if (systemCaptionsServiceComponentName == null) {
             return null;
         }
-
-        return contentCaptureServiceName.substring(0, separatorIndex);
+        return systemCaptionsServiceComponentName.getPackageName();
     }
 
     public String getIncidentReportApproverPackageName() {
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index aced1a2..459de1a 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -2693,6 +2693,7 @@
                 // seinfo     - seinfo label for the app (assigned at install time)
                 // gids       - supplementary gids this app launches with
                 // profileableFromShellFlag  - 0 or 1 if the package is profileable from shell.
+                // longVersionCode - integer version of the package.
                 //
                 // NOTE: We prefer not to expose all ApplicationInfo flags for now.
                 //
@@ -2720,6 +2721,8 @@
                 }
                 sb.append(" ");
                 sb.append(ai.isProfileableByShell() ? "1" : "0");
+                sb.append(" ");
+                sb.append(String.valueOf(ai.longVersionCode));
                 sb.append("\n");
                 writer.append(sb);
             }
diff --git a/services/core/java/com/android/server/pm/ShortcutPackage.java b/services/core/java/com/android/server/pm/ShortcutPackage.java
index eced165..9782648 100644
--- a/services/core/java/com/android/server/pm/ShortcutPackage.java
+++ b/services/core/java/com/android/server/pm/ShortcutPackage.java
@@ -99,6 +99,7 @@
     private static final String ATTR_ICON_RES_ID = "icon-res";
     private static final String ATTR_ICON_RES_NAME = "icon-resname";
     private static final String ATTR_BITMAP_PATH = "bitmap-path";
+    private static final String ATTR_LOCUS_ID = "locus-id";
 
     private static final String ATTR_PERSON_NAME = "name";
     private static final String ATTR_PERSON_URI = "uri";
@@ -1473,6 +1474,10 @@
         ShortcutService.writeAttr(out, ATTR_DISABLED_REASON, si.getDisabledReason());
         ShortcutService.writeAttr(out, ATTR_TIMESTAMP,
                 si.getLastChangedTimestamp());
+        final LocusId locusId = si.getLocusId();
+        if (locusId != null) {
+            ShortcutService.writeAttr(out, ATTR_LOCUS_ID, si.getLocusId().getId());
+        }
         if (forBackup) {
             // Don't write icon information.  Also drop the dynamic flag.
 
@@ -1612,6 +1617,7 @@
         int iconResId;
         String iconResName;
         String bitmapPath;
+        final String locusIdString;
         int backupVersionCode;
         ArraySet<String> categories = null;
         ArrayList<Person> persons = new ArrayList<>();
@@ -1638,6 +1644,7 @@
         iconResId = (int) ShortcutService.parseLongAttribute(parser, ATTR_ICON_RES_ID);
         iconResName = ShortcutService.parseStringAttribute(parser, ATTR_ICON_RES_NAME);
         bitmapPath = ShortcutService.parseStringAttribute(parser, ATTR_BITMAP_PATH);
+        locusIdString = ShortcutService.parseStringAttribute(parser, ATTR_LOCUS_ID);
 
         final int outerDepth = parser.getDepth();
         int type;
@@ -1703,7 +1710,7 @@
             flags |= ShortcutInfo.FLAG_SHADOW;
         }
 
-        LocusId locusId = null; // LocusId is not  set on XML.
+        final LocusId locusId = locusIdString == null ? null : new LocusId(locusIdString);
 
         return new ShortcutInfo(
                 userId, id, packageName, activityComponent, /* icon= */ null,
diff --git a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
index e9077a9..0a17e130 100644
--- a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
+++ b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
@@ -748,11 +748,11 @@
         grantSystemFixedPermissionsToSystemPackage("com.android.sharedstoragebackup", userId,
                 STORAGE_PERMISSIONS);
 
-        // Content Capture Service
-        String contentCaptureServicePackageName =
-                mContext.getPackageManager().getContentCaptureServicePackageName();
-        if (!TextUtils.isEmpty(contentCaptureServicePackageName)) {
-            grantPermissionsToSystemPackage(contentCaptureServicePackageName, userId,
+        // System Captions Service
+        String systemCaptionsServicePackageName =
+                mContext.getPackageManager().getSystemCaptionsServicePackageName();
+        if (!TextUtils.isEmpty(systemCaptionsServicePackageName)) {
+            grantPermissionsToSystemPackage(systemCaptionsServicePackageName, userId,
                     MICROPHONE_PERMISSIONS);
         }
 
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 897b885..e36ac23 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
@@ -17,14 +17,20 @@
 package com.android.server.pm.permission;
 
 import static android.Manifest.permission.READ_EXTERNAL_STORAGE;
+import static android.Manifest.permission.READ_MEDIA_AUDIO;
+import static android.Manifest.permission.READ_MEDIA_IMAGES;
+import static android.Manifest.permission.READ_MEDIA_VIDEO;
 import static android.Manifest.permission.WRITE_EXTERNAL_STORAGE;
 import static android.app.AppOpsManager.MODE_ALLOWED;
 import static android.app.AppOpsManager.MODE_ERRORED;
 import static android.app.AppOpsManager.MODE_FOREGROUND;
+import static android.app.AppOpsManager.MODE_IGNORED;
+import static android.app.AppOpsManager.OP_LEGACY_STORAGE;
 import static android.app.AppOpsManager.OP_NONE;
 import static android.app.AppOpsManager.permissionToOp;
 import static android.app.AppOpsManager.permissionToOpCode;
 import static android.content.pm.PackageManager.FLAG_PERMISSION_GRANTED_BY_DEFAULT;
+import static android.content.pm.PackageManager.FLAG_PERMISSION_HIDDEN;
 import static android.content.pm.PackageManager.FLAG_PERMISSION_POLICY_FIXED;
 import static android.content.pm.PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED;
 import static android.content.pm.PackageManager.FLAG_PERMISSION_REVOKE_ON_UPGRADE;
@@ -1149,6 +1155,8 @@
                     updatedUserIds);
             updatedUserIds = setInitialGrantForNewImplicitPermissionsLocked(origPermissions,
                     permissionsState, pkg, updatedUserIds);
+            updatedUserIds = applyLegacyStoragePermissionModel(origPermissions, permissionsState,
+                    pkg, updatedUserIds);
 
             setAppOpsLocked(permissionsState, pkg);
         }
@@ -1468,6 +1476,179 @@
     }
 
     /**
+     * Pre-Q apps use READ/WRITE_EXTERNAL_STORAGE, post-Q apps use READ_MEDIA_AUDIO/VIDEO/IMAGES.
+     *
+     * <p>There is the special case of the grandfathered post-Q app that has all legacy and modern
+     * permissions system-fixed granted. The only way to remove these permissions is to uninstall
+     * the app.
+     *
+     * @param origPs The permission state of the package before the update
+     * @param ps The permissions state of the package
+     * @param pkg The package
+     * @param updatedUserIds The userIds we have already been updated before
+     *
+     * @return The userIds that have been updated
+     *
+     * @see com.android.server.StorageManagerService#applyLegacyStorage()
+     */
+    private @NonNull int[] applyLegacyStoragePermissionModel(@NonNull PermissionsState origPs,
+            @NonNull PermissionsState ps, @NonNull PackageParser.Package pkg,
+            @NonNull int[] updatedUserIds) {
+        AppOpsManagerInternal appOpsManager = LocalServices.getService(AppOpsManagerInternal.class);
+        int[] users = UserManagerService.getInstance().getUserIds();
+
+        boolean isQApp = pkg.applicationInfo.targetSdkVersion >= Build.VERSION_CODES.Q;
+        boolean isPreMApp = pkg.applicationInfo.targetSdkVersion < Build.VERSION_CODES.M;
+        int appId = getAppId(pkg.applicationInfo.uid);
+
+        int numRequestedPerms = pkg.requestedPermissions.size();
+        for (int i = 0; i < numRequestedPerms; i++) {
+            String perm = pkg.requestedPermissions.get(i);
+
+            boolean isLegacyStoragePermission = false;
+            boolean isModernStoragePermission = false;
+            switch (perm) {
+                case READ_EXTERNAL_STORAGE:
+                case WRITE_EXTERNAL_STORAGE:
+                    isLegacyStoragePermission = true;
+                    break;
+                case READ_MEDIA_AUDIO:
+                case READ_MEDIA_VIDEO:
+                case READ_MEDIA_IMAGES:
+                    isModernStoragePermission = true;
+                    break;
+                default:
+                    // 'perm' is not a storage permission, skip it
+                    continue;
+            }
+
+            BasePermission bp = mSettings.getPermissionLocked(perm);
+
+            for (int userId : users) {
+                boolean useLegacyStoragePermissionModel;
+                if (isQApp) {
+                    useLegacyStoragePermissionModel = appOpsManager.checkOperationUnchecked(
+                            OP_LEGACY_STORAGE, getUid(userId, appId), pkg.packageName)
+                            == MODE_ALLOWED;
+                } else {
+                    useLegacyStoragePermissionModel = true;
+                }
+
+                int origCombinedLegacyFlags =
+                        origPs.getPermissionFlags(READ_EXTERNAL_STORAGE, userId)
+                        | origPs.getPermissionFlags(WRITE_EXTERNAL_STORAGE, userId);
+
+                int origCombinedModernFlags = origPs.getPermissionFlags(READ_MEDIA_AUDIO, userId)
+                        | origPs.getPermissionFlags(READ_MEDIA_VIDEO, userId)
+                        | origPs.getPermissionFlags(READ_MEDIA_IMAGES, userId);
+
+                boolean oldPermAreLegacyStorageModel =
+                        (origCombinedLegacyFlags & FLAG_PERMISSION_HIDDEN) == 0;
+                boolean oldPermAreModernStorageModel =
+                        (origCombinedModernFlags & FLAG_PERMISSION_HIDDEN) == 0;
+
+                if (oldPermAreLegacyStorageModel && oldPermAreModernStorageModel) {
+                    // This only happens after an platform upgrade from before Q
+                    oldPermAreModernStorageModel = false;
+                }
+
+                boolean shouldBeRestricted;
+                boolean shouldBeFixed;
+                boolean shouldBeGranted = false;
+                boolean shouldBeRevoked = false;
+                int userFlags = -1;
+                if (useLegacyStoragePermissionModel) {
+                    shouldBeRestricted = isModernStoragePermission;
+                    shouldBeFixed = isQApp || isModernStoragePermission;
+
+                    if (shouldBeFixed) {
+                        userFlags = 0;
+                        shouldBeGranted = true;
+                        shouldBeRevoked = false;
+                    } else if (oldPermAreModernStorageModel) {
+                        // Inherit grant state on permission model change
+                        userFlags = origCombinedModernFlags;
+
+                        shouldBeGranted = origPs.hasRuntimePermission(READ_MEDIA_AUDIO, userId)
+                                || origPs.hasRuntimePermission(READ_MEDIA_VIDEO, userId)
+                                || origPs.hasRuntimePermission(READ_MEDIA_IMAGES, userId);
+
+                        shouldBeRevoked = !shouldBeGranted;
+                    }
+                } else {
+                    shouldBeRestricted = isLegacyStoragePermission;
+                    shouldBeFixed = isLegacyStoragePermission;
+
+                    if (shouldBeFixed) {
+                        userFlags = 0;
+                        shouldBeGranted = true;
+                        shouldBeRevoked = false;
+                    } else if (oldPermAreLegacyStorageModel) {
+                        // Inherit grant state on permission model change
+                        userFlags = origCombinedLegacyFlags;
+
+                        shouldBeGranted = origPs.hasRuntimePermission(READ_EXTERNAL_STORAGE, userId)
+                                || origPs.hasRuntimePermission(WRITE_EXTERNAL_STORAGE, userId);
+
+                        if ((origCombinedLegacyFlags & FLAG_PERMISSION_REVOKE_ON_UPGRADE) != 0
+                                && !isPreMApp) {
+                            shouldBeGranted = false;
+                        }
+
+                        shouldBeRevoked = !shouldBeGranted;
+                    }
+                }
+
+                // Granted permissions can never be user fixed
+                if (shouldBeGranted & userFlags != -1) {
+                    userFlags &= ~FLAG_PERMISSION_USER_FIXED;
+                }
+
+                boolean changed = false;
+                synchronized (mLock) {
+                    if (shouldBeGranted) {
+                        if (isPreMApp) {
+                            setAppOpMode(perm, pkg, userId, MODE_ALLOWED);
+                        } else if (!ps.hasRuntimePermission(perm, userId)) {
+                            ps.grantRuntimePermission(bp, userId);
+                            changed = true;
+                        }
+                    }
+
+                    if (shouldBeRevoked) {
+                        if (isPreMApp) {
+                            setAppOpMode(perm, pkg, userId, MODE_IGNORED);
+                        } else if (ps.hasRuntimePermission(perm, userId)) {
+                            ps.revokeRuntimePermission(bp, userId);
+                            changed = true;
+                        }
+                    }
+
+                    if (shouldBeFixed) {
+                        changed |= ps.updatePermissionFlags(mSettings.getPermissionLocked(perm),
+                                userId, FLAG_PERMISSION_SYSTEM_FIXED, FLAG_PERMISSION_SYSTEM_FIXED);
+                    }
+
+                    if (userFlags != -1) {
+                        changed |= ps.updatePermissionFlags(mSettings.getPermissionLocked(perm),
+                                userId, USER_PERMISSION_FLAGS, userFlags);
+                    }
+
+                    changed |= ps.updatePermissionFlags(mSettings.getPermissionLocked(perm), userId,
+                            FLAG_PERMISSION_HIDDEN,
+                            shouldBeRestricted ? FLAG_PERMISSION_HIDDEN : 0);
+                }
+
+                if (changed) {
+                    updatedUserIds = ArrayUtils.appendInt(updatedUserIds, userId);
+                }
+            }
+        }
+
+        return updatedUserIds;
+    }
+
+    /**
      * Fix app-op modes for runtime permissions.
      *
      * @param permsState The state of the permissions of the package
diff --git a/services/core/java/com/android/server/pm/permission/TEST_MAPPING b/services/core/java/com/android/server/pm/permission/TEST_MAPPING
index 2280d3f..c610ed0 100644
--- a/services/core/java/com/android/server/pm/permission/TEST_MAPPING
+++ b/services/core/java/com/android/server/pm/permission/TEST_MAPPING
@@ -19,6 +19,9 @@
                 },
                 {
                     "include-filter": "android.permission.cts.PermissionFlagsTest"
+                },
+                {
+                    "include-filter": "android.permission.cts.DualStoragePermissionModelTest"
                 }
             ]
         },
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 5810636..5a32aa0 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -104,7 +104,6 @@
 import android.annotation.Nullable;
 import android.app.ActivityManager;
 import android.app.ActivityManagerInternal;
-import android.app.ActivityOptions;
 import android.app.ActivityTaskManager;
 import android.app.AppOpsManager;
 import android.app.IUiModeManager;
@@ -918,9 +917,6 @@
 
         mWindowManagerFuncs.onPowerKeyDown(interactive);
 
-        // Abort possibly stuck animations.
-        mHandler.post(mWindowManagerFuncs::triggerAnimationFailsafe);
-
         // Latch power key state to detect screenshot chord.
         if (interactive && !mScreenshotChordPowerKeyTriggered
                 && (event.getFlags() & KeyEvent.FLAG_FALLBACK) == 0) {
@@ -1027,6 +1023,11 @@
         cancelPendingPowerKeyAction();
 
         if (!handled) {
+            if ((event.getFlags() & KeyEvent.FLAG_LONG_PRESS) == 0) {
+                // Abort possibly stuck animations only when power key up without long press case.
+                mHandler.post(mWindowManagerFuncs::triggerAnimationFailsafe);
+            }
+
             // Figure out how to handle the key now that it has been released.
             mPowerKeyPressCounter += 1;
 
@@ -2521,7 +2522,6 @@
     }
 
     private static final int[] WINDOW_TYPES_WHERE_HOME_DOESNT_WORK = {
-            WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY,
             WindowManager.LayoutParams.TYPE_SYSTEM_ALERT,
             WindowManager.LayoutParams.TYPE_SYSTEM_ERROR,
         };
@@ -3363,9 +3363,6 @@
      */
     void launchHomeFromHotKey(int displayId, final boolean awakenFromDreams,
             final boolean respectKeyguard) {
-        // Abort possibly stuck animations.
-        mHandler.post(mWindowManagerFuncs::triggerAnimationFailsafe);
-
         if (respectKeyguard) {
             if (isKeyguardShowingAndNotOccluded()) {
                 // don't launch home if keyguard showing
@@ -5114,6 +5111,7 @@
             awakenDreams();
         }
 
+        // Start dock.
         Intent dock = createHomeDockIntent();
         if (dock != null) {
             try {
@@ -5126,21 +5124,9 @@
             }
         }
 
-        Intent intent;
-
-        if (fromHomeKey) {
-            intent = new Intent(mHomeIntent);
-            intent.putExtra(WindowManagerPolicy.EXTRA_FROM_HOME_KEY, fromHomeKey);
-        } else {
-            intent = mHomeIntent;
-        }
-        final Bundle bundle = getLaunchDisplayIdBundle(displayId);
-        startActivityAsUser(intent, bundle, UserHandle.CURRENT);
-    }
-
-    private @Nullable Bundle getLaunchDisplayIdBundle(int displayId) {
-        return (displayId == INVALID_DISPLAY) ? null
-                : ActivityOptions.makeBasic().setLaunchDisplayId(displayId).toBundle();
+        // Start home.
+        mActivityTaskManagerInternal.startHomeOnDisplay(mCurrentUserId, "startDockOrHome",
+                displayId, fromHomeKey);
     }
 
     /**
diff --git a/services/core/java/com/android/server/policy/WindowManagerPolicy.java b/services/core/java/com/android/server/policy/WindowManagerPolicy.java
index 2af2342..b196754 100644
--- a/services/core/java/com/android/server/policy/WindowManagerPolicy.java
+++ b/services/core/java/com/android/server/policy/WindowManagerPolicy.java
@@ -829,9 +829,11 @@
                 return  9;
             case TYPE_SYSTEM_ALERT:
                 // like the ANR / app crashed dialogs
-                return  canAddInternalSystemWindow ? 11 : 10;
+                // Type is deprecated for non-system apps. For system apps, this type should be
+                // in a higher layer than TYPE_APPLICATION_OVERLAY.
+                return  canAddInternalSystemWindow ? 13 : 10;
             case TYPE_APPLICATION_OVERLAY:
-                return  canAddInternalSystemWindow ? 13 : 12;
+                return  12;
             case TYPE_DREAM:
                 // used for Dreams (screensavers with TYPE_DREAM windows)
                 return  14;
diff --git a/services/core/java/com/android/server/power/AttentionDetector.java b/services/core/java/com/android/server/power/AttentionDetector.java
index 406cbc1..701e5af 100644
--- a/services/core/java/com/android/server/power/AttentionDetector.java
+++ b/services/core/java/com/android/server/power/AttentionDetector.java
@@ -269,7 +269,7 @@
      */
     @VisibleForTesting
     boolean isAttentionServiceSupported() {
-        return mAttentionManager.isAttentionServiceSupported();
+        return mAttentionManager != null && mAttentionManager.isAttentionServiceSupported();
     }
 
     public void dump(PrintWriter pw) {
diff --git a/services/core/java/com/android/server/power/Notifier.java b/services/core/java/com/android/server/power/Notifier.java
index 1a82858..b81d969 100644
--- a/services/core/java/com/android/server/power/Notifier.java
+++ b/services/core/java/com/android/server/power/Notifier.java
@@ -486,6 +486,8 @@
                         log.setType(MetricsEvent.TYPE_OPEN);
                         log.setSubtype(why);
                         log.setLatency(interactiveChangeLatency);
+                        log.addTaggedData(
+                                MetricsEvent.FIELD_SCREEN_WAKE_REASON, mInteractiveChangeReason);
                         MetricsLogger.action(log);
                         EventLogTags.writePowerScreenState(1, 0, 0, 0, interactiveChangeLatency);
                         mPolicy.finishedWakingUp(why);
@@ -513,6 +515,8 @@
                         log.setType(MetricsEvent.TYPE_CLOSE);
                         log.setSubtype(why);
                         log.setLatency(interactiveChangeLatency);
+                        log.addTaggedData(
+                                MetricsEvent.FIELD_SCREEN_SLEEP_REASON, mInteractiveChangeReason);
                         MetricsLogger.action(log);
                         EventLogTags.writePowerScreenState(0, why, 0, 0, interactiveChangeLatency);
                         mPolicy.finishedGoingToSleep(why);
diff --git a/services/core/java/com/android/server/power/batterysaver/BatterySaverController.java b/services/core/java/com/android/server/power/batterysaver/BatterySaverController.java
index 5adcf35..f0e4625 100644
--- a/services/core/java/com/android/server/power/batterysaver/BatterySaverController.java
+++ b/services/core/java/com/android/server/power/batterysaver/BatterySaverController.java
@@ -115,9 +115,41 @@
     public static final int REASON_SETTING_CHANGED = 8;
     public static final int REASON_DYNAMIC_POWER_SAVINGS_AUTOMATIC_ON = 9;
     public static final int REASON_DYNAMIC_POWER_SAVINGS_AUTOMATIC_OFF = 10;
-    public static final int REASON_STICKY_RESTORE_OFF = 11;
-    public static final int REASON_ADAPTIVE_DYNAMIC_POWER_SAVINGS_CHANGED = 12;
-    public static final int REASON_TIMEOUT = 13;
+    public static final int REASON_ADAPTIVE_DYNAMIC_POWER_SAVINGS_CHANGED = 11;
+    public static final int REASON_TIMEOUT = 12;
+
+    static String reasonToString(int reason) {
+        switch (reason) {
+            case BatterySaverController.REASON_PERCENTAGE_AUTOMATIC_ON:
+                return "Percentage Auto ON";
+            case BatterySaverController.REASON_PERCENTAGE_AUTOMATIC_OFF:
+                return "Percentage Auto OFF";
+            case BatterySaverController.REASON_MANUAL_ON:
+                return "Manual ON";
+            case BatterySaverController.REASON_MANUAL_OFF:
+                return "Manual OFF";
+            case BatterySaverController.REASON_STICKY_RESTORE:
+                return "Sticky restore";
+            case BatterySaverController.REASON_INTERACTIVE_CHANGED:
+                return "Interactivity changed";
+            case BatterySaverController.REASON_POLICY_CHANGED:
+                return "Policy changed";
+            case BatterySaverController.REASON_PLUGGED_IN:
+                return "Plugged in";
+            case BatterySaverController.REASON_SETTING_CHANGED:
+                return "Setting changed";
+            case BatterySaverController.REASON_DYNAMIC_POWER_SAVINGS_AUTOMATIC_ON:
+                return "Dynamic Warning Auto ON";
+            case BatterySaverController.REASON_DYNAMIC_POWER_SAVINGS_AUTOMATIC_OFF:
+                return "Dynamic Warning Auto OFF";
+            case BatterySaverController.REASON_ADAPTIVE_DYNAMIC_POWER_SAVINGS_CHANGED:
+                return "Adaptive Power Savings changed";
+            case BatterySaverController.REASON_TIMEOUT:
+                return "timeout";
+            default:
+                return "Unknown reason: " + reason;
+        }
+    }
 
     /**
      * Plugin interface. All methods are guaranteed to be called on the same (handler) thread.
diff --git a/services/core/java/com/android/server/power/batterysaver/BatterySaverStateMachine.java b/services/core/java/com/android/server/power/batterysaver/BatterySaverStateMachine.java
index af5d40bf..61daca7 100644
--- a/services/core/java/com/android/server/power/batterysaver/BatterySaverStateMachine.java
+++ b/services/core/java/com/android/server/power/batterysaver/BatterySaverStateMachine.java
@@ -15,6 +15,10 @@
  */
 package com.android.server.power.batterysaver;
 
+import static com.android.server.power.batterysaver.BatterySaverController.reasonToString;
+
+import android.annotation.NonNull;
+import android.annotation.StringRes;
 import android.app.Notification;
 import android.app.NotificationChannel;
 import android.app.NotificationManager;
@@ -49,17 +53,74 @@
  * Do not call out with the lock held. (Settings provider is okay.)
  *
  * Test: atest com.android.server.power.batterysaver.BatterySaverStateMachineTest
+ *
+ * Current state machine. This can be visualized using Graphviz:
+   <pre>
+
+   digraph {
+     STATE_OFF
+     STATE_MANUAL_ON [label="STATE_MANUAL_ON\nTurned on manually by the user"]
+     STATE_AUTOMATIC_ON [label="STATE_AUTOMATIC_ON\nTurned on automatically by the system"]
+     STATE_OFF_AUTOMATIC_SNOOZED [
+       label="STATE_OFF_AUTOMATIC_SNOOZED\nTurned off manually by the user."
+           + " The system should not turn it back on automatically."
+     ]
+     STATE_PENDING_STICKY_ON [
+       label="STATE_PENDING_STICKY_ON\n"
+           + " Turned on manually by the user and then plugged in. Will turn back on after unplug."
+     ]
+
+     STATE_OFF -> STATE_MANUAL_ON [label="manual"]
+     STATE_OFF -> STATE_AUTOMATIC_ON [label="Auto on AND charge <= auto threshold"]
+
+     STATE_MANUAL_ON -> STATE_OFF [label="manual\nOR\nPlugged & sticky disabled"]
+     STATE_MANUAL_ON -> STATE_PENDING_STICKY_ON [label="Plugged & sticky enabled"]
+
+     STATE_PENDING_STICKY_ON -> STATE_MANUAL_ON [label="Unplugged & sticky enabled"]
+     STATE_PENDING_STICKY_ON -> STATE_OFF [
+       label="Sticky disabled\nOR\nSticky auto off enabled AND charge >= sticky auto off threshold"
+     ]
+
+     STATE_AUTOMATIC_ON -> STATE_OFF [label="Plugged"]
+     STATE_AUTOMATIC_ON -> STATE_OFF_AUTOMATIC_SNOOZED [label="Manual"]
+
+     STATE_OFF_AUTOMATIC_SNOOZED -> STATE_OFF [label="Plug\nOR\nCharge > auto threshold"]
+     STATE_OFF_AUTOMATIC_SNOOZED -> STATE_MANUAL_ON [label="manual"]
+
+     </pre>
+   }
  */
 public class BatterySaverStateMachine {
     private static final String TAG = "BatterySaverStateMachine";
     private static final String DYNAMIC_MODE_NOTIF_CHANNEL_ID = "dynamic_mode_notification";
+    private static final String BATTERY_SAVER_NOTIF_CHANNEL_ID = "battery_saver_channel";
     private static final int DYNAMIC_MODE_NOTIFICATION_ID = 1992;
+    private static final int STICKY_AUTO_DISABLED_NOTIFICATION_ID = 1993;
     private final Object mLock;
 
     private static final boolean DEBUG = BatterySaverPolicy.DEBUG;
 
     private static final long ADAPTIVE_CHANGE_TIMEOUT_MS = 24 * 60 * 60 * 1000L;
 
+    /** Turn off adaptive battery saver if the device has charged above this level. */
+    private static final int ADAPTIVE_AUTO_DISABLE_BATTERY_LEVEL = 80;
+
+    private static final int STATE_OFF = BatterySaverStateMachineProto.STATE_OFF;
+
+    /** Turned on manually by the user. */
+    private static final int STATE_MANUAL_ON = BatterySaverStateMachineProto.STATE_MANUAL_ON;
+
+    /** Turned on automatically by the system. */
+    private static final int STATE_AUTOMATIC_ON = BatterySaverStateMachineProto.STATE_AUTOMATIC_ON;
+
+    /** Turned off manually by the user. The system should not turn it back on automatically. */
+    private static final int STATE_OFF_AUTOMATIC_SNOOZED =
+            BatterySaverStateMachineProto.STATE_OFF_AUTOMATIC_SNOOZED;
+
+    /** Turned on manually by the user and then plugged in. Will turn back on after unplug. */
+    private static final int STATE_PENDING_STICKY_ON =
+            BatterySaverStateMachineProto.STATE_PENDING_STICKY_ON;
+
     private final Context mContext;
     private final BatterySaverController mBatterySaverController;
 
@@ -75,6 +136,9 @@
     @GuardedBy("mLock")
     private boolean mBatteryStatusSet;
 
+    @GuardedBy("mLock")
+    private int mState;
+
     /** Whether the device is connected to any power source. */
     @GuardedBy("mLock")
     private boolean mIsPowered;
@@ -142,13 +206,6 @@
     private boolean mDynamicPowerSavingsBatterySaver;
 
     /**
-     * Whether BS has been manually disabled while the battery level is low, in which case we
-     * shouldn't auto re-enable it until the battery level is not low.
-     */
-    @GuardedBy("mLock")
-    private boolean mBatterySaverSnoozing;
-
-    /**
      * Last reason passed to {@link #enableBatterySaverLocked}.
      */
     @GuardedBy("mLock")
@@ -181,6 +238,7 @@
         mLock = lock;
         mContext = context;
         mBatterySaverController = batterySaverController;
+        mState = STATE_OFF;
 
         mBatterySaverStickyBehaviourDisabled = mContext.getResources().getBoolean(
                 com.android.internal.R.bool.config_batterySaverStickyBehaviourDisabled);
@@ -188,8 +246,36 @@
                 com.android.internal.R.integer.config_dynamicPowerSavingsDefaultDisableThreshold);
     }
 
-    private boolean isAutoBatterySaverConfiguredLocked() {
-        return mSettingBatterySaverTriggerThreshold > 0;
+    /** @return true if the automatic percentage based mode should be used */
+    private boolean isAutomaticModeActiveLocked() {
+        return mSettingAutomaticBatterySaver == PowerManager.POWER_SAVER_MODE_PERCENTAGE
+                && mSettingBatterySaverTriggerThreshold > 0;
+    }
+
+    /**
+     * The returned value won't necessarily make sense if {@link #isAutomaticModeActiveLocked()}
+     * returns {@code false}.
+     *
+     * @return true if the battery level is below automatic's threshold.
+     */
+    private boolean isInAutomaticLowZoneLocked() {
+        return mIsBatteryLevelLow;
+    }
+
+    /** @return true if the dynamic mode should be used */
+    private boolean isDynamicModeActiveLocked() {
+        return mSettingAutomaticBatterySaver == PowerManager.POWER_SAVER_MODE_DYNAMIC
+                && mDynamicPowerSavingsBatterySaver;
+    }
+
+    /**
+     * The returned value won't necessarily make sense if {@link #isDynamicModeActiveLocked()}
+     * returns {@code false}.
+     *
+     * @return true if the battery level is below dynamic's threshold.
+     */
+    private boolean isInDynamicLowZoneLocked() {
+        return mBatteryLevel <= mDynamicPowerSavingsDisableThreshold;
     }
 
     /**
@@ -233,7 +319,14 @@
                     Settings.Global.LOW_POWER_MODE_STICKY_AUTO_DISABLE_LEVEL),
                     false, mSettingsObserver, UserHandle.USER_SYSTEM);
 
+
             synchronized (mLock) {
+                final boolean lowPowerModeEnabledSticky = getGlobalSetting(
+                        Settings.Global.LOW_POWER_MODE_STICKY, 0) != 0;
+
+                if (lowPowerModeEnabledSticky) {
+                    mState = STATE_PENDING_STICKY_ON;
+                }
 
                 mBootCompleted = true;
 
@@ -357,11 +450,17 @@
             runOnBgThreadLazy(mThresholdChangeLogger, 2000);
         }
 
+        if (!mSettingBatterySaverStickyAutoDisableEnabled) {
+            hideStickyDisabledNotification();
+        }
+
         if (enabledChanged) {
             final String reason = batterySaverEnabled
                     ? "Global.low_power changed to 1" : "Global.low_power changed to 0";
             enableBatterySaverLocked(/*enable=*/ batterySaverEnabled, /*manual=*/ true,
                     BatterySaverController.REASON_SETTING_CHANGED, reason);
+        } else {
+            doAutoBatterySaverLocked();
         }
     }
 
@@ -428,17 +527,6 @@
         }
     }
 
-    @GuardedBy("mLock")
-    private boolean isBatteryLowLocked() {
-        final boolean percentageLow =
-                mSettingAutomaticBatterySaver == PowerManager.POWER_SAVER_MODE_PERCENTAGE
-                && mIsBatteryLevelLow;
-        final boolean dynamicPowerSavingsLow =
-                mSettingAutomaticBatterySaver == PowerManager.POWER_SAVER_MODE_DYNAMIC
-                && mBatteryLevel <= mDynamicPowerSavingsDisableThreshold;
-        return percentageLow || dynamicPowerSavingsLow;
-    }
-
     /**
      * Decide whether to auto-start / stop battery saver.
      */
@@ -449,7 +537,6 @@
                     + " mSettingsLoaded=" + mSettingsLoaded
                     + " mBatteryStatusSet=" + mBatteryStatusSet
                     + " mIsBatteryLevelLow=" + mIsBatteryLevelLow
-                    + " mBatterySaverSnoozing=" + mBatterySaverSnoozing
                     + " mIsPowered=" + mIsPowered
                     + " mSettingAutomaticBatterySaver=" + mSettingAutomaticBatterySaver
                     + " mSettingBatterySaverEnabledSticky=" + mSettingBatterySaverEnabledSticky
@@ -460,66 +547,170 @@
             return; // Not fully initialized yet.
         }
 
-        if (!isBatteryLowLocked()) {
-            updateSnoozingLocked(false, "Battery not low");
-        }
+        updateStateLocked(false, false);
 
+        // Adaptive control.
         if (SystemClock.elapsedRealtime() - mLastAdaptiveBatterySaverChangedExternallyElapsed
                 > ADAPTIVE_CHANGE_TIMEOUT_MS) {
             mBatterySaverController.setAdaptivePolicyEnabledLocked(
                     false, BatterySaverController.REASON_TIMEOUT);
             mBatterySaverController.resetAdaptivePolicyLocked(
                     BatterySaverController.REASON_TIMEOUT);
+        } else if (mIsPowered && mBatteryLevel >= ADAPTIVE_AUTO_DISABLE_BATTERY_LEVEL) {
+            mBatterySaverController.setAdaptivePolicyEnabledLocked(false,
+                    BatterySaverController.REASON_PLUGGED_IN);
+        }
+    }
+
+    /**
+     * Update the state machine based on the current settings and battery/charge status.
+     *
+     * @param manual Whether the change was made by the user.
+     * @param enable Whether the user wants to turn battery saver on or off. Is only used if {@param
+     *               manual} is true.
+     */
+    @GuardedBy("mLock")
+    private void updateStateLocked(boolean manual, boolean enable) {
+        if (!manual && !(mBootCompleted && mSettingsLoaded && mBatteryStatusSet)) {
+            return; // Not fully initialized yet.
         }
 
-        if (mIsPowered) {
-            updateSnoozingLocked(false, "Plugged in");
-            enableBatterySaverLocked(/*enable=*/ false, /*manual=*/ false,
-                    BatterySaverController.REASON_PLUGGED_IN,
-                    "Plugged in");
-
-            if (mBatteryLevel >= 80 /* Arbitrary level */) {
-                mBatterySaverController.setAdaptivePolicyEnabledLocked(
-                        false, BatterySaverController.REASON_PLUGGED_IN);
+        switch (mState) {
+            case STATE_OFF: {
+                if (!mIsPowered) {
+                    if (manual) {
+                        if (!enable) {
+                            Slog.e(TAG, "Tried to disable BS when it's already OFF");
+                            return;
+                        }
+                        enableBatterySaverLocked(/*enable*/ true, /*manual*/ true,
+                                BatterySaverController.REASON_MANUAL_ON);
+                        hideStickyDisabledNotification();
+                        mState = STATE_MANUAL_ON;
+                    } else if (isAutomaticModeActiveLocked() && isInAutomaticLowZoneLocked()) {
+                        enableBatterySaverLocked(/*enable*/ true, /*manual*/ false,
+                                BatterySaverController.REASON_PERCENTAGE_AUTOMATIC_ON);
+                        hideStickyDisabledNotification();
+                        mState = STATE_AUTOMATIC_ON;
+                    } else if (isDynamicModeActiveLocked() && isInDynamicLowZoneLocked()) {
+                        enableBatterySaverLocked(/*enable*/ true, /*manual*/ false,
+                                BatterySaverController.REASON_DYNAMIC_POWER_SAVINGS_AUTOMATIC_ON);
+                        hideStickyDisabledNotification();
+                        mState = STATE_AUTOMATIC_ON;
+                    }
+                }
+                break;
             }
 
-        } else if (mSettingBatterySaverEnabledSticky && !mBatterySaverStickyBehaviourDisabled) {
-            if (mSettingBatterySaverStickyAutoDisableEnabled
-                    && mBatteryLevel >= mSettingBatterySaverStickyAutoDisableThreshold) {
-                setStickyActive(false);
-            } else {
-                // Re-enable BS.
-                enableBatterySaverLocked(/*enable=*/ true, /*manual=*/ true,
-                        BatterySaverController.REASON_STICKY_RESTORE,
-                        "Sticky restore");
+            case STATE_MANUAL_ON: {
+                if (manual) {
+                    if (enable) {
+                        Slog.e(TAG, "Tried to enable BS when it's already MANUAL_ON");
+                        return;
+                    }
+                    enableBatterySaverLocked(/*enable*/ false, /*manual*/ true,
+                            BatterySaverController.REASON_MANUAL_OFF);
+                    mState = STATE_OFF;
+                } else if (mIsPowered) {
+                    enableBatterySaverLocked(/*enable*/ false, /*manual*/ false,
+                            BatterySaverController.REASON_PLUGGED_IN);
+                    if (mSettingBatterySaverEnabledSticky
+                            && !mBatterySaverStickyBehaviourDisabled) {
+                        mState = STATE_PENDING_STICKY_ON;
+                    } else {
+                        mState = STATE_OFF;
+                    }
+                }
+                break;
             }
 
-        } else if (mSettingAutomaticBatterySaver
-                == PowerManager.POWER_SAVER_MODE_PERCENTAGE
-                && isAutoBatterySaverConfiguredLocked()) {
-            if (mIsBatteryLevelLow && !mBatterySaverSnoozing) {
-                enableBatterySaverLocked(/*enable=*/ true, /*manual=*/ false,
-                        BatterySaverController.REASON_PERCENTAGE_AUTOMATIC_ON,
-                        "Percentage Auto ON");
-            } else {
-                // Battery not low
-                enableBatterySaverLocked(/*enable=*/ false, /*manual=*/ false,
-                        BatterySaverController.REASON_PERCENTAGE_AUTOMATIC_OFF,
-                        "Percentage Auto OFF");
+            case STATE_AUTOMATIC_ON: {
+                if (mIsPowered) {
+                    enableBatterySaverLocked(/*enable*/ false, /*manual*/ false,
+                            BatterySaverController.REASON_PLUGGED_IN);
+                    mState = STATE_OFF;
+                } else if (manual) {
+                    if (enable) {
+                        Slog.e(TAG, "Tried to enable BS when it's already AUTO_ON");
+                        return;
+                    }
+                    enableBatterySaverLocked(/*enable*/ false, /*manual*/ true,
+                            BatterySaverController.REASON_MANUAL_OFF);
+                    // When battery saver is disabled manually (while battery saver is enabled)
+                    // when the battery level is low, we "snooze" BS -- i.e. disable auto battery
+                    // saver.
+                    // We resume auto-BS once the battery level is not low, or the device is
+                    // plugged in.
+                    mState = STATE_OFF_AUTOMATIC_SNOOZED;
+                } else if (isAutomaticModeActiveLocked() && !isInAutomaticLowZoneLocked()) {
+                    enableBatterySaverLocked(/*enable*/ false, /*manual*/ false,
+                            BatterySaverController.REASON_PERCENTAGE_AUTOMATIC_OFF);
+                    mState = STATE_OFF;
+                } else if (isDynamicModeActiveLocked() && !isInDynamicLowZoneLocked()) {
+                    enableBatterySaverLocked(/*enable*/ false, /*manual*/ false,
+                            BatterySaverController.REASON_DYNAMIC_POWER_SAVINGS_AUTOMATIC_OFF);
+                    mState = STATE_OFF;
+                } else if (!isAutomaticModeActiveLocked() && !isDynamicModeActiveLocked()) {
+                    enableBatterySaverLocked(/*enable*/ false, /*manual*/ false,
+                            BatterySaverController.REASON_SETTING_CHANGED);
+                    mState = STATE_OFF;
+                }
+                break;
             }
-        } else if (mSettingAutomaticBatterySaver
-                == PowerManager.POWER_SAVER_MODE_DYNAMIC) {
-            if (mBatteryLevel >= mDynamicPowerSavingsDisableThreshold) {
-                enableBatterySaverLocked(/*enable=*/ false, /*manual=*/ false,
-                        BatterySaverController.REASON_DYNAMIC_POWER_SAVINGS_AUTOMATIC_OFF,
-                        "Dynamic Warning Auto OFF");
-            } else if (mDynamicPowerSavingsBatterySaver && !mBatterySaverSnoozing) {
-                enableBatterySaverLocked(/*enable=*/ true, /*manual=*/ false,
-                        BatterySaverController.REASON_DYNAMIC_POWER_SAVINGS_AUTOMATIC_ON,
-                        "Dynamic Warning Auto ON");
+
+            case STATE_OFF_AUTOMATIC_SNOOZED: {
+                if (manual) {
+                    if (!enable) {
+                        Slog.e(TAG, "Tried to disable BS when it's already AUTO_SNOOZED");
+                        return;
+                    }
+                    enableBatterySaverLocked(/*enable*/ true, /*manual*/ true,
+                            BatterySaverController.REASON_MANUAL_ON);
+                    mState = STATE_MANUAL_ON;
+                } else if (mIsPowered // Plugging in resets snooze.
+                        || (isAutomaticModeActiveLocked() && !isInAutomaticLowZoneLocked())
+                        || (isDynamicModeActiveLocked() && !isInDynamicLowZoneLocked())
+                        || (!isAutomaticModeActiveLocked() && !isDynamicModeActiveLocked())) {
+                    mState = STATE_OFF;
+                }
+                break;
             }
+
+            case STATE_PENDING_STICKY_ON: {
+                if (manual) {
+                    // This shouldn't be possible. We'll only be in this state when the device is
+                    // plugged in, so the user shouldn't be able to manually change state.
+                    Slog.e(TAG, "Tried to manually change BS state from PENDING_STICKY_ON");
+                    return;
+                }
+                final boolean shouldTurnOffSticky = mSettingBatterySaverStickyAutoDisableEnabled
+                        && mBatteryLevel >= mSettingBatterySaverStickyAutoDisableThreshold;
+                final boolean isStickyDisabled =
+                        mBatterySaverStickyBehaviourDisabled || !mSettingBatterySaverEnabledSticky;
+                if (isStickyDisabled || shouldTurnOffSticky) {
+                    setStickyActive(false);
+                    triggerStickyDisabledNotification();
+                    mState = STATE_OFF;
+                } else if (!mIsPowered) {
+                    // Re-enable BS.
+                    enableBatterySaverLocked(/*enable*/ true, /*manual*/ true,
+                            BatterySaverController.REASON_STICKY_RESTORE);
+                    mState = STATE_MANUAL_ON;
+                }
+                break;
+            }
+
+            default:
+                Slog.wtf(TAG, "Unknown state: " + mState);
+                break;
         }
-        // do nothing if automatic battery saver mode = PERCENTAGE and low warning threshold = 0%
+    }
+
+    @VisibleForTesting
+    int getState() {
+        synchronized (mLock) {
+            return mState;
+        }
     }
 
     /**
@@ -533,13 +724,17 @@
             Slog.d(TAG, "setBatterySaverEnabledManually: enabled=" + enabled);
         }
         synchronized (mLock) {
-            enableBatterySaverLocked(/*enable=*/ enabled, /*manual=*/ true,
-                    (enabled ? BatterySaverController.REASON_MANUAL_ON
-                            : BatterySaverController.REASON_MANUAL_OFF),
-                    (enabled ? "Manual ON" : "Manual OFF"));
+            updateStateLocked(true, enabled);
+            // TODO: maybe turn off adaptive if it's on and advertiseIsEnabled is true and
+            //  enabled is false
         }
     }
 
+    @GuardedBy("mLock")
+    private void enableBatterySaverLocked(boolean enable, boolean manual, int intReason) {
+        enableBatterySaverLocked(enable, manual, intReason, reasonToString(intReason));
+    }
+
     /**
      * Actually enable / disable battery saver. Write the new state to the global settings
      * and propagate it to {@link #mBatterySaverController}.
@@ -566,20 +761,6 @@
         mLastChangedIntReason = intReason;
         mLastChangedStrReason = strReason;
 
-        if (manual) {
-            if (enable) {
-                updateSnoozingLocked(false, "Manual snooze OFF");
-            } else {
-                // When battery saver is disabled manually (while battery saver is enabled)
-                // when the battery level is low, we "snooze" BS -- i.e. disable auto battery saver.
-                // We resume auto-BS once the battery level is not low, or the device is plugged in.
-                if (mBatterySaverController.isFullEnabled() && isBatteryLowLocked()) {
-                    updateSnoozingLocked(true, "Manual snooze");
-                }
-                // TODO: maybe turn off adaptive if it's on and advertiseIsEnabled is true
-            }
-        }
-
         mSettingBatterySaverEnabled = enable;
         putGlobalSetting(Settings.Global.LOW_POWER_MODE, enable ? 1 : 0);
 
@@ -605,49 +786,66 @@
     @VisibleForTesting
     void triggerDynamicModeNotification() {
         NotificationManager manager = mContext.getSystemService(NotificationManager.class);
-        ensureNotificationChannelExists(manager);
+        ensureNotificationChannelExists(manager, DYNAMIC_MODE_NOTIF_CHANNEL_ID,
+                R.string.dynamic_mode_notification_channel_name);
 
-        manager.notify(DYNAMIC_MODE_NOTIFICATION_ID, buildNotification());
+        manager.notify(DYNAMIC_MODE_NOTIFICATION_ID,
+                buildNotification(DYNAMIC_MODE_NOTIF_CHANNEL_ID,
+                        R.string.dynamic_mode_notification_title,
+                        R.string.dynamic_mode_notification_summary,
+                        Intent.ACTION_POWER_USAGE_SUMMARY));
     }
 
-    private void ensureNotificationChannelExists(NotificationManager manager) {
+    private void triggerStickyDisabledNotification() {
+        NotificationManager manager = mContext.getSystemService(NotificationManager.class);
+        ensureNotificationChannelExists(manager, BATTERY_SAVER_NOTIF_CHANNEL_ID,
+                R.string.battery_saver_notification_channel_name);
+
+        manager.notify(STICKY_AUTO_DISABLED_NOTIFICATION_ID,
+                buildNotification(BATTERY_SAVER_NOTIF_CHANNEL_ID,
+                        R.string.battery_saver_sticky_disabled_notification_title,
+                        R.string.battery_saver_sticky_disabled_notification_summary,
+                        Settings.ACTION_BATTERY_SAVER_SETTINGS));
+    }
+
+    private void ensureNotificationChannelExists(NotificationManager manager,
+            @NonNull String channelId, @StringRes int nameId) {
         NotificationChannel channel = new NotificationChannel(
-                DYNAMIC_MODE_NOTIF_CHANNEL_ID,
-                mContext.getText(
-                        R.string.dynamic_mode_notification_channel_name),
-                NotificationManager.IMPORTANCE_DEFAULT);
+                channelId, mContext.getText(nameId), NotificationManager.IMPORTANCE_DEFAULT);
         channel.setSound(null, null);
         manager.createNotificationChannel(channel);
     }
 
-    private Notification buildNotification() {
+    private Notification buildNotification(@NonNull String channelId, @StringRes int titleId,
+            @StringRes int summaryId, @NonNull String intentAction) {
         Resources res = mContext.getResources();
-        Intent intent = new Intent(Intent.ACTION_POWER_USAGE_SUMMARY);
+        Intent intent = new Intent(intentAction);
         intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
         PendingIntent batterySaverIntent = PendingIntent.getActivity(
                 mContext, 0 /* requestCode */, intent, PendingIntent.FLAG_UPDATE_CURRENT);
+        final String summary = res.getString(summaryId);
 
-        return new Notification.Builder(mContext, DYNAMIC_MODE_NOTIF_CHANNEL_ID)
+        return new Notification.Builder(mContext, channelId)
                 .setSmallIcon(R.drawable.ic_battery)
-                .setContentTitle(res.getString(R.string.dynamic_mode_notification_title))
-                .setContentText(res.getString(R.string.dynamic_mode_notification_summary))
+                .setContentTitle(res.getString(titleId))
+                .setContentText(summary)
                 .setContentIntent(batterySaverIntent)
+                .setStyle(new Notification.BigTextStyle().bigText(summary))
                 .setOnlyAlertOnce(true)
                 .build();
     }
 
     private void hideDynamicModeNotification() {
-        NotificationManager manager = mContext.getSystemService(NotificationManager.class);
-        manager.cancel(DYNAMIC_MODE_NOTIFICATION_ID);
+        hideNotification(DYNAMIC_MODE_NOTIFICATION_ID);
     }
 
-    @GuardedBy("mLock")
-    private void updateSnoozingLocked(boolean snoozing, String reason) {
-        if (mBatterySaverSnoozing == snoozing) {
-            return;
-        }
-        if (DEBUG) Slog.d(TAG, "Snooze: " + (snoozing ? "start" : "stop")  + " reason=" + reason);
-        mBatterySaverSnoozing = snoozing;
+    private void hideStickyDisabledNotification() {
+        hideNotification(STICKY_AUTO_DISABLED_NOTIFICATION_ID);
+    }
+
+    private void hideNotification(int notificationId) {
+        NotificationManager manager = mContext.getSystemService(NotificationManager.class);
+        manager.cancel(notificationId);
     }
 
     private void setStickyActive(boolean active) {
@@ -684,6 +882,8 @@
                 pw.print(")");
             }
             pw.println();
+            pw.print("  mState=");
+            pw.println(mState);
 
             pw.print("  mLastChangedIntReason=");
             pw.println(mLastChangedIntReason);
@@ -697,9 +897,6 @@
             pw.print("  mBatteryStatusSet=");
             pw.println(mBatteryStatusSet);
 
-            pw.print("  mBatterySaverSnoozing=");
-            pw.println(mBatterySaverSnoozing);
-
             pw.print("  mIsPowered=");
             pw.println(mIsPowered);
             pw.print("  mBatteryLevel=");
@@ -731,6 +928,7 @@
 
             proto.write(BatterySaverStateMachineProto.ENABLED,
                     mBatterySaverController.isEnabled());
+            proto.write(BatterySaverStateMachineProto.STATE, mState);
             proto.write(BatterySaverStateMachineProto.IS_FULL_ENABLED,
                     mBatterySaverController.isFullEnabled());
             proto.write(BatterySaverStateMachineProto.IS_ADAPTIVE_ENABLED,
@@ -742,8 +940,6 @@
             proto.write(BatterySaverStateMachineProto.SETTINGS_LOADED, mSettingsLoaded);
             proto.write(BatterySaverStateMachineProto.BATTERY_STATUS_SET, mBatteryStatusSet);
 
-            proto.write(BatterySaverStateMachineProto.BATTERY_SAVER_SNOOZING,
-                    mBatterySaverSnoozing);
 
             proto.write(BatterySaverStateMachineProto.IS_POWERED, mIsPowered);
             proto.write(BatterySaverStateMachineProto.BATTERY_LEVEL, mBatteryLevel);
diff --git a/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java b/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
index 83d18a6..d632749 100644
--- a/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
+++ b/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
@@ -16,6 +16,7 @@
 
 package com.android.server.rollback;
 
+import android.Manifest;
 import android.annotation.NonNull;
 import android.app.AppOpsManager;
 import android.content.BroadcastReceiver;
@@ -24,6 +25,7 @@
 import android.content.IntentFilter;
 import android.content.IntentSender;
 import android.content.pm.ApplicationInfo;
+import android.content.pm.ModuleInfo;
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageInstaller;
 import android.content.pm.PackageManager;
@@ -42,6 +44,7 @@
 import android.os.ParcelFileDescriptor;
 import android.os.Process;
 import android.os.SystemClock;
+import android.os.UserHandle;
 import android.provider.DeviceConfig;
 import android.util.IntArray;
 import android.util.Log;
@@ -220,9 +223,7 @@
 
     @Override
     public ParceledListSlice getAvailableRollbacks() {
-        mContext.enforceCallingOrSelfPermission(
-                android.Manifest.permission.MANAGE_ROLLBACKS,
-                "getAvailableRollbacks");
+        enforceManageRollbacks("getAvailableRollbacks");
 
         synchronized (mLock) {
             ensureRollbackDataLoadedLocked();
@@ -239,9 +240,7 @@
 
     @Override
     public ParceledListSlice<RollbackInfo> getRecentlyExecutedRollbacks() {
-        mContext.enforceCallingOrSelfPermission(
-                android.Manifest.permission.MANAGE_ROLLBACKS,
-                "getRecentlyExecutedRollbacks");
+        enforceManageRollbacks("getRecentlyCommittedRollbacks");
 
         synchronized (mLock) {
             ensureRollbackDataLoadedLocked();
@@ -259,9 +258,7 @@
     @Override
     public void commitRollback(int rollbackId, ParceledListSlice causePackages,
             String callerPackageName, IntentSender statusReceiver) {
-        mContext.enforceCallingOrSelfPermission(
-                android.Manifest.permission.MANAGE_ROLLBACKS,
-                "executeRollback");
+        enforceManageRollbacks("executeRollback");
 
         final int callingUid = Binder.getCallingUid();
         AppOpsManager appOps = mContext.getSystemService(AppOpsManager.class);
@@ -459,11 +456,8 @@
 
                             Intent broadcast = new Intent(Intent.ACTION_ROLLBACK_COMMITTED);
 
-                            // TODO: This call emits the warning "Calling a method in the
-                            // system process without a qualified user". Fix that.
-                            // TODO: Limit this to receivers holding the
-                            // MANAGE_ROLLBACKS permission?
-                            mContext.sendBroadcast(broadcast);
+                            mContext.sendBroadcastAsUser(broadcast, UserHandle.SYSTEM,
+                                    Manifest.permission.MANAGE_ROLLBACKS);
                         });
                     }
             );
@@ -484,7 +478,7 @@
     @Override
     public void reloadPersistedData() {
         mContext.enforceCallingOrSelfPermission(
-                android.Manifest.permission.MANAGE_ROLLBACKS,
+                Manifest.permission.TEST_MANAGE_ROLLBACKS,
                 "reloadPersistedData");
 
         synchronized (mLock) {
@@ -499,7 +493,7 @@
     @Override
     public void expireRollbackForPackage(String packageName) {
         mContext.enforceCallingOrSelfPermission(
-                android.Manifest.permission.MANAGE_ROLLBACKS,
+                Manifest.permission.TEST_MANAGE_ROLLBACKS,
                 "expireRollbackForPackage");
         synchronized (mLock) {
             ensureRollbackDataLoadedLocked();
@@ -535,8 +529,8 @@
 
     private void updateRollbackLifetimeDurationInMillis() {
         mRollbackLifetimeDurationInMillis = DeviceConfig.getLong(
-                DeviceConfig.Rollback.BOOT_NAMESPACE,
-                DeviceConfig.Rollback.ROLLBACK_LIFETIME_IN_MILLIS,
+                DeviceConfig.NAMESPACE_ROLLBACK_BOOT,
+                RollbackManager.PROPERTY_ROLLBACK_LIFETIME_MILLIS,
                 DEFAULT_ROLLBACK_LIFETIME_DURATION_MILLIS);
         if (mRollbackLifetimeDurationInMillis < 0) {
             mRollbackLifetimeDurationInMillis = DEFAULT_ROLLBACK_LIFETIME_DURATION_MILLIS;
@@ -894,12 +888,19 @@
         Log.i(TAG, "Enabling rollback for install of " + packageName
                 + ", session:" + session.sessionId);
 
+        String installerPackageName = session.getInstallerPackageName();
+        if (!enableRollbackAllowed(installerPackageName, packageName)) {
+            Log.e(TAG, "Installer " + installerPackageName
+                    + " is not allowed to enable rollback on " + packageName);
+            return false;
+        }
+
         VersionedPackage newVersion = new VersionedPackage(packageName, newPackage.versionCode);
         final boolean isApex = ((installFlags & PackageManager.INSTALL_APEX) != 0);
 
         // Get information about the currently installed package.
         PackageManager pm = mContext.getPackageManager();
-        PackageInfo pkgInfo = null;
+        final PackageInfo pkgInfo;
         try {
             pkgInfo = pm.getPackageInfo(packageName, isApex ? PackageManager.MATCH_APEX : 0);
         } catch (PackageManager.NameNotFoundException e) {
@@ -1086,6 +1087,44 @@
     }
 
     /**
+     * Returns true if the installer is allowed to enable rollback for the
+     * given named package, false otherwise.
+     */
+    private boolean enableRollbackAllowed(String installerPackageName, String packageName) {
+        if (installerPackageName == null) {
+            return false;
+        }
+
+        PackageManager pm = mContext.getPackageManager();
+        boolean manageRollbacksGranted = pm.checkPermission(
+                Manifest.permission.MANAGE_ROLLBACKS,
+                installerPackageName) == PackageManager.PERMISSION_GRANTED;
+
+        boolean testManageRollbacksGranted = pm.checkPermission(
+                Manifest.permission.TEST_MANAGE_ROLLBACKS,
+                installerPackageName) == PackageManager.PERMISSION_GRANTED;
+
+        // For now only allow rollbacks for modules or for testing.
+        return (isModule(packageName) && manageRollbacksGranted)
+            || testManageRollbacksGranted;
+    }
+
+    /**
+     * Returns true if the package name is the name of a module.
+     */
+    private boolean isModule(String packageName) {
+        PackageManager pm = mContext.getPackageManager();
+        final ModuleInfo moduleInfo;
+        try {
+            moduleInfo = pm.getModuleInfo(packageName, 0);
+        } catch (PackageManager.NameNotFoundException e) {
+            return false;
+        }
+
+        return moduleInfo != null;
+    }
+
+    /**
      * Gets the version of the package currently installed.
      * Returns null if the package is not currently installed.
      */
@@ -1311,4 +1350,15 @@
             }
         }
     }
+
+    private void enforceManageRollbacks(@NonNull String message) {
+        if ((PackageManager.PERMISSION_GRANTED != mContext.checkCallingOrSelfPermission(
+                        Manifest.permission.MANAGE_ROLLBACKS))
+                && (PackageManager.PERMISSION_GRANTED != mContext.checkCallingOrSelfPermission(
+                        Manifest.permission.TEST_MANAGE_ROLLBACKS))) {
+            throw new SecurityException(message + " requires "
+                    + Manifest.permission.MANAGE_ROLLBACKS + " or "
+                    + Manifest.permission.TEST_MANAGE_ROLLBACKS);
+        }
+    }
 }
diff --git a/services/core/java/com/android/server/stats/StatsCompanionService.java b/services/core/java/com/android/server/stats/StatsCompanionService.java
index 2b17d19..1800433 100644
--- a/services/core/java/com/android/server/stats/StatsCompanionService.java
+++ b/services/core/java/com/android/server/stats/StatsCompanionService.java
@@ -19,6 +19,8 @@
 import static android.content.pm.PermissionInfo.PROTECTION_DANGEROUS;
 import static android.os.Process.getPidsForCommands;
 import static android.os.Process.getUidForPid;
+import static android.os.storage.VolumeInfo.TYPE_PRIVATE;
+import static android.os.storage.VolumeInfo.TYPE_PUBLIC;
 
 import static com.android.internal.util.Preconditions.checkNotNull;
 import static com.android.server.am.MemoryStatUtil.readCmdlineFromProcfs;
@@ -89,6 +91,7 @@
 import android.os.storage.DiskInfo;
 import android.os.storage.StorageManager;
 import android.os.storage.VolumeInfo;
+import android.stats.storage.StorageEnums;
 import android.telephony.ModemActivityInfo;
 import android.telephony.TelephonyManager;
 import android.util.ArrayMap;
@@ -1968,7 +1971,7 @@
         pulledData.add(e);
     }
 
-    private void pullSDCardInfo(int tagId, long elapsedNanos, long wallClockNanos,
+    private void pullExternalStorageInfo(int tagId, long elapsedNanos, long wallClockNanos,
             List<StatsLogEventWrapper> pulledData) {
         StorageManager storageManager = mContext.getSystemService(StorageManager.class);
         if (storageManager != null) {
@@ -1976,11 +1979,29 @@
             for (VolumeInfo vol : volumes) {
                 final String envState = VolumeInfo.getEnvironmentForState(vol.getState());
                 final DiskInfo diskInfo = vol.getDisk();
-                if (diskInfo != null && diskInfo.isSd()) {
+                if (diskInfo != null) {
                     if (envState.equals(Environment.MEDIA_MOUNTED)) {
+                        // Get the type of the volume, if it is adoptable or portable.
+                        int volumeType = StatsLog.EXTERNAL_STORAGE_INFO__VOLUME_TYPE__OTHER;
+                        if (vol.getType() == TYPE_PUBLIC) {
+                            volumeType = StatsLog.EXTERNAL_STORAGE_INFO__VOLUME_TYPE__PUBLIC;
+                        } else if (vol.getType() == TYPE_PRIVATE) {
+                            volumeType = StatsLog.EXTERNAL_STORAGE_INFO__VOLUME_TYPE__PRIVATE;
+                        }
+                        // Get the type of external storage inserted in the device (sd cards,
+                        // usb, etc)
+                        int externalStorageType;
+                        if (diskInfo.isSd()) {
+                            externalStorageType = StorageEnums.SD_CARD;
+                        } else if (diskInfo.isUsb()) {
+                            externalStorageType = StorageEnums.USB;
+                        } else {
+                            externalStorageType = StorageEnums.OTHER;
+                        }
                         StatsLogEventWrapper e =
                                 new StatsLogEventWrapper(tagId, elapsedNanos, wallClockNanos);
-                        e.writeInt(vol.getType() + 1);
+                        e.writeInt(externalStorageType);
+                        e.writeInt(volumeType);
                         e.writeLong(diskInfo.size);
                         pulledData.add(e);
                     }
@@ -2185,8 +2206,8 @@
                 pullTimeZoneDataInfo(tagId, elapsedNanos, wallClockNanos, ret);
                 break;
             }
-            case StatsLog.SDCARD_INFO: {
-                pullSDCardInfo(tagId, elapsedNanos, wallClockNanos, ret);
+            case StatsLog.EXTERNAL_STORAGE_INFO: {
+                pullExternalStorageInfo(tagId, elapsedNanos, wallClockNanos, ret);
                 break;
             }
             default:
diff --git a/services/core/java/com/android/server/wm/ActivityDisplay.java b/services/core/java/com/android/server/wm/ActivityDisplay.java
index a33b454d..9d6efb4 100644
--- a/services/core/java/com/android/server/wm/ActivityDisplay.java
+++ b/services/core/java/com/android/server/wm/ActivityDisplay.java
@@ -1173,7 +1173,17 @@
     }
 
     private void releaseSelfIfNeeded() {
-        if (mStacks.isEmpty() && mRemoved) {
+        if (!mRemoved || mDisplayContent == null) {
+            return;
+        }
+
+        final ActivityStack stack = mStacks.size() == 1 ? mStacks.get(0) : null;
+        if (stack != null && stack.isActivityTypeHome() && stack.getAllTasks().isEmpty()) {
+            // Release this display if an empty home stack is the only thing left.
+            // Since it is the last stack, this display will be released along with the stack
+            // removal.
+            stack.remove();
+        } else if (mStacks.isEmpty()) {
             mDisplayContent.removeIfPossible();
             mDisplayContent = null;
             mRootActivityContainer.removeChild(this);
diff --git a/services/core/java/com/android/server/wm/ActivityStack.java b/services/core/java/com/android/server/wm/ActivityStack.java
index ad98970..4c9b80b 100644
--- a/services/core/java/com/android/server/wm/ActivityStack.java
+++ b/services/core/java/com/android/server/wm/ActivityStack.java
@@ -3053,7 +3053,17 @@
         ActivityOptions.abort(options);
         if (DEBUG_STATES) Slog.d(TAG_STATES,
                 "resumeTopActivityInNextFocusableStack: " + reason + ", go home");
-        return mRootActivityContainer.resumeHomeActivity(prev, reason, mDisplayId);
+        if (isActivityTypeHome()) {
+            // resumeTopActivityUncheckedLocked has been prevented to run recursively. Post a
+            // runnable to resume home since we are currently in the process of resuming top
+            // activity in home stack.
+            // See {@link #mInResumeTopActivity}.
+            mService.mH.post(
+                    () -> mRootActivityContainer.resumeHomeActivity(prev, reason, mDisplayId));
+            return true;
+        } else {
+            return mRootActivityContainer.resumeHomeActivity(prev, reason, mDisplayId);
+        }
     }
 
     /** Returns the position the input task should be placed in this stack. */
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
index 5a20959..b262a00 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
@@ -352,6 +352,19 @@
     /** @return The intent used to launch the home activity. */
     public abstract Intent getHomeIntent();
     public abstract boolean startHomeActivity(int userId, String reason);
+    /**
+     * This starts home activity on displays that can have system decorations based on displayId -
+     * Default display always use primary home component.
+     * For Secondary displays, the home activity must have category SECONDARY_HOME and then resolves
+     * according to the priorities listed below.
+     *  - If default home is not set, always use the secondary home defined in the config.
+     *  - Use currently selected primary home activity.
+     *  - Use the activity in the same package as currently selected primary home activity.
+     *    If there are multiple activities matched, use first one.
+     *  - Use the secondary home defined in the config.
+     */
+    public abstract boolean startHomeOnDisplay(int userId, String reason, int displayId,
+            boolean fromHomeKey);
     /** Start home activities on all displays that support system decorations. */
     public abstract boolean startHomeOnAllDisplays(int userId, String reason);
     /** @return true if the given process is the factory test process. */
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index a1dbbab..c91ee8e 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -6491,6 +6491,15 @@
         }
 
         @Override
+        public boolean startHomeOnDisplay(int userId, String reason, int displayId,
+                boolean fromHomeKey) {
+            synchronized (mGlobalLock) {
+                return mRootActivityContainer.startHomeOnDisplay(userId, reason, displayId,
+                        fromHomeKey);
+            }
+        }
+
+        @Override
         public boolean startHomeOnAllDisplays(int userId, String reason) {
             synchronized (mGlobalLock) {
                 return mRootActivityContainer.startHomeOnAllDisplays(userId, reason);
diff --git a/services/core/java/com/android/server/wm/AppTransition.java b/services/core/java/com/android/server/wm/AppTransition.java
index af05a27..e053ff3 100644
--- a/services/core/java/com/android/server/wm/AppTransition.java
+++ b/services/core/java/com/android/server/wm/AppTransition.java
@@ -484,6 +484,10 @@
         mListeners.add(listener);
     }
 
+    void unregisterListener(AppTransitionListener listener) {
+        mListeners.remove(listener);
+    }
+
     public void notifyAppTransitionFinishedLocked(IBinder token) {
         for (int i = 0; i < mListeners.size(); i++) {
             mListeners.get(i).onAppTransitionFinishedLocked(token);
diff --git a/services/core/java/com/android/server/wm/AppTransitionController.java b/services/core/java/com/android/server/wm/AppTransitionController.java
index f6326957..75e34fb 100644
--- a/services/core/java/com/android/server/wm/AppTransitionController.java
+++ b/services/core/java/com/android/server/wm/AppTransitionController.java
@@ -19,6 +19,7 @@
 import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
 import static android.view.WindowManager.TRANSIT_ACTIVITY_CLOSE;
 import static android.view.WindowManager.TRANSIT_ACTIVITY_OPEN;
+import static android.view.WindowManager.TRANSIT_ACTIVITY_RELAUNCH;
 import static android.view.WindowManager.TRANSIT_CRASHING_ACTIVITY_CLOSE;
 import static android.view.WindowManager.TRANSIT_DOCK_TASK_FROM_RECENTS;
 import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_NO_ANIMATION;
@@ -638,6 +639,39 @@
         return transit;
     }
 
+    /**
+     * Identifies whether the current transition occurs within a single task or not. This is used
+     * to determine whether animations should be clipped to the task bounds instead of stack bounds.
+     */
+    @VisibleForTesting
+    boolean isTransitWithinTask(int transit, Task task) {
+        if (task == null
+                || !mDisplayContent.mChangingApps.isEmpty()) {
+            // if there is no task, then we can't constrain to the task.
+            // if anything is changing, it can animate outside its task.
+            return false;
+        }
+        if (!(transit == TRANSIT_ACTIVITY_OPEN
+                || transit == TRANSIT_ACTIVITY_CLOSE
+                || transit == TRANSIT_ACTIVITY_RELAUNCH)) {
+            // only activity-level transitions will be within-task.
+            return false;
+        }
+        // check that all components are in the task.
+        for (AppWindowToken activity : mDisplayContent.mOpeningApps) {
+            Task activityTask = activity.getTask();
+            if (activityTask != task) {
+                return false;
+            }
+        }
+        for (AppWindowToken activity : mDisplayContent.mClosingApps) {
+            if (activity.getTask() != task) {
+                return false;
+            }
+        }
+        return true;
+    }
+
     private boolean canBeWallpaperTarget(ArraySet<AppWindowToken> apps) {
         for (int i = apps.size() - 1; i >= 0; i--) {
             if (apps.valueAt(i).windowsCanBeWallpaperTarget()) {
diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java
index ea3a7d5..955f2e9 100644
--- a/services/core/java/com/android/server/wm/AppWindowToken.java
+++ b/services/core/java/com/android/server/wm/AppWindowToken.java
@@ -666,7 +666,7 @@
             }
         }
 
-        if (isReallyAnimating()) {
+        if (isSelfAnimating()) {
             delayed = true;
         } else {
 
@@ -2436,6 +2436,12 @@
                 getWindowingMode() == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
         final boolean allowSplitScreenPrimaryAnimation = transit != TRANSIT_WALLPAPER_OPEN;
 
+        // Don't animate when the task runs recents animation.
+        final RecentsAnimationController controller = mWmService.getRecentsAnimationController();
+        if (controller != null && controller.isAnimatingTask(getTask())) {
+            return false;
+        }
+
         // We animate always if it's not split screen primary, and only some special cases in split
         // screen primary because it causes issues with stack clipping when we run an un-minimize
         // animation at the same time.
@@ -2705,16 +2711,21 @@
         // If the animation needs to be cropped then an animation bounds layer is created as a child
         // of the pinned stack or animation layer. The leash is then reparented to this new layer.
         if (mNeedsAnimationBoundsLayer) {
-            final TaskStack stack = getStack();
-            if (stack == null) {
-                return;
+            mTmpRect.setEmpty();
+            final Task task = getTask();
+            if (getDisplayContent().mAppTransitionController.isTransitWithinTask(
+                    getTransit(), task)) {
+                task.getBounds(mTmpRect);
+            } else {
+                final TaskStack stack = getStack();
+                if (stack == null) {
+                    return;
+                }
+                // Set clip rect to stack bounds.
+                stack.getBounds(mTmpRect);
             }
             mAnimationBoundsLayer = createAnimationBoundsLayer(t);
 
-            // Set clip rect to stack bounds.
-            mTmpRect.setEmpty();
-            stack.getBounds(mTmpRect);
-
             // Crop to stack bounds.
             t.setWindowCrop(mAnimationBoundsLayer, mTmpRect);
 
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index bcfbefe..bec72f5 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -130,6 +130,7 @@
 import static com.android.server.wm.WindowState.RESIZE_HANDLE_WIDTH_IN_DP;
 import static com.android.server.wm.WindowStateAnimator.DRAW_PENDING;
 import static com.android.server.wm.WindowStateAnimator.READY_TO_SHOW;
+import static com.android.server.wm.utils.RegionUtils.rectListToRegion;
 
 import android.animation.AnimationHandler;
 import android.annotation.CallSuper;
@@ -153,6 +154,7 @@
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.Process;
+import android.os.RemoteCallbackList;
 import android.os.RemoteException;
 import android.os.SystemClock;
 import android.os.Trace;
@@ -165,6 +167,7 @@
 import android.view.DisplayCutout;
 import android.view.DisplayInfo;
 import android.view.Gravity;
+import android.view.ISystemGestureExclusionListener;
 import android.view.InputChannel;
 import android.view.InputDevice;
 import android.view.InputWindowHandle;
@@ -312,6 +315,10 @@
     private DisplayRotation mDisplayRotation;
     DisplayFrames mDisplayFrames;
 
+    private final RemoteCallbackList<ISystemGestureExclusionListener>
+            mSystemGestureExclusionListeners = new RemoteCallbackList<>();
+    private final Region mSystemGestureExclusion = new Region();
+
     /**
      * For default display it contains real metrics, empty for others.
      * @see WindowManagerService#createWatermarkInTransaction()
@@ -2818,6 +2825,14 @@
         mWallpaperController.dump(pw, "  ");
 
         pw.println();
+        pw.print("mSystemGestureExclusion=");
+        if (mSystemGestureExclusionListeners.getRegisteredCallbackCount() > 0) {
+            pw.println(mSystemGestureExclusion);
+        } else {
+            pw.println("<no lstnrs>");
+        }
+
+        pw.println();
         pw.println(prefix + "Application tokens in top down Z order:");
         for (int stackNdx = mTaskStackContainers.getChildCount() - 1; stackNdx >= 0; --stackNdx) {
             final TaskStack stack = mTaskStackContainers.getChildAt(stackNdx);
@@ -3284,7 +3299,11 @@
     }
 
     private void updateImeParent() {
-        final SurfaceControl newParent = computeImeParent();
+        // Force attaching IME to the display when magnifying, or it would be magnified with
+        // target app together.
+        final boolean shouldAttachToDisplay = (mMagnificationSpec != null);
+        final SurfaceControl newParent =
+                shouldAttachToDisplay ? mWindowingLayer : computeImeParent();
         if (newParent != null) {
             mPendingTransaction.reparent(mImeWindowsContainers.mSurfaceControl, newParent);
             scheduleAnimation();
@@ -4699,6 +4718,8 @@
         } else {
             mMagnificationSpec = null;
         }
+        // Re-parent IME's SurfaceControl when MagnificationSpec changed.
+        updateImeParent();
 
         applyMagnificationSpec(getPendingTransaction(), spec);
         getPendingTransaction().apply();
@@ -4945,6 +4966,100 @@
     }
 
     /**
+     * Updates the display's system gesture exclusion.
+     *
+     * @return true, if the exclusion changed.
+     */
+    boolean updateSystemGestureExclusion() {
+        if (mSystemGestureExclusionListeners.getRegisteredCallbackCount() == 0) {
+            // No one's interested anyways.
+            return false;
+        }
+
+        final Region systemGestureExclusion = calculateSystemGestureExclusion();
+        try {
+            if (mSystemGestureExclusion.equals(systemGestureExclusion)) {
+                return false;
+            }
+            mSystemGestureExclusion.set(systemGestureExclusion);
+            for (int i = mSystemGestureExclusionListeners.beginBroadcast() - 1; i >= 0; --i) {
+                try {
+                    mSystemGestureExclusionListeners.getBroadcastItem(i)
+                            .onSystemGestureExclusionChanged(mDisplayId, systemGestureExclusion);
+                } catch (RemoteException e) {
+                    Slog.e(TAG, "Failed to notify SystemGestureExclusionListener", e);
+                }
+            }
+            mSystemGestureExclusionListeners.finishBroadcast();
+            return true;
+        } finally {
+            systemGestureExclusion.recycle();
+        }
+    }
+
+    @VisibleForTesting
+    Region calculateSystemGestureExclusion() {
+        final Region global = Region.obtain();
+        final Region touchableRegion = Region.obtain();
+        final Region local = Region.obtain();
+
+        // Traverse all windows bottom up to assemble the gesture exclusion rects.
+        // For each window, we only take the rects that fall within its touchable region.
+        forAllWindows(w -> {
+            if (w.cantReceiveTouchInput() || !w.isVisible()
+                    || (w.getAttrs().flags & FLAG_NOT_TOUCHABLE) != 0) {
+                return;
+            }
+            final boolean modal =
+                    (w.mAttrs.flags & (FLAG_NOT_TOUCH_MODAL | FLAG_NOT_FOCUSABLE)) == 0;
+
+            // Only keep the exclusion zones from the windows behind where the current window
+            // isn't touchable.
+            w.getTouchableRegion(touchableRegion);
+            global.op(touchableRegion, Op.DIFFERENCE);
+
+            rectListToRegion(w.getSystemGestureExclusion(), local);
+
+            // Transform to display coordinates
+            local.scale(w.mGlobalScale);
+            final Rect frame = w.getWindowFrames().mFrame;
+            local.translate(frame.left, frame.top);
+
+            // A window can only exclude system gestures where it is actually touchable
+            local.op(touchableRegion, Op.INTERSECT);
+
+            global.op(local, Op.UNION);
+        }, false /* topToBottom */);
+        local.recycle();
+        touchableRegion.recycle();
+        return global;
+    }
+
+    void registerSystemGestureExclusionListener(ISystemGestureExclusionListener listener) {
+        mSystemGestureExclusionListeners.register(listener);
+        final boolean changed;
+        if (mSystemGestureExclusionListeners.getRegisteredCallbackCount() == 1) {
+            changed = updateSystemGestureExclusion();
+        } else {
+            changed = false;
+        }
+
+        if (!changed) {
+            // If updateSystemGestureExclusion changed the exclusion, it will already have
+            // notified the listener. Otherwise, we'll do it here.
+            try {
+                listener.onSystemGestureExclusionChanged(mDisplayId, mSystemGestureExclusion);
+            } catch (RemoteException e) {
+                Slog.e(TAG, "Failed to notify SystemGestureExclusionListener during register", e);
+            }
+        }
+    }
+
+    void unregisterSystemGestureExclusionListener(ISystemGestureExclusionListener listener) {
+        mSystemGestureExclusionListeners.unregister(listener);
+    }
+
+    /**
      * Create a portal window handle for input. This window transports any touch to the display
      * indicated by {@link InputWindowHandle#portalToDisplayId} if the touch hits this window.
      *
diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java
index ba1dfbb..ff4e256 100644
--- a/services/core/java/com/android/server/wm/DisplayPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayPolicy.java
@@ -59,7 +59,6 @@
 import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING;
 import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
 import static android.view.WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST;
-import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
 import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
 import static android.view.WindowManager.LayoutParams.TYPE_BOOT_PROGRESS;
 import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER;
@@ -2067,8 +2066,7 @@
                     of.set(displayFrames.mRestricted);
                     df.set(displayFrames.mRestricted);
                     pf.set(displayFrames.mRestricted);
-                } else if (type == TYPE_TOAST || type == TYPE_SYSTEM_ALERT
-                        || type == TYPE_APPLICATION_OVERLAY) {
+                } else if (type == TYPE_TOAST || type == TYPE_SYSTEM_ALERT) {
                     // These dialogs are stable to interim decor changes.
                     cf.set(displayFrames.mStable);
                     of.set(displayFrames.mStable);
diff --git a/services/core/java/com/android/server/wm/KeyguardController.java b/services/core/java/com/android/server/wm/KeyguardController.java
index 8c8b05f..72a1a2f 100644
--- a/services/core/java/com/android/server/wm/KeyguardController.java
+++ b/services/core/java/com/android/server/wm/KeyguardController.java
@@ -269,7 +269,8 @@
      * @return True if we may show an activity while Keyguard is occluded, false otherwise.
      */
     boolean canShowWhileOccluded(boolean dismissKeyguard, boolean showWhenLocked) {
-        return showWhenLocked || dismissKeyguard && !mWindowManager.isKeyguardSecure();
+        return showWhenLocked || dismissKeyguard
+                && !mWindowManager.isKeyguardSecure(mService.getCurrentUserId());
     }
 
     private void visibilitiesUpdated() {
@@ -317,7 +318,7 @@
         // We only allow dismissing Keyguard via the flag when Keyguard is secure for legacy
         // reasons, because that's how apps used to dismiss Keyguard in the secure case. In the
         // insecure case, we actually show it on top of the lockscreen. See #canShowWhileOccluded.
-        if (!mWindowManager.isKeyguardSecure()) {
+        if (!mWindowManager.isKeyguardSecure(mService.getCurrentUserId())) {
             return;
         }
 
@@ -345,7 +346,8 @@
      * @return true if Keyguard can be currently dismissed without entering credentials.
      */
     boolean canDismissKeyguard() {
-        return mWindowManager.isKeyguardTrusted() || !mWindowManager.isKeyguardSecure();
+        return mWindowManager.isKeyguardTrusted()
+                || !mWindowManager.isKeyguardSecure(mService.getCurrentUserId());
     }
 
     private int resolveOccludeTransit() {
@@ -487,7 +489,8 @@
             }
             if (lastDismissActivity != mDismissingKeyguardActivity && !mOccluded
                     && mDismissingKeyguardActivity != null
-                    && controller.mWindowManager.isKeyguardSecure()) {
+                    && controller.mWindowManager.isKeyguardSecure(
+                            controller.mService.getCurrentUserId())) {
                 mRequestDismissKeyguard = true;
             }
         }
diff --git a/services/core/java/com/android/server/wm/LockTaskController.java b/services/core/java/com/android/server/wm/LockTaskController.java
index e6e6275..2411e00 100644
--- a/services/core/java/com/android/server/wm/LockTaskController.java
+++ b/services/core/java/com/android/server/wm/LockTaskController.java
@@ -762,7 +762,7 @@
             } else {
                 // If keyguard is not secure and it is locked, dismiss the keyguard before
                 // disabling it, which avoids the platform to think the keyguard is still on.
-                if (mWindowManager.isKeyguardLocked() && !mWindowManager.isKeyguardSecure()) {
+                if (mWindowManager.isKeyguardLocked() && !mWindowManager.isKeyguardSecure(userId)) {
                     mPendingDisableFromDismiss = userId;
                     mWindowManager.dismissKeyguard(new IKeyguardDismissCallback.Stub() {
                         @Override
diff --git a/services/core/java/com/android/server/wm/RecentsAnimation.java b/services/core/java/com/android/server/wm/RecentsAnimation.java
index cb9cbd6..f1560d9 100644
--- a/services/core/java/com/android/server/wm/RecentsAnimation.java
+++ b/services/core/java/com/android/server/wm/RecentsAnimation.java
@@ -31,6 +31,7 @@
 import static com.android.server.wm.RecentsAnimationController.REORDER_KEEP_IN_PLACE;
 import static com.android.server.wm.RecentsAnimationController.REORDER_MOVE_TO_ORIGINAL_POSITION;
 import static com.android.server.wm.RecentsAnimationController.REORDER_MOVE_TO_TOP;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_RECENTS_ANIMATIONS;
 
 import android.app.ActivityOptions;
 import android.app.AppOpsManager;
@@ -59,7 +60,7 @@
 class RecentsAnimation implements RecentsAnimationCallbacks,
         ActivityDisplay.OnStackOrderChangedListener {
     private static final String TAG = RecentsAnimation.class.getSimpleName();
-    private static final boolean DEBUG = false;
+    private static final boolean DEBUG = DEBUG_RECENTS_ANIMATIONS;
 
     private final ActivityTaskManagerService mService;
     private final ActivityStackSupervisor mStackSupervisor;
@@ -395,11 +396,23 @@
             // The stack is not visible, so ignore this change
             return;
         }
+        final RecentsAnimationController controller =
+                mWindowManager.getRecentsAnimationController();
 
-        // If the activity display stack order changes, cancel any running recents animation in
-        // place
-        mWindowManager.cancelRecentsAnimationSynchronously(REORDER_KEEP_IN_PLACE,
-                "stackOrderChanged");
+        // Cancel running recents animation and screenshot previous task when the next
+        // transition starts in below cases:
+        // 1) The next launching task is not in recents animation task.
+        // 2) The next task is home activity. (i.e. pressing home key to back home in recents).
+        if ((!controller.isAnimatingTask(stack.getTaskStack().getTopChild())
+                || controller.isTargetApp(stack.getTopActivity().mAppWindowToken))
+                && controller.shouldCancelWithDeferredScreenshot()) {
+            controller.cancelOnNextTransitionStart();
+        } else {
+            // Just cancel directly to unleash from launcher when the next launching task is the
+            // current top task.
+            mWindowManager.cancelRecentsAnimationSynchronously(REORDER_KEEP_IN_PLACE,
+                    "stackOrderChanged");
+        }
     }
 
     /**
@@ -407,7 +420,7 @@
      */
     private void notifyAnimationCancelBeforeStart(IRecentsAnimationRunner recentsAnimationRunner) {
         try {
-            recentsAnimationRunner.onAnimationCanceled();
+            recentsAnimationRunner.onAnimationCanceled(false /* deferredWithScreenshot */);
         } catch (RemoteException e) {
             Slog.e(TAG, "Failed to cancel recents animation before start", e);
         }
diff --git a/services/core/java/com/android/server/wm/RecentsAnimationController.java b/services/core/java/com/android/server/wm/RecentsAnimationController.java
index 105ff06..26df832 100644
--- a/services/core/java/com/android/server/wm/RecentsAnimationController.java
+++ b/services/core/java/com/android/server/wm/RecentsAnimationController.java
@@ -29,6 +29,7 @@
 import static com.android.server.wm.AnimationAdapterProto.REMOTE;
 import static com.android.server.wm.RemoteAnimationAdapterWrapperProto.TARGET;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_RECENTS_ANIMATIONS;
+import static com.android.server.wm.WindowManagerInternal.AppTransitionListener;
 
 import android.annotation.IntDef;
 import android.app.ActivityManager.TaskSnapshot;
@@ -92,6 +93,8 @@
     private final Runnable mFailsafeRunnable = () ->
             cancelAnimation(REORDER_MOVE_TO_ORIGINAL_POSITION, "failSafeRunnable");
 
+    final Object mLock = new Object();
+
     // The recents component app token that is shown behind the visibile tasks
     private AppWindowToken mTargetAppToken;
     private int mTargetActivityType;
@@ -117,6 +120,27 @@
 
     private boolean mLinkedToDeathOfRunner;
 
+    private boolean mCancelWithDeferredScreenshot;
+
+    private boolean mCancelOnNextTransitionStart;
+
+    /**
+     * Animates the screenshot of task that used to be controlled by RecentsAnimation.
+     * @see {@link #cancelOnNextTransitionStart}
+     */
+    SurfaceAnimator mRecentScreenshotAnimator;
+
+    final AppTransitionListener mAppTransitionListener = new AppTransitionListener() {
+        @Override
+        public int onAppTransitionStartingLocked(int transit, long duration,
+                long statusBarAnimationStartTime, long statusBarAnimationDuration) {
+            onTransitionStart();
+            mService.mRoot.getDisplayContent(mDisplayId).mAppTransition
+                    .unregisterListener(this);
+            return 0;
+        }
+    };
+
     public interface RecentsAnimationCallbacks {
         void onAnimationFinished(@ReorderMode int reorderMode, boolean runSychronously);
     }
@@ -245,6 +269,23 @@
                 Binder.restoreCallingIdentity(token);
             }
         }
+
+        @Override
+        public void setCancelWithDeferredScreenshot(boolean screenshot) {
+            synchronized (mLock) {
+                setCancelWithDeferredScreenshotLocked(screenshot);
+            }
+        }
+
+        @Override
+        public void cleanupScreenshot() {
+            synchronized (mLock) {
+                if (mRecentScreenshotAnimator != null) {
+                    mRecentScreenshotAnimator.cancelAnimation();
+                    mRecentScreenshotAnimator = null;
+                }
+            }
+        }
     };
 
     /**
@@ -273,6 +314,7 @@
     @VisibleForTesting
     void initialize(DisplayContent dc, int targetActivityType, SparseBooleanArray recentTaskIds) {
         mTargetActivityType = targetActivityType;
+        dc.mAppTransition.registerListenerLocked(mAppTransitionListener);
 
         // Make leashes for each of the visible/target tasks and add it to the recents animation to
         // be started
@@ -416,15 +458,20 @@
     }
 
     void cancelAnimation(@ReorderMode int reorderMode, String reason) {
-        cancelAnimation(reorderMode, false /* runSynchronously */, reason);
+        cancelAnimation(reorderMode, false /* runSynchronously */, false /*screenshot */, reason);
     }
 
     void cancelAnimationSynchronously(@ReorderMode int reorderMode, String reason) {
-        cancelAnimation(reorderMode, true /* runSynchronously */, reason);
+        cancelAnimation(reorderMode, true /* runSynchronously */, false /* screenshot */, reason);
+    }
+
+    void cancelAnimationWithScreenShot() {
+        cancelAnimation(REORDER_KEEP_IN_PLACE, true /* sync */, true /* screenshot */,
+                "stackOrderChanged");
     }
 
     private void cancelAnimation(@ReorderMode int reorderMode, boolean runSynchronously,
-            String reason) {
+            boolean screenshot, String reason) {
         if (DEBUG_RECENTS_ANIMATIONS) Slog.d(TAG, "cancelAnimation(): reason=" + reason
                 + " runSynchronously=" + runSynchronously);
         synchronized (mService.getWindowManagerLock()) {
@@ -435,14 +482,67 @@
             mService.mH.removeCallbacks(mFailsafeRunnable);
             mCanceled = true;
             try {
-                mRunner.onAnimationCanceled();
+                if (screenshot) {
+                    // Screen shot previous task when next task starts transition.
+                    final Task task = mPendingAnimations.get(0).mTask;
+                    screenshotRecentTask(task, reorderMode, runSynchronously);
+                    mRunner.onAnimationCanceled(true /* deferredWithScreenshot */);
+                    return;
+                }
+                mRunner.onAnimationCanceled(false /* deferredWithScreenshot */);
             } catch (RemoteException e) {
                 Slog.e(TAG, "Failed to cancel recents animation", e);
             }
+            // Clean up and return to the previous app
+            mCallbacks.onAnimationFinished(reorderMode, runSynchronously);
+        }
+    }
+
+    /**
+     * Cancel recents animation when the next app transition starts.
+     * <p>
+     * When we cancel the recents animation due to a stack order change, we can't just cancel it
+     * immediately as it would lead to a flicker in Launcher if we just remove the task from the
+     * leash. Instead we screenshot the previous task and replace the child of the leash with the
+     * screenshot, so that Launcher can still control the leash lifecycle & make the next app
+     * transition animate smoothly without flickering.
+     */
+    void cancelOnNextTransitionStart() {
+        mCancelOnNextTransitionStart = true;
+    }
+
+    void setCancelWithDeferredScreenshotLocked(boolean screenshot) {
+        mCancelWithDeferredScreenshot = screenshot;
+    }
+
+    boolean shouldCancelWithDeferredScreenshot() {
+        return mCancelWithDeferredScreenshot;
+    }
+
+    void onTransitionStart() {
+        if (mCanceled) {
+            return;
         }
 
-        // Clean up and return to the previous app
-        mCallbacks.onAnimationFinished(reorderMode, runSynchronously);
+        if (mCancelOnNextTransitionStart) {
+            mCancelOnNextTransitionStart = false;
+            cancelAnimationWithScreenShot();
+        }
+    }
+
+    void screenshotRecentTask(Task task, @ReorderMode int reorderMode, boolean runSynchronously) {
+        final TaskScreenshotAnimatable animatable = TaskScreenshotAnimatable.create(task);
+        if (animatable != null) {
+            mRecentScreenshotAnimator = new SurfaceAnimator(
+                    animatable,
+                    () -> {
+                        if (DEBUG_RECENTS_ANIMATIONS) {
+                            Slog.d(TAG, "mRecentScreenshotAnimator finish");
+                        }
+                        mCallbacks.onAnimationFinished(reorderMode, runSynchronously);
+                    }, mService);
+            mRecentScreenshotAnimator.transferAnimation(task.mSurfaceAnimator);
+        }
     }
 
     void cleanupAnimation(@ReorderMode int reorderMode) {
@@ -465,6 +565,12 @@
         mRunner = null;
         mCanceled = true;
 
+        // Make sure previous animator has cleaned-up.
+        if (mRecentScreenshotAnimator != null) {
+            mRecentScreenshotAnimator.cancelAnimation();
+            mRecentScreenshotAnimator = null;
+        }
+
         // Update the input windows after the animation is complete
         final InputMonitor inputMonitor =
                 mService.mRoot.getDisplayContent(mDisplayId).getInputMonitor();
diff --git a/services/core/java/com/android/server/wm/RootActivityContainer.java b/services/core/java/com/android/server/wm/RootActivityContainer.java
index f964b57..24cf7f1 100644
--- a/services/core/java/com/android/server/wm/RootActivityContainer.java
+++ b/services/core/java/com/android/server/wm/RootActivityContainer.java
@@ -114,6 +114,7 @@
 import com.android.server.am.ActivityManagerService;
 import com.android.server.am.AppTimeTracker;
 import com.android.server.am.UserState;
+import com.android.server.policy.WindowManagerPolicy;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
@@ -345,6 +346,10 @@
         }
     }
 
+    boolean startHomeOnDisplay(int userId, String reason, int displayId) {
+        return startHomeOnDisplay(userId, reason, displayId, false /*fromHomeKey*/);
+    }
+
     /**
      * This starts home activity on displays that can have system decorations based on displayId -
      * Default display always use primary home component.
@@ -356,7 +361,12 @@
      *    If there are multiple activities matched, use first one.
      *  - Use the secondary home defined in the config.
      */
-    boolean startHomeOnDisplay(int userId, String reason, int displayId) {
+    boolean startHomeOnDisplay(int userId, String reason, int displayId, boolean fromHomeKey) {
+        // Fallback to top focused display if the displayId is invalid.
+        if (displayId == INVALID_DISPLAY) {
+            displayId = getTopDisplayFocusedStack().mDisplayId;
+        }
+
         Intent homeIntent;
         ActivityInfo aInfo;
         if (displayId == DEFAULT_DISPLAY) {
@@ -380,6 +390,10 @@
         // Updates the home component of the intent.
         homeIntent.setComponent(new ComponentName(aInfo.applicationInfo.packageName, aInfo.name));
         homeIntent.setFlags(homeIntent.getFlags() | FLAG_ACTIVITY_NEW_TASK);
+        // Updates the extra information of the intent.
+        if (fromHomeKey) {
+            homeIntent.putExtra(WindowManagerPolicy.EXTRA_FROM_HOME_KEY, true);
+        }
         // Update the reason for ANR debugging to verify if the user activity is the one that
         // actually launched.
         final String myReason = reason + ":" + userId + ":" + UserHandle.getUserId(
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index 8f4e842..ed5f665 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -682,6 +682,7 @@
         // Finally update all input windows now that the window changes have stabilized.
         forAllDisplays(dc -> {
             dc.getInputMonitor().updateInputWindowsLw(true /*force*/);
+            dc.updateSystemGestureExclusion();
         });
 
         mWmService.setHoldScreenLocked(mHoldScreen);
diff --git a/services/core/java/com/android/server/wm/Session.java b/services/core/java/com/android/server/wm/Session.java
index dc8c7b7..9b634f9 100644
--- a/services/core/java/com/android/server/wm/Session.java
+++ b/services/core/java/com/android/server/wm/Session.java
@@ -57,6 +57,7 @@
 
 import java.io.PrintWriter;
 import java.util.HashSet;
+import java.util.List;
 import java.util.Set;
 import java.util.function.BiConsumer;
 
@@ -314,6 +315,16 @@
         }
     }
 
+    @Override
+    public void reportSystemGestureExclusionChanged(IWindow window, List<Rect> exclusionRects) {
+        long ident = Binder.clearCallingIdentity();
+        try {
+            mService.reportSystemGestureExclusionChanged(this, window, exclusionRects);
+        } finally {
+            Binder.restoreCallingIdentity(ident);
+        }
+    }
+
     private void actionOnWallpaper(IBinder window,
             BiConsumer<WallpaperController, WindowState> action) {
         final WindowState windowState = mService.windowForClientLocked(this, window, true);
diff --git a/services/core/java/com/android/server/wm/SystemGesturesPointerEventListener.java b/services/core/java/com/android/server/wm/SystemGesturesPointerEventListener.java
index bdb76c2..bd4e542 100644
--- a/services/core/java/com/android/server/wm/SystemGesturesPointerEventListener.java
+++ b/services/core/java/com/android/server/wm/SystemGesturesPointerEventListener.java
@@ -83,7 +83,12 @@
     }
 
     public void systemReady() {
-        mGestureDetector = new GestureDetector(mContext, new FlingGestureDetector(), mHandler);
+        // GestureDetector records statistics about gesture classification events to inform gesture
+        // usage trends. SystemGesturesPointerEventListener creates a lot of noise in these
+        // statistics because it passes every touch event though a GestureDetector. By creating an
+        // anonymous subclass of GestureDetector, these statistics will be recorded with a unique
+        // source name that can be filtered.
+        mGestureDetector = new GestureDetector(mContext, new FlingGestureDetector(), mHandler) {};
     }
 
     @Override
diff --git a/services/core/java/com/android/server/wm/TaskScreenshotAnimatable.java b/services/core/java/com/android/server/wm/TaskScreenshotAnimatable.java
new file mode 100644
index 0000000..e0d85e8
--- /dev/null
+++ b/services/core/java/com/android/server/wm/TaskScreenshotAnimatable.java
@@ -0,0 +1,124 @@
+/*
+ * 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.server.wm;
+
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_RECENTS_ANIMATIONS;
+
+import android.graphics.GraphicBuffer;
+import android.graphics.Rect;
+import android.util.Slog;
+import android.view.Surface;
+import android.view.SurfaceControl;
+import android.view.SurfaceSession;
+
+/**
+ * Class used by {@link RecentsAnimationController} to create a surface control with taking
+ * screenshot of task when canceling recents animation.
+ *
+ * @see {@link RecentsAnimationController#cancelOnNextTransitionStart}
+ */
+class TaskScreenshotAnimatable implements SurfaceAnimator.Animatable {
+    private static final String TAG = "TaskScreenshotAnim";
+    private Task mTask;
+    private SurfaceControl mSurfaceControl;
+    private int mWidth;
+    private int mHeight;
+
+    public static TaskScreenshotAnimatable create(Task task) {
+        return new TaskScreenshotAnimatable(task, getBufferFromTask(task));
+    }
+
+    private static GraphicBuffer getBufferFromTask(Task task) {
+        if (task == null) {
+            return null;
+        }
+        final Rect tmpRect = task.getBounds();
+        tmpRect.offset(0, 0);
+        return SurfaceControl.captureLayers(
+                task.getSurfaceControl().getHandle(), tmpRect, 1f);
+    }
+
+    private TaskScreenshotAnimatable(Task task, GraphicBuffer buffer) {
+        mTask = task;
+        mWidth = (buffer != null) ? buffer.getWidth() : 1;
+        mHeight = (buffer != null) ? buffer.getHeight() : 1;
+        if (DEBUG_RECENTS_ANIMATIONS) {
+            Slog.d(TAG, "Creating TaskScreenshotAnimatable: task: " + task
+                    + "width: " + mWidth + "height: " + mHeight);
+        }
+        mSurfaceControl = new SurfaceControl.Builder(new SurfaceSession())
+                .setName("RecentTaskScreenshotSurface")
+                .setBufferSize(mWidth, mHeight)
+                .build();
+        if (buffer != null) {
+            final Surface surface = new Surface();
+            surface.copyFrom(mSurfaceControl);
+            surface.attachAndQueueBuffer(buffer);
+            surface.release();
+        }
+        getPendingTransaction().show(mSurfaceControl);
+    }
+
+    @Override
+    public SurfaceControl.Transaction getPendingTransaction() {
+        return mTask.mPendingTransaction;
+    }
+
+    @Override
+    public void commitPendingTransaction() {
+        mTask.commitPendingTransaction();
+    }
+
+    @Override
+    public void onAnimationLeashCreated(SurfaceControl.Transaction t, SurfaceControl leash) {
+        t.setLayer(leash, 1);
+    }
+
+    @Override
+    public void onAnimationLeashDestroyed(SurfaceControl.Transaction t) {
+        t.remove(mSurfaceControl);
+    }
+
+    @Override
+    public SurfaceControl.Builder makeAnimationLeash() {
+        return mTask.makeAnimationLeash();
+    }
+
+    @Override
+    public SurfaceControl getAnimationLeashParent() {
+        return mTask.getAnimationLeashParent();
+    }
+
+    @Override
+    public SurfaceControl getSurfaceControl() {
+        return mSurfaceControl;
+    }
+
+    @Override
+    public SurfaceControl getParentSurfaceControl() {
+        return mTask.mSurfaceAnimator.mLeash;
+    }
+
+    @Override
+    public int getSurfaceWidth() {
+        return mWidth;
+    }
+
+    @Override
+    public int getSurfaceHeight() {
+        return mHeight;
+    }
+}
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index a6c9257..7751560 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -202,6 +202,7 @@
 import android.view.IPinnedStackListener;
 import android.view.IRecentsAnimationRunner;
 import android.view.IRotationWatcher;
+import android.view.ISystemGestureExclusionListener;
 import android.view.IWallpaperVisibilityListener;
 import android.view.IWindow;
 import android.view.IWindowId;
@@ -274,6 +275,7 @@
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Date;
+import java.util.List;
 
 /** {@hide} */
 public class WindowManagerService extends IWindowManager.Stub
@@ -2868,8 +2870,13 @@
     }
 
     @Override
-    public boolean isKeyguardSecure() {
-        int userId = UserHandle.getCallingUserId();
+    public boolean isKeyguardSecure(int userId) {
+        if (userId != UserHandle.getCallingUserId()
+                && !checkCallingPermission(Manifest.permission.INTERACT_ACROSS_USERS,
+                "isKeyguardSecure")) {
+            throw new SecurityException("Requires INTERACT_ACROSS_USERS permission");
+        }
+
         long origId = Binder.clearCallingIdentity();
         try {
             return mPolicy.isKeyguardSecure(userId);
@@ -3812,6 +3819,42 @@
     }
 
     @Override
+    public void registerSystemGestureExclusionListener(ISystemGestureExclusionListener listener,
+            int displayId) {
+        synchronized (mGlobalLock) {
+            final DisplayContent displayContent = mRoot.getDisplayContent(displayId);
+            if (displayContent == null) {
+                throw new IllegalArgumentException("Trying to register visibility event "
+                        + "for invalid display: " + displayId);
+            }
+            displayContent.registerSystemGestureExclusionListener(listener);
+        }
+    }
+
+    @Override
+    public void unregisterSystemGestureExclusionListener(ISystemGestureExclusionListener listener,
+            int displayId) {
+        synchronized (mGlobalLock) {
+            final DisplayContent displayContent = mRoot.getDisplayContent(displayId);
+            if (displayContent == null) {
+                throw new IllegalArgumentException("Trying to register visibility event "
+                        + "for invalid display: " + displayId);
+            }
+            displayContent.unregisterSystemGestureExclusionListener(listener);
+        }
+    }
+
+    void reportSystemGestureExclusionChanged(Session session, IWindow window,
+            List<Rect> exclusionRects) {
+        synchronized (mGlobalLock) {
+            final WindowState win = windowForClientLocked(session, window, true);
+            if (win.setSystemGestureExclusion(exclusionRects)) {
+                win.getDisplayContent().updateSystemGestureExclusion();
+            }
+        }
+    }
+
+    @Override
     public void registerDisplayFoldListener(IDisplayFoldListener listener) {
         mPolicy.registerDisplayFoldListener(listener);
     }
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index ee445d8..600178f 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -205,6 +205,7 @@
 import java.lang.ref.WeakReference;
 import java.util.ArrayList;
 import java.util.Comparator;
+import java.util.List;
 import java.util.function.Predicate;
 
 /** A window in the window manager. */
@@ -363,6 +364,13 @@
      */
     private final Rect mInsetFrame = new Rect();
 
+    /**
+     * List of rects where system gestures should be ignored.
+     *
+     * Coordinates are relative to the window's position.
+     */
+    private final List<Rect> mExclusionRects = new ArrayList<>();
+
     // If a window showing a wallpaper: the requested offset for the
     // wallpaper; if a wallpaper window: the currently applied offset.
     float mWallpaperX = -1;
@@ -612,6 +620,24 @@
         }
     }
 
+    List<Rect> getSystemGestureExclusion() {
+        return mExclusionRects;
+    }
+
+    /**
+     * Sets the system gesture exclusion rects.
+     *
+     * @return {@code true} if anything changed
+     */
+    boolean setSystemGestureExclusion(List<Rect> exclusionRects) {
+        if (mExclusionRects.equals(exclusionRects)) {
+            return false;
+        }
+        mExclusionRects.clear();
+        mExclusionRects.addAll(exclusionRects);
+        return true;
+    }
+
     interface PowerManagerWrapper {
         void wakeUp(long time, @WakeReason int reason, String details);
 
diff --git a/services/core/java/com/android/server/wm/utils/RegionUtils.java b/services/core/java/com/android/server/wm/utils/RegionUtils.java
new file mode 100644
index 0000000..1458440
--- /dev/null
+++ b/services/core/java/com/android/server/wm/utils/RegionUtils.java
@@ -0,0 +1,45 @@
+/*
+ * 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.server.wm.utils;
+
+import android.graphics.Rect;
+import android.graphics.Region;
+
+import java.util.List;
+
+/**
+ * Utility methods to handle Regions.
+ */
+public class RegionUtils {
+
+    private RegionUtils() {}
+
+
+    /**
+     * Converts a list of rects into a {@code Region}.
+     *
+     * @param rects the list of rects to convert
+     * @param outRegion the Region to set to the list of rects
+     */
+    public static void rectListToRegion(List<Rect> rects, Region outRegion) {
+        outRegion.setEmpty();
+        final int n = rects.size();
+        for (int i = 0; i < n; i++) {
+            outRegion.union(rects.get(i));
+        }
+    }
+}
diff --git a/services/core/jni/Android.bp b/services/core/jni/Android.bp
index 050a079..00b815a 100644
--- a/services/core/jni/Android.bp
+++ b/services/core/jni/Android.bp
@@ -109,6 +109,7 @@
         "android.hardware.gnss@1.0",
         "android.hardware.gnss@1.1",
         "android.hardware.gnss@2.0",
+        "android.hardware.gnss.measurement_corrections@1.0",
         "android.hardware.gnss.visibility_control@1.0",
         "android.hardware.input.classifier@1.0",
         "android.hardware.ir@1.0",
diff --git a/services/core/jni/com_android_server_input_InputManagerService.cpp b/services/core/jni/com_android_server_input_InputManagerService.cpp
index 57377c6..3d84bd4 100644
--- a/services/core/jni/com_android_server_input_InputManagerService.cpp
+++ b/services/core/jni/com_android_server_input_InputManagerService.cpp
@@ -228,7 +228,7 @@
 
     virtual void getReaderConfiguration(InputReaderConfiguration* outConfig);
     virtual sp<PointerControllerInterface> obtainPointerController(int32_t deviceId);
-    virtual void notifyInputDevicesChanged(const Vector<InputDeviceInfo>& inputDevices);
+    virtual void notifyInputDevicesChanged(const std::vector<InputDeviceInfo>& inputDevices);
     virtual sp<KeyCharacterMap> getKeyboardLayoutOverlay(const InputDeviceIdentifier& identifier);
     virtual std::string getDeviceAlias(const InputDeviceIdentifier& identifier);
     virtual TouchAffineTransformation getTouchAffineTransformation(JNIEnv *env,
@@ -598,7 +598,7 @@
     }
 }
 
-void NativeInputManager::notifyInputDevicesChanged(const Vector<InputDeviceInfo>& inputDevices) {
+void NativeInputManager::notifyInputDevicesChanged(const std::vector<InputDeviceInfo>& inputDevices) {
     ATRACE_CALL();
     JNIEnv* env = jniEnv();
 
@@ -608,7 +608,7 @@
     if (inputDevicesObjArray) {
         bool error = false;
         for (size_t i = 0; i < count; i++) {
-            jobject inputDeviceObj = android_view_InputDevice_create(env, inputDevices.itemAt(i));
+            jobject inputDeviceObj = android_view_InputDevice_create(env, inputDevices[i]);
             if (!inputDeviceObj) {
                 error = true;
                 break;
@@ -775,7 +775,7 @@
 
 void NativeInputManager::setInputWindows(JNIEnv* env, jobjectArray windowHandleObjArray,
          int32_t displayId) {
-    Vector<sp<InputWindowHandle> > windowHandles;
+    std::vector<sp<InputWindowHandle> > windowHandles;
 
     if (windowHandleObjArray) {
         jsize length = env->GetArrayLength(windowHandleObjArray);
@@ -788,7 +788,7 @@
             sp<InputWindowHandle> windowHandle =
                     android_view_InputWindowHandle_getHandle(env, windowHandleObj);
             if (windowHandle != nullptr) {
-                windowHandles.push(windowHandle);
+                windowHandles.push_back(windowHandle);
             }
             env->DeleteLocalRef(windowHandleObj);
         }
@@ -800,7 +800,7 @@
     bool newPointerGesturesEnabled = true;
     size_t numWindows = windowHandles.size();
     for (size_t i = 0; i < numWindows; i++) {
-        const sp<InputWindowHandle>& windowHandle = windowHandles.itemAt(i);
+        const sp<InputWindowHandle>& windowHandle = windowHandles[i];
         const InputWindowInfo* windowInfo = windowHandle->getInfo();
         if (windowInfo && windowInfo->hasFocus && (windowInfo->inputFeatures
                 & InputWindowInfo::INPUT_FEATURE_DISABLE_TOUCH_PAD_GESTURES)) {
diff --git a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
index caba3af..65a7eec 100644
--- a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
+++ b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
@@ -71,6 +71,7 @@
 static jmethodID method_reportNavigationMessages;
 static jmethodID method_reportLocationBatch;
 static jmethodID method_reportGnssServiceDied;
+static jmethodID method_setMeasurementCorrectionsCapabilities;
 static jmethodID method_correctionsGetLatitudeDegrees;
 static jmethodID method_correctionsGetLongitudeDegrees;
 static jmethodID method_correctionsGetAltitudeMeters;
@@ -116,9 +117,6 @@
 using android::hardware::gnss::V1_0::GnssConstellationType;
 using android::hardware::gnss::V1_0::GnssLocationFlags;
 using android::hardware::gnss::V1_0::IAGnssRilCallback;
-using android::hardware::gnss::V1_0::IGnssBatching;
-using android::hardware::gnss::V1_0::IGnssBatchingCallback;
-using android::hardware::gnss::V1_0::IGnssDebug;
 using android::hardware::gnss::V1_0::IGnssGeofenceCallback;
 using android::hardware::gnss::V1_0::IGnssGeofencing;
 using android::hardware::gnss::V1_0::IGnssNavigationMessage;
@@ -142,9 +140,12 @@
 using IGnss_V1_0 = android::hardware::gnss::V1_0::IGnss;
 using IGnss_V1_1 = android::hardware::gnss::V1_1::IGnss;
 using IGnss_V2_0 = android::hardware::gnss::V2_0::IGnss;
+using IGnssCallback_V1_0 = android::hardware::gnss::V1_0::IGnssCallback;
 using IGnssConfiguration_V1_0 = android::hardware::gnss::V1_0::IGnssConfiguration;
 using IGnssConfiguration_V1_1 = android::hardware::gnss::V1_1::IGnssConfiguration;
 using IGnssConfiguration_V2_0 = android::hardware::gnss::V2_0::IGnssConfiguration;
+using IGnssDebug_V1_0 = android::hardware::gnss::V1_0::IGnssDebug;
+using IGnssDebug_V2_0 = android::hardware::gnss::V2_0::IGnssDebug;
 using IGnssMeasurement_V1_0 = android::hardware::gnss::V1_0::IGnssMeasurement;
 using IGnssMeasurement_V1_1 = android::hardware::gnss::V1_1::IGnssMeasurement;
 using IGnssMeasurement_V2_0 = android::hardware::gnss::V2_0::IGnssMeasurement;
@@ -157,11 +158,14 @@
 using IAGnss_V2_0 = android::hardware::gnss::V2_0::IAGnss;
 using IAGnssCallback_V1_0 = android::hardware::gnss::V1_0::IAGnssCallback;
 using IAGnssCallback_V2_0 = android::hardware::gnss::V2_0::IAGnssCallback;
+using IGnssBatching_V1_0 = android::hardware::gnss::V1_0::IGnssBatching;
+using IGnssBatching_V2_0 = android::hardware::gnss::V2_0::IGnssBatching;
+using IGnssBatchingCallback_V1_0 = android::hardware::gnss::V1_0::IGnssBatchingCallback;
+using IGnssBatchingCallback_V2_0 = android::hardware::gnss::V2_0::IGnssBatchingCallback;
 
-using IMeasurementCorrections =
-    android::hardware::gnss::measurement_corrections::V1_0::IMeasurementCorrections;
-using GnssSingleSatCorrectionFlags =
-    android::hardware::gnss::measurement_corrections::V1_0::GnssSingleSatCorrectionFlags;
+using android::hardware::gnss::measurement_corrections::V1_0::IMeasurementCorrections;
+using android::hardware::gnss::measurement_corrections::V1_0::IMeasurementCorrectionsCallback;
+using android::hardware::gnss::measurement_corrections::V1_0::GnssSingleSatCorrectionFlags;
 
 using android::hardware::gnss::visibility_control::V1_0::IGnssVisibilityControl;
 using android::hardware::gnss::visibility_control::V1_0::IGnssVisibilityControlCallback;
@@ -190,8 +194,10 @@
 sp<IGnssGeofencing> gnssGeofencingIface = nullptr;
 sp<IAGnss_V1_0> agnssIface = nullptr;
 sp<IAGnss_V2_0> agnssIface_V2_0 = nullptr;
-sp<IGnssBatching> gnssBatchingIface = nullptr;
-sp<IGnssDebug> gnssDebugIface = nullptr;
+sp<IGnssBatching_V1_0> gnssBatchingIface = nullptr;
+sp<IGnssBatching_V2_0> gnssBatchingIface_V2_0 = nullptr;
+sp<IGnssDebug_V1_0> gnssDebugIface = nullptr;
+sp<IGnssDebug_V2_0> gnssDebugIface_V2_0 = nullptr;
 sp<IGnssConfiguration_V1_0> gnssConfigurationIface = nullptr;
 sp<IGnssConfiguration_V1_1> gnssConfigurationIface_V1_1 = nullptr;
 sp<IGnssConfiguration_V2_0> gnssConfigurationIface_V2_0 = nullptr;
@@ -201,7 +207,6 @@
 sp<IGnssMeasurement_V2_0> gnssMeasurementIface_V2_0 = nullptr;
 sp<IGnssNavigationMessage> gnssNavigationMessageIface = nullptr;
 sp<IMeasurementCorrections> gnssCorrectionsIface = nullptr;
-
 sp<IGnssVisibilityControl> gnssVisibilityControlIface = nullptr;
 
 #define WAKE_LOCK_NAME  "GPS"
@@ -549,7 +554,9 @@
 struct GnssCallback : public IGnssCallback {
     Return<void> gnssLocationCb(const GnssLocation_V1_0& location) override;
     Return<void> gnssStatusCb(const IGnssCallback::GnssStatusValue status) override;
-    Return<void> gnssSvStatusCb(const IGnssCallback::GnssSvStatus& svStatus) override;
+    Return<void> gnssSvStatusCb(const IGnssCallback_V1_0::GnssSvStatus& svStatus) override {
+        return gnssSvStatusCbImpl(svStatus);
+    }
     Return<void> gnssNmeaCb(int64_t timestamp, const android::hardware::hidl_string& nmea) override;
     Return<void> gnssSetCapabilitesCb(uint32_t capabilities) override;
     Return<void> gnssAcquireWakelockCb() override;
@@ -567,14 +574,47 @@
             override;
     Return<void> gnssSetCapabilitiesCb_2_0(uint32_t capabilities) override;
     Return<void> gnssLocationCb_2_0(const GnssLocation_V2_0& location) override;
+    Return<void> gnssSvStatusCb_2_0(const hidl_vec<IGnssCallback::GnssSvInfo>& svInfoList) override {
+        return gnssSvStatusCbImpl(svInfoList);
+    }
 
-    // Templated implementation for gnnsLocationCb and gnnsLocationCb_2_0.
-    template <class T>
-    Return<void> gnssLocationCbImpl(const T& location);
+    Return<void> gnssSetCapabilitesCbImpl(uint32_t capabilities, bool hasSubHalCapabilityFlags);
 
-    // TODO(b/73306084): Reconsider allocation cost vs threadsafety on these statics
+    // TODO: Reconsider allocation cost vs threadsafety on these statics
     static const char* sNmeaString;
     static size_t sNmeaStringLength;
+private:
+    template<class T>
+    Return<void> gnssLocationCbImpl(const T& location);
+
+    template<class T>
+    Return<void> gnssSvStatusCbImpl(const T& svStatus);
+
+    uint32_t getGnssSvInfoListSize(const IGnssCallback_V1_0::GnssSvStatus& svStatus) {
+        return svStatus.numSvs;
+    }
+
+    uint32_t getGnssSvInfoListSize(const hidl_vec<IGnssCallback::GnssSvInfo>& svInfoList) {
+        return svInfoList.size();
+    }
+
+    const IGnssCallback_V1_0::GnssSvInfo& getGnssSvInfoOfIndex(
+            const IGnssCallback_V1_0::GnssSvStatus& svStatus, size_t i) {
+        return svStatus.gnssSvList.data()[i];
+    }
+
+    const IGnssCallback_V1_0::GnssSvInfo& getGnssSvInfoOfIndex(
+            const hidl_vec<IGnssCallback::GnssSvInfo>& svInfoList, size_t i) {
+        return svInfoList[i].v1_0;
+    }
+
+    uint32_t getConstellationType(const IGnssCallback_V1_0::GnssSvStatus& svStatus, size_t i) {
+        return static_cast<uint32_t>(svStatus.gnssSvList.data()[i].constellation);
+    }
+
+    uint32_t getConstellationType(const hidl_vec<IGnssCallback::GnssSvInfo>& svInfoList, size_t i) {
+        return static_cast<uint32_t>(svInfoList[i].constellation);
+    }
 };
 
 Return<void> GnssCallback::gnssNameCb(const android::hardware::hidl_string& name) {
@@ -622,10 +662,11 @@
     return Void();
 }
 
-Return<void> GnssCallback::gnssSvStatusCb(const IGnssCallback::GnssSvStatus& svStatus) {
+template<class T>
+Return<void> GnssCallback::gnssSvStatusCbImpl(const T& svStatus) {
     JNIEnv* env = getJniEnv();
 
-    uint32_t listSize = svStatus.numSvs;
+    uint32_t listSize = getGnssSvInfoListSize(svStatus);
     if (listSize > static_cast<uint32_t>(
             android::hardware::gnss::V1_0::GnssMax::SVS_COUNT)) {
         ALOGD("Too many satellites %u. Clamps to %u.", listSize,
@@ -654,9 +695,9 @@
             CONSTELLATION_TYPE_SHIFT_WIDTH = 4
         };
 
-        const IGnssCallback::GnssSvInfo& info = svStatus.gnssSvList.data()[i];
+        const IGnssCallback_V1_0::GnssSvInfo& info = getGnssSvInfoOfIndex(svStatus, i);
         svidWithFlags[i] = (info.svid << SVID_SHIFT_WIDTH) |
-            (static_cast<uint32_t>(info.constellation) << CONSTELLATION_TYPE_SHIFT_WIDTH) |
+            (getConstellationType(svStatus, i) << CONSTELLATION_TYPE_SHIFT_WIDTH) |
             static_cast<uint32_t>(info.svFlag);
         cn0s[i] = info.cN0Dbhz;
         elev[i] = info.elevationDegrees;
@@ -694,16 +735,29 @@
 }
 
 Return<void> GnssCallback::gnssSetCapabilitesCb(uint32_t capabilities) {
-    ALOGD("%s: %du\n", __func__, capabilities);
-
-    JNIEnv* env = getJniEnv();
-    env->CallVoidMethod(mCallbacksObj, method_setEngineCapabilities, capabilities);
-    checkAndClearExceptionFromCallback(env, __FUNCTION__);
-    return Void();
+    return GnssCallback::gnssSetCapabilitesCbImpl(capabilities,
+        /* hasSubHalCapabilityFlags = */ true);
 }
 
 Return<void> GnssCallback::gnssSetCapabilitiesCb_2_0(uint32_t capabilities) {
-    return GnssCallback::gnssSetCapabilitesCb(capabilities);
+    return GnssCallback::gnssSetCapabilitesCbImpl(capabilities,
+        /* hasSubHalCapabilityFlags = */ false);
+}
+
+Return <void> GnssCallback::gnssSetCapabilitesCbImpl(uint32_t capabilities,
+        bool hasSubHalCapabilityFlags) {
+    // The IGnssCallback.hal@2.0 removed sub-HAL capability flags from the Capabilities enum
+    // and instead uses the sub-HAL non-null handle returned from IGnss.hal@2.0 to indicate
+    // support. Therefore, the 'hasSubHalCapabilityFlags' parameter is needed to tell if the
+    // 'capabilities' parameter includes the sub-HAL capability flags or not. Old HALs
+    // which explicitly set the sub-HAL capability bits must continue to work.
+    ALOGD("%s: capabilities=%du, hasSubHalCapabilityFlags=%d\n", __func__, capabilities,
+        hasSubHalCapabilityFlags);
+    JNIEnv* env = getJniEnv();
+    env->CallVoidMethod(mCallbacksObj, method_setEngineCapabilities, capabilities,
+            boolToJbool(hasSubHalCapabilityFlags));
+    checkAndClearExceptionFromCallback(env, __FUNCTION__);
+    return Void();
 }
 
 Return<void> GnssCallback::gnssAcquireWakelockCb() {
@@ -1065,6 +1119,9 @@
 
     // Overwrite with v2_0.state since v2_0->v1_1->v1_0.state is deprecated.
     SET(State, static_cast<int32_t>(measurement_V2_0->state));
+
+    // Overwrite with v2_0.constellation since v2_0->v1_1->v1_0.constellation is deprecated.
+    SET(ConstellationType, static_cast<int32_t>(measurement_V2_0->constellation));
 }
 
 jobject GnssMeasurementCallback::translateGnssClock(
@@ -1153,6 +1210,22 @@
 }
 
 /*
+ * MeasurementCorrectionsCallback implements callback methods of interface
+ * IMeasurementCorrectionsCallback.hal.
+ */
+struct MeasurementCorrectionsCallback : public IMeasurementCorrectionsCallback {
+    Return<void> setCapabilitiesCb(uint32_t capabilities) override;
+};
+
+Return<void> MeasurementCorrectionsCallback::setCapabilitiesCb(uint32_t capabilities) {
+    ALOGD("%s: %du\n", __func__, capabilities);
+    JNIEnv* env = getJniEnv();
+    env->CallVoidMethod(mCallbacksObj, method_setMeasurementCorrectionsCapabilities, capabilities);
+    checkAndClearExceptionFromCallback(env, __FUNCTION__);
+    return Void();
+}
+
+/*
  * GnssNiCallback implements callback methods required by the IGnssNi interface.
  */
 struct GnssNiCallback : public IGnssNiCallback {
@@ -1375,20 +1448,15 @@
     return Void();
 }
 
-/*
- * GnssBatchingCallback interface implements the callback methods
- * required by the IGnssBatching interface.
- */
-struct GnssBatchingCallback : public IGnssBatchingCallback {
-    /*
-    * Methods from ::android::hardware::gps::V1_0::IGnssBatchingCallback
-    * follow.
-    */
-    Return<void> gnssLocationBatchCb(const hidl_vec<GnssLocation_V1_0>& locations) override;
+struct GnssBatchingCallbackUtil {
+    template<class T>
+    static Return<void> gnssLocationBatchCbImpl(const hidl_vec<T>& locations);
+private:
+    GnssBatchingCallbackUtil() = delete;
 };
 
-Return<void> GnssBatchingCallback::gnssLocationBatchCb(
-    const hidl_vec<GnssLocation_V1_0>& locations) {
+template<class T>
+Return<void> GnssBatchingCallbackUtil::gnssLocationBatchCbImpl(const hidl_vec<T>& locations) {
     JNIEnv* env = getJniEnv();
 
     jobjectArray jLocations = env->NewObjectArray(locations.size(),
@@ -1408,6 +1476,28 @@
     return Void();
 }
 
+/*
+ * GnssBatchingCallback_V1_0 class implements the callback methods required by the
+ * IGnssBatching 1.0 interface.
+ */
+struct GnssBatchingCallback_V1_0 : public IGnssBatchingCallback_V1_0 {
+    /** Methods from ::android::hardware::gps::V1_0::IGnssBatchingCallback follow. */
+    Return<void> gnssLocationBatchCb(const hidl_vec<GnssLocation_V1_0>& locations) override {
+        return GnssBatchingCallbackUtil::gnssLocationBatchCbImpl(locations);
+    }
+};
+
+/*
+ * GnssBatchingCallback_V2_0 class implements the callback methods required by the
+ * IGnssBatching 2.0 interface.
+ */
+struct GnssBatchingCallback_V2_0 : public IGnssBatchingCallback_V2_0 {
+    /** Methods from ::android::hardware::gps::V2_0::IGnssBatchingCallback follow. */
+    Return<void> gnssLocationBatchCb(const hidl_vec<GnssLocation_V2_0>& locations) override {
+        return GnssBatchingCallbackUtil::gnssLocationBatchCbImpl(locations);
+    }
+};
+
 static void android_location_GnssLocationProvider_class_init_native(JNIEnv* env, jclass clazz) {
     gnssHal_V2_0 = IGnss_V2_0::getService();
     if (gnssHal_V2_0 != nullptr) {
@@ -1434,7 +1524,7 @@
     method_reportSvStatus = env->GetMethodID(clazz, "reportSvStatus", "(I[I[F[F[F[F)V");
     method_reportAGpsStatus = env->GetMethodID(clazz, "reportAGpsStatus", "(II[B)V");
     method_reportNmea = env->GetMethodID(clazz, "reportNmea", "(J)V");
-    method_setEngineCapabilities = env->GetMethodID(clazz, "setEngineCapabilities", "(I)V");
+    method_setEngineCapabilities = env->GetMethodID(clazz, "setEngineCapabilities", "(IZ)V");
     method_setGnssYearOfHardware = env->GetMethodID(clazz, "setGnssYearOfHardware", "(I)V");
     method_setGnssHardwareModelName = env->GetMethodID(clazz, "setGnssHardwareModelName",
             "(Ljava/lang/String;)V");
@@ -1474,6 +1564,9 @@
             "(Ljava/lang/String;BLjava/lang/String;BLjava/lang/String;BZZ)V");
     method_isInEmergencySession = env->GetMethodID(clazz, "isInEmergencySession", "()Z");
 
+    method_setMeasurementCorrectionsCapabilities = env->GetMethodID(clazz,
+            "setMeasurementCorrectionsCapabilities", "(I)V");
+
     jclass measCorrClass = env->FindClass("android/location/GnssMeasurementCorrections");
     method_correctionsGetLatitudeDegrees = env->GetMethodID(
             measCorrClass,"getLatitudeDegrees", "()D");
@@ -1591,7 +1684,7 @@
     }
 
     if (gnssHal_V2_0 != nullptr) {
-        // TODO(b/119638366): getExtensionGnssMeasurement_1_1 from gnssHal_V2_0
+        // TODO: getExtensionGnssMeasurement_1_1 from gnssHal_V2_0
         auto gnssMeasurement = gnssHal_V2_0->getExtensionGnssMeasurement_2_0();
         if (!gnssMeasurement.isOk()) {
             ALOGD("Unable to get a handle to GnssMeasurement_V2_0");
@@ -1623,11 +1716,21 @@
          }
     }
 
-    auto gnssDebug = gnssHal->getExtensionGnssDebug();
-    if (!gnssDebug.isOk()) {
-        ALOGD("Unable to get a handle to GnssDebug");
+    if (gnssHal_V2_0 != nullptr) {
+        auto gnssDebug = gnssHal_V2_0->getExtensionGnssDebug_2_0();
+        if (!gnssDebug.isOk()) {
+            ALOGD("Unable to get a handle to GnssDebug_V2_0");
+        } else {
+            gnssDebugIface_V2_0 = gnssDebug;
+            gnssDebugIface = gnssDebugIface_V2_0;
+        }
     } else {
-        gnssDebugIface = gnssDebug;
+        auto gnssDebug = gnssHal->getExtensionGnssDebug();
+        if (!gnssDebug.isOk()) {
+            ALOGD("Unable to get a handle to GnssDebug");
+        } else {
+            gnssDebugIface = gnssDebug;
+        }
     }
 
     auto gnssNi = gnssHal->getExtensionGnssNi();
@@ -1670,11 +1773,22 @@
         gnssGeofencingIface = gnssGeofencing;
     }
 
-    auto gnssBatching = gnssHal->getExtensionGnssBatching();
-    if (!gnssBatching.isOk()) {
-        ALOGD("Unable to get a handle to gnssBatching");
-    } else {
-        gnssBatchingIface = gnssBatching;
+    // If IGnssBatching.hal@2.0 is not supported, use IGnssBatching.hal@1.0
+    if (gnssHal_V2_0 != nullptr) {
+        auto gnssBatching_V2_0 = gnssHal_V2_0->getExtensionGnssBatching_2_0();
+        if (!gnssBatching_V2_0.isOk()) {
+            ALOGD("Unable to get a handle to GnssBatching_V2_0");
+        } else {
+            gnssBatchingIface_V2_0 = gnssBatching_V2_0;
+        }
+    }
+    if (gnssBatchingIface_V2_0 == nullptr ) {
+        auto gnssBatching_V1_0 = gnssHal->getExtensionGnssBatching();
+        if (!gnssBatching_V1_0.isOk()) {
+            ALOGD("Unable to get a handle to GnssBatching");
+        } else {
+            gnssBatchingIface = gnssBatching_V1_0;
+        }
     }
 
     if (gnssHal_V2_0 != nullptr) {
@@ -1795,6 +1909,12 @@
         gnssVisibilityControlIface->setCallback(gnssVisibilityControlCbIface);
     }
 
+    if (gnssCorrectionsIface != nullptr) {
+        sp<IMeasurementCorrectionsCallback> gnssCorrectionsIfaceCbIface =
+                new MeasurementCorrectionsCallback();
+        gnssCorrectionsIface->setCallback(gnssCorrectionsIfaceCbIface);
+    }
+
     return JNI_TRUE;
 }
 
@@ -2034,8 +2154,6 @@
 
 private:
     AGnssDispatcher() = delete;
-    AGnssDispatcher(const AGnssDispatcher&) = delete;
-    AGnssDispatcher& operator=(const AGnssDispatcher&) = delete;
 };
 
 void AGnssDispatcher::dataConnOpen(sp<IAGnss_V1_0> agnssIface, JNIEnv* env, jstring apn,
@@ -2150,76 +2268,100 @@
     gnssNiIface->respond(notifId, static_cast<IGnssNiCallback::GnssUserResponseType>(response));
 }
 
+const IGnssDebug_V1_0::SatelliteData& getSatelliteData(const hidl_vec<IGnssDebug_V1_0::SatelliteData>& satelliteDataArray, size_t i) {
+    return satelliteDataArray[i];
+}
+
+const IGnssDebug_V1_0::SatelliteData& getSatelliteData(const hidl_vec<IGnssDebug_V2_0::SatelliteData>& satelliteDataArray, size_t i) {
+    return satelliteDataArray[i].v1_0;
+}
+
+template<class T>
+uint32_t getConstellationType(const hidl_vec<T>& satelliteDataArray, size_t i) {
+    return static_cast<uint32_t>(satelliteDataArray[i].constellation);
+}
+
+template<class T>
+static jstring parseDebugData(JNIEnv* env, std::stringstream& internalState, const T& data) {
+    internalState << "Gnss Location Data:: ";
+    if (!data.position.valid) {
+        internalState << "not valid";
+    } else {
+        internalState << "LatitudeDegrees: " << data.position.latitudeDegrees
+                      << ", LongitudeDegrees: " << data.position.longitudeDegrees
+                      << ", altitudeMeters: " << data.position.altitudeMeters
+                      << ", speedMetersPerSecond: " << data.position.speedMetersPerSec
+                      << ", bearingDegrees: " << data.position.bearingDegrees
+                      << ", horizontalAccuracyMeters: "
+                      << data.position.horizontalAccuracyMeters
+                      << ", verticalAccuracyMeters: " << data.position.verticalAccuracyMeters
+                      << ", speedAccuracyMetersPerSecond: "
+                      << data.position.speedAccuracyMetersPerSecond
+                      << ", bearingAccuracyDegrees: " << data.position.bearingAccuracyDegrees
+                      << ", ageSeconds: " << data.position.ageSeconds;
+    }
+    internalState << std::endl;
+
+    internalState << "Gnss Time Data:: timeEstimate: " << data.time.timeEstimate
+                  << ", timeUncertaintyNs: " << data.time.timeUncertaintyNs
+                  << ", frequencyUncertaintyNsPerSec: "
+                  << data.time.frequencyUncertaintyNsPerSec << std::endl;
+
+    if (data.satelliteDataArray.size() != 0) {
+        internalState << "Satellite Data for " << data.satelliteDataArray.size()
+                      << " satellites:: " << std::endl;
+    }
+
+    internalState << "constell: 1=GPS, 2=SBAS, 3=GLO, 4=QZSS, 5=BDS, 6=GAL, 7=IRNSS; "
+                  << "ephType: 0=Eph, 1=Alm, 2=Unk; "
+                  << "ephSource: 0=Demod, 1=Supl, 2=Server, 3=Unk; "
+                  << "ephHealth: 0=Good, 1=Bad, 2=Unk" << std::endl;
+    for (size_t i = 0; i < data.satelliteDataArray.size(); i++) {
+        IGnssDebug_V1_0::SatelliteData satelliteData =
+                getSatelliteData(data.satelliteDataArray, i);
+        internalState << "constell: "
+                      << getConstellationType(data.satelliteDataArray, i)
+                      << ", svid: " << std::setw(3) << satelliteData.svid
+                      << ", serverPredAvail: "
+                      << satelliteData.serverPredictionIsAvailable
+                      << ", serverPredAgeSec: " << std::setw(7)
+                      << satelliteData.serverPredictionAgeSeconds
+                      << ", ephType: "
+                      << static_cast<uint32_t>(satelliteData.ephemerisType)
+                      << ", ephSource: "
+                      << static_cast<uint32_t>(satelliteData.ephemerisSource)
+                      << ", ephHealth: "
+                      << static_cast<uint32_t>(satelliteData.ephemerisHealth)
+                      << ", ephAgeSec: " << std::setw(7)
+                      << satelliteData.ephemerisAgeSeconds << std::endl;
+    }
+    return (jstring) env->NewStringUTF(internalState.str().c_str());
+}
+
 static jstring android_location_GnssLocationProvider_get_internal_state(JNIEnv* env,
                                                                        jobject /* obj */) {
     jstring result = nullptr;
     /*
-     * TODO(b/33089503) : Create a jobject to represent GnssDebug.
+     * TODO: Create a jobject to represent GnssDebug.
      */
 
     std::stringstream internalState;
 
     if (gnssDebugIface == nullptr) {
         internalState << "Gnss Debug Interface not available"  << std::endl;
-    } else {
-        IGnssDebug::DebugData data;
-        gnssDebugIface->getDebugData([&data](const IGnssDebug::DebugData& debugData) {
+    } else if (gnssDebugIface_V2_0 != nullptr) {
+        IGnssDebug_V2_0::DebugData data;
+        gnssDebugIface_V2_0->getDebugData_2_0([&data](const IGnssDebug_V2_0::DebugData& debugData) {
             data = debugData;
         });
-
-        internalState << "Gnss Location Data:: ";
-        if (!data.position.valid) {
-            internalState << "not valid";
-        } else {
-            internalState << "LatitudeDegrees: " << data.position.latitudeDegrees
-                          << ", LongitudeDegrees: " << data.position.longitudeDegrees
-                          << ", altitudeMeters: " << data.position.altitudeMeters
-                          << ", speedMetersPerSecond: " << data.position.speedMetersPerSec
-                          << ", bearingDegrees: " << data.position.bearingDegrees
-                          << ", horizontalAccuracyMeters: "
-                          << data.position.horizontalAccuracyMeters
-                          << ", verticalAccuracyMeters: " << data.position.verticalAccuracyMeters
-                          << ", speedAccuracyMetersPerSecond: "
-                          << data.position.speedAccuracyMetersPerSecond
-                          << ", bearingAccuracyDegrees: " << data.position.bearingAccuracyDegrees
-                          << ", ageSeconds: " << data.position.ageSeconds;
-        }
-        internalState << std::endl;
-
-        internalState << "Gnss Time Data:: timeEstimate: " << data.time.timeEstimate
-                      << ", timeUncertaintyNs: " << data.time.timeUncertaintyNs
-                      << ", frequencyUncertaintyNsPerSec: "
-                      << data.time.frequencyUncertaintyNsPerSec << std::endl;
-
-        if (data.satelliteDataArray.size() != 0) {
-            internalState << "Satellite Data for " << data.satelliteDataArray.size()
-                          << " satellites:: " << std::endl;
-        }
-
-        internalState << "constell: 1=GPS, 2=SBAS, 3=GLO, 4=QZSS, 5=BDS, 6=GAL; "
-                      << "ephType: 0=Eph, 1=Alm, 2=Unk; "
-                      << "ephSource: 0=Demod, 1=Supl, 2=Server, 3=Unk; "
-                      << "ephHealth: 0=Good, 1=Bad, 2=Unk" << std::endl;
-        for (size_t i = 0; i < data.satelliteDataArray.size(); i++) {
-            internalState << "constell: "
-                          << static_cast<uint32_t>(data.satelliteDataArray[i].constellation)
-                          << ", svid: " << std::setw(3) << data.satelliteDataArray[i].svid
-                          << ", serverPredAvail: "
-                          << data.satelliteDataArray[i].serverPredictionIsAvailable
-                          << ", serverPredAgeSec: " << std::setw(7)
-                          << data.satelliteDataArray[i].serverPredictionAgeSeconds
-                          << ", ephType: "
-                          << static_cast<uint32_t>(data.satelliteDataArray[i].ephemerisType)
-                          << ", ephSource: "
-                          << static_cast<uint32_t>(data.satelliteDataArray[i].ephemerisSource)
-                          << ", ephHealth: "
-                          << static_cast<uint32_t>(data.satelliteDataArray[i].ephemerisHealth)
-                          << ", ephAgeSec: " << std::setw(7)
-                          << data.satelliteDataArray[i].ephemerisAgeSeconds << std::endl;
-        }
+        result = parseDebugData(env, internalState, data);
+    } else {
+        IGnssDebug_V1_0::DebugData data;
+        gnssDebugIface->getDebugData([&data](const IGnssDebug_V1_0::DebugData& debugData) {
+            data = debugData;
+        });
+        result = parseDebugData(env, internalState, data);
     }
-
-    result = env->NewStringUTF(internalState.str().c_str());
     return result;
 }
 
@@ -2380,13 +2522,25 @@
     return boolToJbool(result.isOk());
 }
 
-static jboolean android_location_GnssMeasurementsProvider_inject_gnss_measurement_corrections(
+static jboolean
+    android_location_GnssMeasurementCorrectionsProvider_is_measurement_corrections_supported(
+    JNIEnv* env, jclass clazz) {
+    if (gnssCorrectionsIface != nullptr) {
+        return JNI_TRUE;
+    }
+
+    return JNI_FALSE;
+}
+
+static jboolean
+    android_location_GnssMeasurementCorrectionsProvider_inject_gnss_measurement_corrections(
         JNIEnv* env,
         jobject obj /* clazz*/,
         jobject correctionsObj) {
 
     if (gnssCorrectionsIface == nullptr) {
-        ALOGW("Trying to inject GNSS corrections on a chipset that does not support them.");
+        ALOGW("Trying to inject GNSS measurement corrections on a chipset that does not"
+            " support them.");
         return JNI_FALSE;
     }
 
@@ -2723,12 +2877,15 @@
 }
 
 static jboolean android_location_GnssBatchingProvider_init_batching(JNIEnv*, jclass) {
-    if (gnssBatchingIface == nullptr) {
+    if (gnssBatchingIface_V2_0 != nullptr) {
+        sp<IGnssBatchingCallback_V2_0> gnssBatchingCbIface_V2_0 = new GnssBatchingCallback_V2_0();
+        return static_cast<jboolean>(gnssBatchingIface_V2_0->init_2_0(gnssBatchingCbIface_V2_0));
+    } else if (gnssBatchingIface != nullptr) {
+        sp<IGnssBatchingCallback_V1_0> gnssBatchingCbIface_V1_0 = new GnssBatchingCallback_V1_0();
+        return static_cast<jboolean>(gnssBatchingIface->init(gnssBatchingCbIface_V1_0));
+    } else {
         return JNI_FALSE; // batching not supported
     }
-    sp<IGnssBatchingCallback> gnssBatchingCbIface = new GnssBatchingCallback();
-
-    return static_cast<jboolean>(gnssBatchingIface->init(gnssBatchingCbIface));
 }
 
 static void android_location_GnssBatchingProvider_cleanup_batching(JNIEnv*, jclass) {
@@ -2744,10 +2901,10 @@
         return JNI_FALSE; // batching not supported
     }
 
-    IGnssBatching::Options options;
+    IGnssBatching_V1_0::Options options;
     options.periodNanos = periodNanos;
     if (wakeOnFifoFull) {
-        options.flags = static_cast<uint8_t>(IGnssBatching::Flag::WAKEUP_ON_FIFO_FULL);
+        options.flags = static_cast<uint8_t>(IGnssBatching_V1_0::Flag::WAKEUP_ON_FIFO_FULL);
     } else {
         options.flags = 0;
     }
@@ -2882,18 +3039,25 @@
 static const JNINativeMethod sMeasurementMethods[] = {
     /* name, signature, funcPtr */
     {"native_is_measurement_supported", "()Z",
-     reinterpret_cast<void*>(
-         android_location_GnssMeasurementsProvider_is_measurement_supported)},
+            reinterpret_cast<void*>(
+            android_location_GnssMeasurementsProvider_is_measurement_supported)},
     {"native_start_measurement_collection", "(Z)Z",
-     reinterpret_cast<void*>(
-         android_location_GnssMeasurementsProvider_start_measurement_collection)},
+            reinterpret_cast<void*>(
+            android_location_GnssMeasurementsProvider_start_measurement_collection)},
     {"native_stop_measurement_collection", "()Z",
-     reinterpret_cast<void*>(
-         android_location_GnssMeasurementsProvider_stop_measurement_collection)},
+            reinterpret_cast<void*>(
+            android_location_GnssMeasurementsProvider_stop_measurement_collection)},
+};
+
+static const JNINativeMethod sMeasurementCorrectionsMethods[] = {
+    /* name, signature, funcPtr */
+    {"native_is_measurement_corrections_supported", "()Z",
+            reinterpret_cast<void*>(
+            android_location_GnssMeasurementCorrectionsProvider_is_measurement_corrections_supported)},
     {"native_inject_gnss_measurement_corrections",
-     "(Landroid/location/GnssMeasurementCorrections;)Z",
-     reinterpret_cast<void*>(
-         android_location_GnssMeasurementsProvider_inject_gnss_measurement_corrections)},
+            "(Landroid/location/GnssMeasurementCorrections;)Z",
+            reinterpret_cast<void*>(
+            android_location_GnssMeasurementCorrectionsProvider_inject_gnss_measurement_corrections)},
 };
 
 static const JNINativeMethod sNavigationMessageMethods[] = {
@@ -2992,6 +3156,11 @@
             NELEM(sMeasurementMethods));
     jniRegisterNativeMethods(
             env,
+            "com/android/server/location/GnssMeasurementCorrectionsProvider",
+            sMeasurementCorrectionsMethods,
+            NELEM(sMeasurementCorrectionsMethods));
+    jniRegisterNativeMethods(
+            env,
             "com/android/server/location/GnssNavigationMessageProvider",
             sNavigationMessageMethods,
             NELEM(sNavigationMessageMethods));
diff --git a/services/ipmemorystore/Android.bp b/services/ipmemorystore/Android.bp
deleted file mode 100644
index 013cf56..0000000
--- a/services/ipmemorystore/Android.bp
+++ /dev/null
@@ -1,4 +0,0 @@
-java_library_static {
-    name: "services.ipmemorystore",
-    srcs: ["java/**/*.java"],
-}
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 3f323d9..419f52c 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -108,7 +108,6 @@
 import com.android.server.media.projection.MediaProjectionManagerService;
 import com.android.server.net.NetworkPolicyManagerService;
 import com.android.server.net.NetworkStatsService;
-import com.android.server.net.ipmemorystore.IpMemoryStoreService;
 import com.android.server.net.watchlist.NetworkWatchlistService;
 import com.android.server.notification.NotificationManagerService;
 import com.android.server.oemlock.OemLockService;
@@ -1231,6 +1230,7 @@
             }
 
             startContentCaptureService(context);
+            startAttentionService(context);
 
             // App prediction manager service
             traceBeginAndSlog("StartAppPredictionService");
@@ -1264,14 +1264,6 @@
             }
             traceEnd();
 
-            traceBeginAndSlog("StartIpMemoryStoreService");
-            try {
-                ServiceManager.addService(Context.IP_MEMORY_STORE_SERVICE,
-                        new IpMemoryStoreService(context));
-            } catch (Throwable e) {
-                reportWtf("starting IP Memory Store Service", e);
-            }
-            traceEnd();
 
             traceBeginAndSlog("StartIpSecService");
             try {
@@ -1293,10 +1285,6 @@
                 traceEnd();
             }
 
-            traceBeginAndSlog("StartAttentionManagerService");
-            mSystemServiceManager.startService(AttentionManagerService.class);
-            traceEnd();
-
             traceBeginAndSlog("StartNetworkScoreService");
             mSystemServiceManager.startService(NetworkScoreService.Lifecycle.class);
             traceEnd();
@@ -2269,6 +2257,17 @@
         traceEnd();
     }
 
+    private void startAttentionService(@NonNull Context context) {
+        if (!AttentionManagerService.isServiceConfigured(context)) {
+            Slog.d(TAG, "AttentionService is not configured on this device");
+            return;
+        }
+
+        traceBeginAndSlog("StartAttentionManagerService");
+        mSystemServiceManager.startService(AttentionManagerService.class);
+        traceEnd();
+    }
+
     static final void startSystemUi(Context context, WindowManagerService windowManager) {
         Intent intent = new Intent();
         intent.setComponent(new ComponentName("com.android.systemui",
diff --git a/services/net/Android.bp b/services/net/Android.bp
index 8ad4d76..486d15d 100644
--- a/services/net/Android.bp
+++ b/services/net/Android.bp
@@ -7,6 +7,19 @@
     ]
 }
 
+java_library_static {
+    name: "ipmemorystore-client",
+    sdk_version: "system_current",
+    srcs: [
+        ":framework-annotations",
+        "java/android/net/IpMemoryStoreClient.java",
+        "java/android/net/ipmemorystore/**.java",
+    ],
+    static_libs: [
+        "ipmemorystore-aidl-interfaces-java",
+    ]
+}
+
 filegroup {
     name: "services-networkstack-shared-srcs",
     srcs: [
diff --git a/services/net/java/android/net/IpMemoryStore.java b/services/net/java/android/net/IpMemoryStore.java
new file mode 100644
index 0000000..9248299
--- /dev/null
+++ b/services/net/java/android/net/IpMemoryStore.java
@@ -0,0 +1,62 @@
+/*
+ * 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 android.net;
+
+import android.annotation.NonNull;
+import android.content.Context;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ExecutionException;
+
+/**
+ * Manager class used to communicate with the ip memory store service in the network stack,
+ * which is running in a separate module.
+ * @hide
+*/
+public class IpMemoryStore extends IpMemoryStoreClient {
+    private final CompletableFuture<IIpMemoryStore> mService;
+
+    public IpMemoryStore(@NonNull final Context context) {
+        super(context);
+        mService = new CompletableFuture<>();
+        getNetworkStackClient().fetchIpMemoryStore(
+                new IIpMemoryStoreCallbacks.Stub() {
+                    @Override
+                    public void onIpMemoryStoreFetched(final IIpMemoryStore memoryStore) {
+                        mService.complete(memoryStore);
+                    }
+                });
+    }
+
+    @Override
+    protected IIpMemoryStore getService() throws InterruptedException, ExecutionException {
+        return mService.get();
+    }
+
+    @VisibleForTesting
+    protected NetworkStackClient getNetworkStackClient() {
+        return NetworkStackClient.getInstance();
+    }
+
+    /** Gets an instance of the memory store */
+    @NonNull
+    public static IpMemoryStore getMemoryStore(final Context context) {
+        return new IpMemoryStore(context);
+    }
+}
diff --git a/core/java/android/net/IpMemoryStore.java b/services/net/java/android/net/IpMemoryStoreClient.java
similarity index 68%
rename from core/java/android/net/IpMemoryStore.java
rename to services/net/java/android/net/IpMemoryStoreClient.java
index 2f4d9bc..2f4fdbd 100644
--- a/core/java/android/net/IpMemoryStore.java
+++ b/services/net/java/android/net/IpMemoryStoreClient.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2018 The Android Open Source Project
+ * 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.
@@ -18,7 +18,6 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.annotation.SystemService;
 import android.content.Context;
 import android.net.ipmemorystore.Blob;
 import android.net.ipmemorystore.IOnBlobRetrievedListener;
@@ -27,23 +26,34 @@
 import android.net.ipmemorystore.IOnSameNetworkResponseListener;
 import android.net.ipmemorystore.IOnStatusListener;
 import android.net.ipmemorystore.NetworkAttributes;
+import android.net.ipmemorystore.Status;
+import android.net.ipmemorystore.StatusParcelable;
 import android.os.RemoteException;
+import android.util.Log;
 
-import com.android.internal.util.Preconditions;
+import java.util.concurrent.ExecutionException;
 
 /**
- * The interface for system components to access the IP memory store.
- * @see com.android.server.net.ipmemorystore.IpMemoryStoreService
+ * service used to communicate with the ip memory store service in network stack,
+ * which is running in a separate module.
  * @hide
  */
-@SystemService(Context.IP_MEMORY_STORE_SERVICE)
-public class IpMemoryStore {
-    @NonNull final Context mContext;
-    @NonNull final IIpMemoryStore mService;
+public abstract class IpMemoryStoreClient {
+    private static final String TAG = IpMemoryStoreClient.class.getSimpleName();
+    private final Context mContext;
 
-    public IpMemoryStore(@NonNull final Context context, @NonNull final IIpMemoryStore service) {
-        mContext = Preconditions.checkNotNull(context, "missing context");
-        mService = Preconditions.checkNotNull(service, "missing IIpMemoryStore");
+    public IpMemoryStoreClient(@NonNull final Context context) {
+        if (context == null) throw new IllegalArgumentException("missing context");
+        mContext = context;
+    }
+
+    @NonNull
+    protected abstract IIpMemoryStore getService() throws InterruptedException, ExecutionException;
+
+    protected StatusParcelable internalErrorStatus() {
+        final StatusParcelable error = new StatusParcelable();
+        error.resultCode = Status.ERROR_UNKNOWN;
+        return error;
     }
 
     /**
@@ -66,9 +76,13 @@
             @NonNull final NetworkAttributes attributes,
             @Nullable final IOnStatusListener listener) {
         try {
-            mService.storeNetworkAttributes(l2Key, attributes.toParcelable(), listener);
+            try {
+                getService().storeNetworkAttributes(l2Key, attributes.toParcelable(), listener);
+            } catch (InterruptedException | ExecutionException m) {
+                listener.onComplete(internalErrorStatus());
+            }
         } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
+            Log.e(TAG, "Error storing network attributes", e);
         }
     }
 
@@ -87,9 +101,13 @@
             @NonNull final String name, @NonNull final Blob data,
             @Nullable final IOnStatusListener listener) {
         try {
-            mService.storeBlob(l2Key, clientId, name, data, listener);
+            try {
+                getService().storeBlob(l2Key, clientId, name, data, listener);
+            } catch (InterruptedException | ExecutionException m) {
+                listener.onComplete(internalErrorStatus());
+            }
         } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
+            Log.e(TAG, "Error storing blob", e);
         }
     }
 
@@ -110,9 +128,13 @@
     public void findL2Key(@NonNull final NetworkAttributes attributes,
             @NonNull final IOnL2KeyResponseListener listener) {
         try {
-            mService.findL2Key(attributes.toParcelable(), listener);
+            try {
+                getService().findL2Key(attributes.toParcelable(), listener);
+            } catch (InterruptedException | ExecutionException m) {
+                listener.onL2KeyResponse(internalErrorStatus(), null);
+            }
         } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
+            Log.e(TAG, "Error finding L2 Key", e);
         }
     }
 
@@ -128,9 +150,13 @@
     public void isSameNetwork(@NonNull final String l2Key1, @NonNull final String l2Key2,
             @NonNull final IOnSameNetworkResponseListener listener) {
         try {
-            mService.isSameNetwork(l2Key1, l2Key2, listener);
+            try {
+                getService().isSameNetwork(l2Key1, l2Key2, listener);
+            } catch (InterruptedException | ExecutionException m) {
+                listener.onSameNetworkResponse(internalErrorStatus(), null);
+            }
         } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
+            Log.e(TAG, "Error checking for network sameness", e);
         }
     }
 
@@ -146,9 +172,13 @@
     public void retrieveNetworkAttributes(@NonNull final String l2Key,
             @NonNull final IOnNetworkAttributesRetrieved listener) {
         try {
-            mService.retrieveNetworkAttributes(l2Key, listener);
+            try {
+                getService().retrieveNetworkAttributes(l2Key, listener);
+            } catch (InterruptedException | ExecutionException m) {
+                listener.onNetworkAttributesRetrieved(internalErrorStatus(), null, null);
+            }
         } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
+            Log.e(TAG, "Error retrieving network attributes", e);
         }
     }
 
@@ -166,14 +196,13 @@
     public void retrieveBlob(@NonNull final String l2Key, @NonNull final String clientId,
             @NonNull final String name, @NonNull final IOnBlobRetrievedListener listener) {
         try {
-            mService.retrieveBlob(l2Key, clientId, name, listener);
+            try {
+                getService().retrieveBlob(l2Key, clientId, name, listener);
+            } catch (InterruptedException | ExecutionException m) {
+                listener.onBlobRetrieved(internalErrorStatus(), null, null, null);
+            }
         } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
+            Log.e(TAG, "Error retrieving blob", e);
         }
     }
-
-    /** Gets an instance of the memory store */
-    public static IpMemoryStore getMemoryStore(final Context context) {
-        return (IpMemoryStore) context.getSystemService(Context.IP_MEMORY_STORE_SERVICE);
-    }
 }
diff --git a/services/net/java/android/net/NetworkStackClient.java b/services/net/java/android/net/NetworkStackClient.java
index cc09fe3..7befd087 100644
--- a/services/net/java/android/net/NetworkStackClient.java
+++ b/services/net/java/android/net/NetworkStackClient.java
@@ -130,6 +130,21 @@
         });
     }
 
+    /**
+     * Get an instance of the IpMemoryStore.
+     *
+     * <p>The IpMemoryStore will be returned asynchronously through the provided callbacks.
+     */
+    public void fetchIpMemoryStore(IIpMemoryStoreCallbacks cb) {
+        requestConnector(connector -> {
+            try {
+                connector.fetchIpMemoryStore(cb);
+            } catch (RemoteException e) {
+                e.rethrowFromSystemServer();
+            }
+        });
+    }
+
     private class NetworkStackConnection implements ServiceConnection {
         @Override
         public void onServiceConnected(ComponentName name, IBinder service) {
diff --git a/core/java/android/net/TcpKeepalivePacketData.java b/services/net/java/android/net/TcpKeepalivePacketData.java
similarity index 78%
rename from core/java/android/net/TcpKeepalivePacketData.java
rename to services/net/java/android/net/TcpKeepalivePacketData.java
index 99d36c5..d79ad1f 100644
--- a/core/java/android/net/TcpKeepalivePacketData.java
+++ b/services/net/java/android/net/TcpKeepalivePacketData.java
@@ -25,8 +25,8 @@
 import android.os.Parcelable;
 import android.system.OsConstants;
 
-import java.net.Inet4Address;
 import java.net.InetAddress;
+import java.net.UnknownHostException;
 import java.nio.ByteBuffer;
 import java.nio.ByteOrder;
 import java.util.Objects;
@@ -56,10 +56,10 @@
 
     // This should only be constructed via static factory methods, such as
     // tcpKeepalivePacket.
-    private TcpKeepalivePacketData(TcpSocketInfo tcpDetails, byte[] data)
-            throws InvalidPacketException {
-        super(tcpDetails.srcAddress, tcpDetails.srcPort, tcpDetails.dstAddress,
-                tcpDetails.dstPort, data);
+    private TcpKeepalivePacketData(final TcpKeepalivePacketDataParcelable tcpDetails,
+            final byte[] data) throws InvalidPacketException, UnknownHostException {
+        super(InetAddress.getByAddress(tcpDetails.srcAddress), tcpDetails.srcPort,
+                InetAddress.getByAddress(tcpDetails.dstAddress), tcpDetails.dstPort, data);
         tcpSeq = tcpDetails.seq;
         tcpAck = tcpDetails.ack;
         // In the packet, the window is shifted right by the window scale.
@@ -71,17 +71,22 @@
      * Factory method to create tcp keepalive packet structure.
      */
     public static TcpKeepalivePacketData tcpKeepalivePacket(
-            TcpSocketInfo tcpDetails) throws InvalidPacketException {
+            TcpKeepalivePacketDataParcelable tcpDetails) throws InvalidPacketException {
         final byte[] packet;
-        if ((tcpDetails.srcAddress instanceof Inet4Address)
-                && (tcpDetails.dstAddress instanceof Inet4Address)) {
-            packet = buildV4Packet(tcpDetails);
-        } else {
-            // TODO: support ipv6
+        try {
+            if ((tcpDetails.srcAddress != null) && (tcpDetails.dstAddress != null)
+                    && (tcpDetails.srcAddress.length == 4 /* V4 IP length */)
+                    && (tcpDetails.dstAddress.length == 4 /* V4 IP length */)) {
+                packet = buildV4Packet(tcpDetails);
+            } else {
+                // TODO: support ipv6
+                throw new InvalidPacketException(ERROR_INVALID_IP_ADDRESS);
+            }
+            return new TcpKeepalivePacketData(tcpDetails, packet);
+        } catch (UnknownHostException e) {
             throw new InvalidPacketException(ERROR_INVALID_IP_ADDRESS);
         }
 
-        return new TcpKeepalivePacketData(tcpDetails, packet);
     }
 
     /**
@@ -89,7 +94,7 @@
      */
     // TODO : if this code is ever moved to the network stack, factorize constants with the ones
     // over there.
-    private static byte[] buildV4Packet(TcpSocketInfo tcpDetails) {
+    private static byte[] buildV4Packet(TcpKeepalivePacketDataParcelable tcpDetails) {
         final int length = IPV4_HEADER_LENGTH + TCP_HEADER_LENGTH;
         ByteBuffer buf = ByteBuffer.allocate(length);
         buf.order(ByteOrder.BIG_ENDIAN);
@@ -102,8 +107,8 @@
         buf.put((byte) OsConstants.IPPROTO_TCP);
         final int ipChecksumOffset = buf.position();
         buf.putShort((short) 0);                    // IP checksum
-        buf.put(tcpDetails.srcAddress.getAddress());
-        buf.put(tcpDetails.dstAddress.getAddress());
+        buf.put(tcpDetails.srcAddress);
+        buf.put(tcpDetails.dstAddress);
         buf.putShort((short) tcpDetails.srcPort);
         buf.putShort((short) tcpDetails.dstPort);
         buf.putInt(tcpDetails.seq);                 // Sequence Number
@@ -122,31 +127,6 @@
 
     // TODO: add buildV6Packet.
 
-    /** Represents tcp/ip information. */
-    // TODO: Replace TcpSocketInfo with TcpKeepalivePacketDataParcelable.
-    public static class TcpSocketInfo {
-        public final InetAddress srcAddress;
-        public final InetAddress dstAddress;
-        public final int srcPort;
-        public final int dstPort;
-        public final int seq;
-        public final int ack;
-        public final int rcvWnd;
-        public final int rcvWndScale;
-
-        public TcpSocketInfo(InetAddress sAddr, int sPort, InetAddress dAddr,
-                int dPort, int writeSeq, int readSeq, int rWnd, int rWndScale) {
-            srcAddress = sAddr;
-            dstAddress = dAddr;
-            srcPort = sPort;
-            dstPort = dPort;
-            seq = writeSeq;
-            ack = readSeq;
-            rcvWnd = rWnd;
-            rcvWndScale = rWndScale;
-        }
-    }
-
     @Override
     public boolean equals(@Nullable final Object o) {
         if (!(o instanceof TcpKeepalivePacketData)) return false;
@@ -167,8 +147,9 @@
                 tcpWndScale);
     }
 
-    /* Parcelable Implementation. */
-    /* Note that this object implements parcelable (and needs to keep doing this as it inherits
+    /**
+     * Parcelable Implementation.
+     * Note that this object implements parcelable (and needs to keep doing this as it inherits
      * from a class that does), but should usually be parceled as a stable parcelable using
      * the toStableParcelable() and fromStableParcelable() methods.
      */
@@ -194,7 +175,7 @@
     }
 
     /** Parcelable Creator. */
-    public static final @android.annotation.NonNull Parcelable.Creator<TcpKeepalivePacketData> CREATOR =
+    public static final @NonNull Parcelable.Creator<TcpKeepalivePacketData> CREATOR =
             new Parcelable.Creator<TcpKeepalivePacketData>() {
                 public TcpKeepalivePacketData createFromParcel(Parcel in) {
                     return new TcpKeepalivePacketData(in);
@@ -217,6 +198,8 @@
         parcel.dstPort = dstPort;
         parcel.seq = tcpSeq;
         parcel.ack = tcpAck;
+        parcel.rcvWnd = tcpWnd;
+        parcel.rcvWndScale = tcpWndScale;
         return parcel;
     }
 
diff --git a/services/net/java/android/net/ip/IpServer.java b/services/net/java/android/net/ip/IpServer.java
index 0e44f88..fc1128b 100644
--- a/services/net/java/android/net/ip/IpServer.java
+++ b/services/net/java/android/net/ip/IpServer.java
@@ -506,7 +506,7 @@
         if (v6only != null) {
             params = new RaParams();
             params.mtu = v6only.getMtu();
-            params.hasDefaultRoute = v6only.hasIPv6DefaultRoute();
+            params.hasDefaultRoute = v6only.hasIpv6DefaultRoute();
 
             if (params.hasDefaultRoute) params.hopLimit = getHopLimit(v6only.getInterfaceName());
 
diff --git a/core/java/android/net/ipmemorystore/NetworkAttributes.java b/services/net/java/android/net/ipmemorystore/NetworkAttributes.java
similarity index 100%
rename from core/java/android/net/ipmemorystore/NetworkAttributes.java
rename to services/net/java/android/net/ipmemorystore/NetworkAttributes.java
diff --git a/core/java/android/net/ipmemorystore/SameL3NetworkResponse.java b/services/net/java/android/net/ipmemorystore/SameL3NetworkResponse.java
similarity index 100%
rename from core/java/android/net/ipmemorystore/SameL3NetworkResponse.java
rename to services/net/java/android/net/ipmemorystore/SameL3NetworkResponse.java
diff --git a/core/java/android/net/ipmemorystore/Status.java b/services/net/java/android/net/ipmemorystore/Status.java
similarity index 97%
rename from core/java/android/net/ipmemorystore/Status.java
rename to services/net/java/android/net/ipmemorystore/Status.java
index cacd42d..13242c0 100644
--- a/core/java/android/net/ipmemorystore/Status.java
+++ b/services/net/java/android/net/ipmemorystore/Status.java
@@ -32,6 +32,7 @@
     public static final int ERROR_ILLEGAL_ARGUMENT = -2;
     public static final int ERROR_DATABASE_CANNOT_BE_OPENED = -3;
     public static final int ERROR_STORAGE = -4;
+    public static final int ERROR_UNKNOWN = -5;
 
     public final int resultCode;
 
diff --git a/services/net/java/android/net/shared/InitialConfiguration.java b/services/net/java/android/net/shared/InitialConfiguration.java
index e423d62..007c8ca9 100644
--- a/services/net/java/android/net/shared/InitialConfiguration.java
+++ b/services/net/java/android/net/shared/InitialConfiguration.java
@@ -207,7 +207,7 @@
     }
 
     private static boolean isIPv6GUA(LinkAddress addr) {
-        return addr.isIPv6() && addr.isGlobalPreferred();
+        return addr.isIpv6() && addr.isGlobalPreferred();
     }
 
     // TODO: extract out into CollectionUtils.
diff --git a/services/robotests/backup/src/com/android/server/backup/TransportManagerTest.java b/services/robotests/backup/src/com/android/server/backup/TransportManagerTest.java
index 9a6e003..42115d4 100644
--- a/services/robotests/backup/src/com/android/server/backup/TransportManagerTest.java
+++ b/services/robotests/backup/src/com/android/server/backup/TransportManagerTest.java
@@ -554,7 +554,7 @@
                 transportManager.getTransportCurrentDestinationString(mTransportA1.transportName);
         Intent dataManagementIntent =
                 transportManager.getTransportDataManagementIntent(mTransportA1.transportName);
-        String dataManagementLabel =
+        CharSequence dataManagementLabel =
                 transportManager.getTransportDataManagementLabel(mTransportA1.transportName);
         String transportDirName = transportManager.getTransportDirName(mTransportA1.transportName);
         String transportDirNameByComponent =
diff --git a/services/robotests/backup/src/com/android/server/backup/testing/TransportData.java b/services/robotests/backup/src/com/android/server/backup/testing/TransportData.java
index 77f5d9a4..3c29810 100644
--- a/services/robotests/backup/src/com/android/server/backup/testing/TransportData.java
+++ b/services/robotests/backup/src/com/android/server/backup/testing/TransportData.java
@@ -75,7 +75,7 @@
     @Nullable public Intent configurationIntent;
     @Nullable public String currentDestinationString;
     @Nullable public Intent dataManagementIntent;
-    @Nullable public String dataManagementLabel;
+    @Nullable public CharSequence dataManagementLabel;
 
     private TransportData(
             @TransportStatus int transportStatus,
@@ -85,7 +85,7 @@
             Intent configurationIntent,
             String currentDestinationString,
             Intent dataManagementIntent,
-            String dataManagementLabel) {
+            CharSequence dataManagementLabel) {
         this.transportStatus = transportStatus;
         this.transportName = transportName;
         this.transportComponentShort = transportComponentShort;
@@ -103,7 +103,7 @@
             Intent configurationIntent,
             String currentDestinationString,
             Intent dataManagementIntent,
-            String dataManagementLabel) {
+            CharSequence dataManagementLabel) {
         this(
                 TransportStatus.REGISTERED_AVAILABLE,
                 transportName,
diff --git a/services/robotests/backup/src/com/android/server/backup/testing/TransportTestUtils.java b/services/robotests/backup/src/com/android/server/backup/testing/TransportTestUtils.java
index f6ed630..7dd5be5 100644
--- a/services/robotests/backup/src/com/android/server/backup/testing/TransportTestUtils.java
+++ b/services/robotests/backup/src/com/android/server/backup/testing/TransportTestUtils.java
@@ -188,7 +188,8 @@
             when(transportBinder.currentDestinationString())
                     .thenReturn(transport.currentDestinationString);
             when(transportBinder.dataManagementIntent()).thenReturn(transport.dataManagementIntent);
-            when(transportBinder.dataManagementLabel()).thenReturn(transport.dataManagementLabel);
+            when(transportBinder.dataManagementIntentLabel())
+                    .thenReturn(transport.dataManagementLabel);
         } catch (RemoteException e) {
             fail("RemoteException?");
         }
diff --git a/services/tests/mockingservicestests/src/com/android/server/AlarmManagerServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/AlarmManagerServiceTest.java
index 6386b3b3..7c91b64 100644
--- a/services/tests/mockingservicestests/src/com/android/server/AlarmManagerServiceTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/AlarmManagerServiceTest.java
@@ -15,7 +15,10 @@
  */
 package com.android.server;
 
+import static android.app.AlarmManager.ELAPSED_REALTIME;
 import static android.app.AlarmManager.ELAPSED_REALTIME_WAKEUP;
+import static android.app.AlarmManager.RTC;
+import static android.app.AlarmManager.RTC_WAKEUP;
 import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_ACTIVE;
 import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_FREQUENT;
 import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_RARE;
@@ -254,14 +257,22 @@
     }
 
     private void setTestAlarm(int type, long triggerTime, PendingIntent operation) {
+        setTestAlarm(type, triggerTime, operation, TEST_CALLING_UID);
+    }
+
+    private void setTestAlarm(int type, long triggerTime, PendingIntent operation, int callingUid) {
         mService.setImpl(type, triggerTime, AlarmManager.WINDOW_EXACT, 0,
                 operation, null, "test", AlarmManager.FLAG_STANDALONE, null, null,
-                TEST_CALLING_UID, TEST_CALLING_PACKAGE);
+                callingUid, TEST_CALLING_PACKAGE);
     }
 
     private PendingIntent getNewMockPendingIntent() {
+        return getNewMockPendingIntent(TEST_CALLING_UID);
+    }
+
+    private PendingIntent getNewMockPendingIntent(int mockUid) {
         final PendingIntent mockPi = mock(PendingIntent.class, Answers.RETURNS_DEEP_STUBS);
-        when(mockPi.getCreatorUid()).thenReturn(TEST_CALLING_UID);
+        when(mockPi.getCreatorUid()).thenReturn(mockUid);
         when(mockPi.getCreatorPackage()).thenReturn(TEST_CALLING_PACKAGE);
         return mockPi;
     }
@@ -724,6 +735,91 @@
         verify(mMockContext).sendBroadcastAsUser(mService.mTimeTickIntent, UserHandle.ALL);
     }
 
+    @Test
+    public void alarmCountKeyedOnCallingUid() {
+        final int mockCreatorUid = 431412;
+        final PendingIntent pi = getNewMockPendingIntent(mockCreatorUid);
+        setTestAlarm(ELAPSED_REALTIME, mNowElapsedTest + 5, pi);
+        assertEquals(1, mService.mAlarmsPerUid.get(TEST_CALLING_UID));
+        assertEquals(-1, mService.mAlarmsPerUid.get(mockCreatorUid, -1));
+    }
+
+    @Test
+    public void alarmCountOnSet() {
+        final int numAlarms = 103;
+        final int[] types = {RTC_WAKEUP, RTC, ELAPSED_REALTIME_WAKEUP, ELAPSED_REALTIME};
+        for (int i = 1; i <= numAlarms; i++) {
+            setTestAlarm(types[i % 4], mNowElapsedTest + i, getNewMockPendingIntent());
+            assertEquals(i, mService.mAlarmsPerUid.get(TEST_CALLING_UID));
+        }
+    }
+
+    @Test
+    public void alarmCountOnExpiration() throws InterruptedException {
+        final int numAlarms = 8; // This test is slow
+        for (int i = 0; i < numAlarms; i++) {
+            setTestAlarm(ELAPSED_REALTIME, mNowElapsedTest + i + 10, getNewMockPendingIntent());
+        }
+        int expired = 0;
+        while (expired < numAlarms) {
+            mNowElapsedTest = mTestTimer.getElapsed();
+            mTestTimer.expire();
+            expired++;
+            assertEquals(numAlarms - expired, mService.mAlarmsPerUid.get(TEST_CALLING_UID, 0));
+        }
+    }
+
+    @Test
+    public void alarmCountOnUidRemoved() {
+        final int numAlarms = 10;
+        for (int i = 0; i < numAlarms; i++) {
+            setTestAlarm(ELAPSED_REALTIME, mNowElapsedTest + i + 10, getNewMockPendingIntent());
+        }
+        assertEquals(numAlarms, mService.mAlarmsPerUid.get(TEST_CALLING_UID));
+        mService.removeLocked(TEST_CALLING_UID);
+        assertEquals(0, mService.mAlarmsPerUid.get(TEST_CALLING_UID, 0));
+    }
+
+    @Test
+    public void alarmCountOnPackageRemoved() {
+        final int numAlarms = 10;
+        for (int i = 0; i < numAlarms; i++) {
+            setTestAlarm(ELAPSED_REALTIME, mNowElapsedTest + i + 10, getNewMockPendingIntent());
+        }
+        assertEquals(numAlarms, mService.mAlarmsPerUid.get(TEST_CALLING_UID));
+        mService.removeLocked(TEST_CALLING_PACKAGE);
+        assertEquals(0, mService.mAlarmsPerUid.get(TEST_CALLING_UID, 0));
+    }
+
+    @Test
+    public void alarmCountOnUserRemoved() {
+        final int mockUserId = 15;
+        final int numAlarms = 10;
+        for (int i = 0; i < numAlarms; i++) {
+            int mockUid = UserHandle.getUid(mockUserId, 1234 + i);
+            setTestAlarm(ELAPSED_REALTIME, mNowElapsedTest + i + 10,
+                    getNewMockPendingIntent(mockUid), mockUid);
+        }
+        assertEquals(numAlarms, mService.mAlarmsPerUid.size());
+        mService.removeUserLocked(mockUserId);
+        assertEquals(0, mService.mAlarmsPerUid.size());
+    }
+
+    @Test
+    public void alarmCountOnAlarmRemoved() {
+        final int numAlarms = 10;
+        final PendingIntent[] pis = new PendingIntent[numAlarms];
+        for (int i = 0; i < numAlarms; i++) {
+            pis[i] = getNewMockPendingIntent();
+            setTestAlarm(ELAPSED_REALTIME, mNowElapsedTest + i + 5, pis[i]);
+        }
+        assertEquals(numAlarms, mService.mAlarmsPerUid.get(TEST_CALLING_UID));
+        for (int i = 0; i < numAlarms; i++) {
+            mService.removeLocked(pis[i], null);
+            assertEquals(numAlarms - i - 1, mService.mAlarmsPerUid.get(TEST_CALLING_UID, 0));
+        }
+    }
+
     @After
     public void tearDown() {
         if (mMockingSession != null) {
diff --git a/services/tests/mockingservicestests/src/com/android/server/job/controllers/ConnectivityControllerTest.java b/services/tests/mockingservicestests/src/com/android/server/job/controllers/ConnectivityControllerTest.java
index 8e78a56..c45122e 100644
--- a/services/tests/mockingservicestests/src/com/android/server/job/controllers/ConnectivityControllerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/job/controllers/ConnectivityControllerTest.java
@@ -52,6 +52,7 @@
 import android.net.NetworkInfo.DetailedState;
 import android.net.NetworkPolicyManager;
 import android.os.Build;
+import android.os.Looper;
 import android.os.SystemClock;
 import android.util.DataUnit;
 
@@ -102,6 +103,8 @@
         LocalServices.removeServiceForTest(NetworkPolicyManagerInternal.class);
         LocalServices.addService(NetworkPolicyManagerInternal.class, mNetPolicyManagerInternal);
 
+        when(mContext.getMainLooper()).thenReturn(Looper.getMainLooper());
+
         // Freeze the clocks at this moment in time
         JobSchedulerService.sSystemClock =
                 Clock.fixed(Clock.systemUTC().instant(), ZoneOffset.UTC);
diff --git a/services/tests/mockingservicestests/src/com/android/server/power/batterysaver/BatterySaverStateMachineTest.java b/services/tests/mockingservicestests/src/com/android/server/power/batterysaver/BatterySaverStateMachineTest.java
index 86e8598..2e5efbd 100644
--- a/services/tests/mockingservicestests/src/com/android/server/power/batterysaver/BatterySaverStateMachineTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/power/batterysaver/BatterySaverStateMachineTest.java
@@ -28,6 +28,7 @@
 import android.content.ContentResolver;
 import android.content.Context;
 import android.content.res.Resources;
+import android.os.PowerManager;
 import android.provider.Settings.Global;
 
 import androidx.test.filters.SmallTest;
@@ -452,6 +453,21 @@
         assertEquals(true, mDevice.batterySaverEnabled);
         assertEquals(30, mPersistedState.batteryLevel);
         assertEquals(true, mPersistedState.batteryLow);
+
+        // Disable auto battery saver.
+        mDevice.putGlobalSetting(Global.LOW_POWER_MODE_TRIGGER_LEVEL, 0);
+        mDevice.setBatteryLevel(25);
+
+        assertEquals(false, mDevice.batterySaverEnabled);
+        assertEquals(25, mPersistedState.batteryLevel);
+        assertEquals(false, mPersistedState.batteryLow);
+
+        // PowerManager sets batteryLow to true at 15% if battery saver trigger level is lower.
+        mDevice.setBatteryLevel(15);
+
+        assertEquals(false, mDevice.batterySaverEnabled);
+        assertEquals(15, mPersistedState.batteryLevel);
+        assertEquals(true, mPersistedState.batteryLow);
     }
 
     @Test
@@ -542,6 +558,12 @@
         assertEquals(100, mPersistedState.batteryLevel);
         assertEquals(false, mPersistedState.batteryLow);
 
+        mDevice.setBatteryLevel(97);
+
+        assertEquals(true, mDevice.batterySaverEnabled); // Stays on.
+        assertEquals(97, mPersistedState.batteryLevel);
+        assertEquals(false, mPersistedState.batteryLow);
+
         mDevice.setBatteryLevel(95);
 
         assertEquals(true, mDevice.batterySaverEnabled); // Stays on.
@@ -719,6 +741,48 @@
     }
 
     @Test
+    public void testAutoBatterySaver_withSticky_withAutoOffToggled() {
+        mDevice.putGlobalSetting(Global.LOW_POWER_MODE_TRIGGER_LEVEL, 50);
+        mDevice.putGlobalSetting(Global.LOW_POWER_MODE_STICKY_AUTO_DISABLE_ENABLED, 1);
+        mDevice.putGlobalSetting(Global.LOW_POWER_MODE_STICKY_AUTO_DISABLE_LEVEL, 90);
+
+        // Scenario 1: User turns BS on manually above the threshold, it shouldn't turn off even
+        // with battery level change above threshold.
+        mDevice.setBatteryLevel(100);
+        mTarget.setBatterySaverEnabledManually(true);
+
+        assertEquals(true, mDevice.batterySaverEnabled);
+        assertEquals(100, mPersistedState.batteryLevel);
+        assertEquals(false, mPersistedState.batteryLow);
+
+        mDevice.setBatteryLevel(95);
+
+        assertEquals(true, mDevice.batterySaverEnabled); // Stays on.
+        assertEquals(95, mPersistedState.batteryLevel);
+        assertEquals(false, mPersistedState.batteryLow);
+
+        // Disable auto disable while in the pending sticky state. BS should reactivate after
+        // unplug.
+        mDevice.setPowered(true);
+        mDevice.putGlobalSetting(Global.LOW_POWER_MODE_STICKY_AUTO_DISABLE_ENABLED, 0);
+        mDevice.setPowered(false);
+
+        assertEquals(true, mDevice.batterySaverEnabled); // Sticky BS should activate.
+        assertEquals(95, mPersistedState.batteryLevel);
+        assertEquals(false, mPersistedState.batteryLow);
+
+        // Enable auto disable while in the pending sticky state. Sticky should turn off after
+        // unplug.
+        mDevice.setPowered(true);
+        mDevice.putGlobalSetting(Global.LOW_POWER_MODE_STICKY_AUTO_DISABLE_ENABLED, 1);
+        mDevice.setPowered(false);
+
+        assertEquals(false, mDevice.batterySaverEnabled); // Sticky BS no longer enabled.
+        assertEquals(95, mPersistedState.batteryLevel);
+        assertEquals(false, mPersistedState.batteryLow);
+    }
+
+    @Test
     public void testAutoBatterySaver_withStickyDisabled() {
         when(mMockResources.getBoolean(
                 com.android.internal.R.bool.config_batterySaverStickyBehaviourDisabled))
@@ -739,7 +803,9 @@
         assertEquals(30, mPersistedState.batteryLevel);
         assertEquals(true, mPersistedState.batteryLow);
 
+        mDevice.setPowered(true);
         mDevice.setBatteryLevel(80);
+        mDevice.setPowered(false);
 
         assertEquals(false, mDevice.batterySaverEnabled); // Not sticky.
         assertEquals(80, mPersistedState.batteryLevel);
@@ -830,10 +896,9 @@
         assertEquals(90, mPersistedState.batteryLevel);
         assertEquals(false, mPersistedState.batteryLow);
 
-        // Reboot -- setting BS from adb is also sticky.
+        // Reboot -- LOW_POWER_MODE shouldn't be persisted.
         initDevice();
-
-        assertEquals(true, mDevice.batterySaverEnabled);
+        assertEquals(false, mDevice.batterySaverEnabled);
         assertEquals(90, mPersistedState.batteryLevel);
         assertEquals(false, mPersistedState.batteryLow);
     }
@@ -841,7 +906,8 @@
     @Test
     public void testAutoBatterySaver_smartBatterySaverEnabled() {
         mDevice.putGlobalSetting(Global.DYNAMIC_POWER_SAVINGS_DISABLE_THRESHOLD, 50);
-        mDevice.putGlobalSetting(Global.AUTOMATIC_POWER_SAVER_MODE, 1);
+        mDevice.putGlobalSetting(Global.AUTOMATIC_POWER_SAVER_MODE,
+                PowerManager.POWER_SAVER_MODE_DYNAMIC);
         mDevice.putGlobalSetting(Global.DYNAMIC_POWER_SAVINGS_ENABLED, 0);
 
         assertEquals(false, mDevice.batterySaverEnabled);
@@ -922,8 +988,8 @@
         mDevice.putGlobalSetting(Global.DYNAMIC_POWER_SAVINGS_DISABLE_THRESHOLD, 71);
         mDevice.setBatteryLevel(mPersistedState.batteryLevel);
 
-        // changes are only registered if some battery level changed
-        assertEquals(false, mDevice.batterySaverEnabled);
+        // Changes should register immediately.
+        assertEquals(true, mDevice.batterySaverEnabled);
         assertEquals(70, mPersistedState.batteryLevel);
 
         mDevice.setBatteryLevel(69);
@@ -935,8 +1001,8 @@
         mDevice.putGlobalSetting(Global.DYNAMIC_POWER_SAVINGS_DISABLE_THRESHOLD, 60);
         mDevice.setBatteryLevel(mPersistedState.batteryLevel);
 
-        // changes are only registered if battery level changed
-        assertEquals(true, mDevice.batterySaverEnabled);
+        // Changes should register immediately.
+        assertEquals(false, mDevice.batterySaverEnabled);
         assertEquals(69, mPersistedState.batteryLevel);
 
         mDevice.setBatteryLevel(68);
@@ -956,4 +1022,220 @@
         assertEquals(true, mDevice.batterySaverEnabled);
         assertEquals(30, mPersistedState.batteryLevel);
     }
+
+    @Test
+    public void testAutoBatterySaver_snoozed_autoEnabled() {
+        mDevice.putGlobalSetting(Global.LOW_POWER_MODE_TRIGGER_LEVEL, 30);
+        // Test dynamic threshold higher than automatic to make sure it doesn't interfere when it's
+        // not enabled.
+        mDevice.putGlobalSetting(Global.DYNAMIC_POWER_SAVINGS_DISABLE_THRESHOLD, 50);
+        mDevice.putGlobalSetting(Global.AUTOMATIC_POWER_SAVER_MODE,
+                PowerManager.POWER_SAVER_MODE_PERCENTAGE);
+        mDevice.putGlobalSetting(Global.DYNAMIC_POWER_SAVINGS_ENABLED, 0);
+
+        assertEquals(false, mDevice.batterySaverEnabled);
+        assertEquals(100, mPersistedState.batteryLevel);
+
+        mDevice.setBatteryLevel(90);
+
+        assertEquals(false, mDevice.batterySaverEnabled);
+        assertEquals(90, mPersistedState.batteryLevel);
+
+        mDevice.setBatteryLevel(51);
+
+        assertEquals(false, mDevice.batterySaverEnabled);
+        assertEquals(51, mPersistedState.batteryLevel);
+
+        // Hit dynamic threshold. BS should be disabled since dynamic is off
+        mDevice.setBatteryLevel(50);
+
+        assertEquals(false, mDevice.batterySaverEnabled);
+        assertEquals(50, mPersistedState.batteryLevel);
+
+        mDevice.setBatteryLevel(30);
+
+        assertEquals(true, mDevice.batterySaverEnabled);
+        assertEquals(30, mPersistedState.batteryLevel);
+
+        mDevice.setPowered(true);
+
+        assertEquals(false, mDevice.batterySaverEnabled);
+        assertEquals(30, mPersistedState.batteryLevel);
+
+        mDevice.setPowered(false);
+
+        assertEquals(true, mDevice.batterySaverEnabled);
+        assertEquals(30, mPersistedState.batteryLevel);
+
+        mTarget.setBatterySaverEnabledManually(false); // Manually disable -> snooze.
+
+        assertEquals(false, mDevice.batterySaverEnabled);
+        assertEquals(30, mPersistedState.batteryLevel);
+
+        mDevice.setBatteryLevel(20);
+
+        assertEquals(false, mDevice.batterySaverEnabled);
+        assertEquals(20, mPersistedState.batteryLevel);
+
+        // Lower threshold. Level is still below, so should still be snoozed.
+        mDevice.putGlobalSetting(Global.LOW_POWER_MODE_TRIGGER_LEVEL, 25);
+
+        assertEquals(false, mDevice.batterySaverEnabled);
+        assertEquals(20, mPersistedState.batteryLevel);
+
+        // Lower threshold even more. Battery no longer considered "low" so snoozing should be
+        // disabled.
+        mDevice.putGlobalSetting(Global.LOW_POWER_MODE_TRIGGER_LEVEL, 10);
+        // "batteryLow" is set in setBatteryLevel.
+        mDevice.setBatteryLevel(19);
+
+        assertEquals(false, mDevice.batterySaverEnabled);
+        assertEquals(19, mPersistedState.batteryLevel);
+
+        mDevice.setBatteryLevel(10);
+
+        assertEquals(true, mDevice.batterySaverEnabled); // No longer snoozing.
+        assertEquals(10, mPersistedState.batteryLevel);
+
+        mTarget.setBatterySaverEnabledManually(false); // Manually disable -> snooze.
+
+        // Plug in and out, snooze will reset.
+        mDevice.setPowered(true);
+        mDevice.setPowered(false);
+
+        assertEquals(true, mDevice.batterySaverEnabled);
+        assertEquals(10, mPersistedState.batteryLevel);
+
+        mDevice.setPowered(true);
+        mDevice.setBatteryLevel(60);
+
+        assertEquals(false, mDevice.batterySaverEnabled);
+        assertEquals(60, mPersistedState.batteryLevel);
+
+        // Test toggling resets snooze.
+        mDevice.putGlobalSetting(Global.LOW_POWER_MODE_TRIGGER_LEVEL, 50);
+        mDevice.setPowered(false);
+        mDevice.setBatteryLevel(45);
+
+        assertEquals(true, mDevice.batterySaverEnabled);
+        assertEquals(45, mPersistedState.batteryLevel);
+
+        mTarget.setBatterySaverEnabledManually(false); // Manually disable -> snooze.
+        assertEquals(false, mDevice.batterySaverEnabled);
+        assertEquals(45, mPersistedState.batteryLevel);
+
+        // Disable and re-enable.
+        mDevice.putGlobalSetting(Global.LOW_POWER_MODE_TRIGGER_LEVEL, 0);
+        mDevice.putGlobalSetting(Global.LOW_POWER_MODE_TRIGGER_LEVEL, 50);
+
+        assertEquals(true, mDevice.batterySaverEnabled); // Snooze reset
+        assertEquals(45, mPersistedState.batteryLevel);
+    }
+
+    @Test
+    public void testAutoBatterySaver_snoozed_dynamicEnabled() {
+        // Test auto threshold higher than dynamic to make sure it doesn't interfere when it's
+        // not enabled.
+        mDevice.putGlobalSetting(Global.LOW_POWER_MODE_TRIGGER_LEVEL, 50);
+        mDevice.putGlobalSetting(Global.DYNAMIC_POWER_SAVINGS_DISABLE_THRESHOLD, 30);
+        mDevice.putGlobalSetting(Global.AUTOMATIC_POWER_SAVER_MODE,
+                PowerManager.POWER_SAVER_MODE_DYNAMIC);
+        mDevice.putGlobalSetting(Global.DYNAMIC_POWER_SAVINGS_ENABLED, 1);
+
+        assertEquals(false, mDevice.batterySaverEnabled);
+        assertEquals(100, mPersistedState.batteryLevel);
+
+        mDevice.setBatteryLevel(90);
+
+        assertEquals(false, mDevice.batterySaverEnabled);
+        assertEquals(90, mPersistedState.batteryLevel);
+
+        mDevice.setBatteryLevel(51);
+
+        assertEquals(false, mDevice.batterySaverEnabled);
+        assertEquals(51, mPersistedState.batteryLevel);
+
+        // Hit automatic threshold. BS should be disabled since automatic is off
+        mDevice.setBatteryLevel(50);
+
+        assertEquals(false, mDevice.batterySaverEnabled);
+        assertEquals(50, mPersistedState.batteryLevel);
+
+        mDevice.setBatteryLevel(30);
+
+        assertEquals(true, mDevice.batterySaverEnabled);
+        assertEquals(30, mPersistedState.batteryLevel);
+
+        mDevice.setPowered(true);
+
+        assertEquals(false, mDevice.batterySaverEnabled);
+        assertEquals(30, mPersistedState.batteryLevel);
+
+        mDevice.setPowered(false);
+
+        assertEquals(true, mDevice.batterySaverEnabled);
+        assertEquals(30, mPersistedState.batteryLevel);
+
+        mTarget.setBatterySaverEnabledManually(false); // Manually disable -> snooze.
+
+        assertEquals(false, mDevice.batterySaverEnabled);
+        assertEquals(30, mPersistedState.batteryLevel);
+
+        mDevice.setBatteryLevel(20);
+
+        assertEquals(false, mDevice.batterySaverEnabled);
+        assertEquals(20, mPersistedState.batteryLevel);
+
+        // Lower threshold. Level is still below, so should still be snoozed.
+        mDevice.putGlobalSetting(Global.DYNAMIC_POWER_SAVINGS_DISABLE_THRESHOLD, 25);
+
+        assertEquals(false, mDevice.batterySaverEnabled);
+        assertEquals(20, mPersistedState.batteryLevel);
+
+        // Lower threshold even more. Battery no longer considered "low" so snoozing should be
+        // disabled.
+        mDevice.putGlobalSetting(Global.DYNAMIC_POWER_SAVINGS_DISABLE_THRESHOLD, 10);
+
+        assertEquals(false, mDevice.batterySaverEnabled);
+        assertEquals(20, mPersistedState.batteryLevel);
+
+        mDevice.setBatteryLevel(10);
+
+        assertEquals(true, mDevice.batterySaverEnabled); // No longer snoozing.
+        assertEquals(10, mPersistedState.batteryLevel);
+
+        mTarget.setBatterySaverEnabledManually(false); // Manually disable -> snooze.
+
+        // Plug in and out, snooze will reset.
+        mDevice.setPowered(true);
+        mDevice.setPowered(false);
+
+        assertEquals(true, mDevice.batterySaverEnabled);
+        assertEquals(10, mPersistedState.batteryLevel);
+
+        mDevice.setPowered(true);
+        mDevice.setBatteryLevel(60);
+
+        assertEquals(false, mDevice.batterySaverEnabled);
+        assertEquals(60, mPersistedState.batteryLevel);
+
+        // Test toggling resets snooze.
+        mDevice.putGlobalSetting(Global.DYNAMIC_POWER_SAVINGS_DISABLE_THRESHOLD, 50);
+        mDevice.setPowered(false);
+        mDevice.setBatteryLevel(45);
+
+        assertEquals(true, mDevice.batterySaverEnabled);
+        assertEquals(45, mPersistedState.batteryLevel);
+
+        mTarget.setBatterySaverEnabledManually(false); // Manually disable -> snooze.
+        assertEquals(false, mDevice.batterySaverEnabled);
+        assertEquals(45, mPersistedState.batteryLevel);
+
+        // Disable and re-enable.
+        mDevice.putGlobalSetting(Global.DYNAMIC_POWER_SAVINGS_ENABLED, 0);
+        mDevice.putGlobalSetting(Global.DYNAMIC_POWER_SAVINGS_ENABLED, 1);
+
+        assertEquals(true, mDevice.batterySaverEnabled); // Snooze reset
+        assertEquals(45, mPersistedState.batteryLevel);
+    }
 }
diff --git a/services/tests/servicestests/src/com/android/server/am/MemoryStatUtilTest.java b/services/tests/servicestests/src/com/android/server/am/MemoryStatUtilTest.java
index 71b4397..5fb762e 100644
--- a/services/tests/servicestests/src/com/android/server/am/MemoryStatUtilTest.java
+++ b/services/tests/servicestests/src/com/android/server/am/MemoryStatUtilTest.java
@@ -310,6 +310,8 @@
     @Test
     public void testParseIonHeapSizeFromDebugfs_invalidValue() {
         assertEquals(0, parseIonHeapSizeFromDebugfs("<<no-value>>"));
+
+        assertEquals(0, parseIonHeapSizeFromDebugfs("\ntotal 12345678901234567890\n"));
     }
 
     @Test
diff --git a/services/tests/servicestests/src/com/android/server/backup/TrampolineTest.java b/services/tests/servicestests/src/com/android/server/backup/TrampolineTest.java
index 3e5ce46..dd79aad 100644
--- a/services/tests/servicestests/src/com/android/server/backup/TrampolineTest.java
+++ b/services/tests/servicestests/src/com/android/server/backup/TrampolineTest.java
@@ -82,7 +82,7 @@
     private static final String CURRENT_PASSWORD = "current_password";
     private static final String NEW_PASSWORD = "new_password";
     private static final String ENCRYPTION_PASSWORD = "encryption_password";
-    private static final String DATA_MANAGEMENT_LABEL = "data_management_label";
+    private static final CharSequence DATA_MANAGEMENT_LABEL = "data_management_label";
     private static final String DESTINATION_STRING = "destination_string";
     private static final String[] PACKAGE_NAMES =
             new String[]{"some.package.name._1", "some.package.name._2"};
@@ -1104,8 +1104,8 @@
     }
 
     @Test
-    public void getDataManagementLabel_calledBeforeInitialize_ignored() throws Exception {
-        assertNull(mTrampoline.getDataManagementLabel(TRANSPORT_NAME));
+    public void getDataManagementLabelForUser_calledBeforeInitialize_ignored() throws Exception {
+        assertNull(mTrampoline.getDataManagementLabelForUser(mUserId, TRANSPORT_NAME));
         verifyNoMoreInteractions(mBackupManagerServiceMock);
     }
 
@@ -1122,17 +1122,6 @@
     }
 
     @Test
-    public void getDataManagementLabel_forwarded() throws Exception {
-        TrampolineTestable.sCallingUserId = mUserId;
-        when(mBackupManagerServiceMock.getDataManagementLabel(mUserId, TRANSPORT_NAME)).thenReturn(
-                DATA_MANAGEMENT_LABEL);
-        mTrampoline.initializeService();
-
-        assertEquals(DATA_MANAGEMENT_LABEL, mTrampoline.getDataManagementLabel(TRANSPORT_NAME));
-        verify(mBackupManagerServiceMock).getDataManagementLabel(mUserId, TRANSPORT_NAME);
-    }
-
-    @Test
     public void beginRestoreSession_calledBeforeInitialize_ignored() throws Exception {
         mTrampoline.beginRestoreSessionForUser(mUserId, PACKAGE_NAME, TRANSPORT_NAME);
         verifyNoMoreInteractions(mBackupManagerServiceMock);
diff --git a/services/tests/servicestests/src/com/android/server/backup/testutils/IPackageManagerStub.java b/services/tests/servicestests/src/com/android/server/backup/testutils/IPackageManagerStub.java
index 26b1224..caf6c9c 100644
--- a/services/tests/servicestests/src/com/android/server/backup/testutils/IPackageManagerStub.java
+++ b/services/tests/servicestests/src/com/android/server/backup/testutils/IPackageManagerStub.java
@@ -1138,7 +1138,7 @@
     }
 
     @Override
-    public String getContentCaptureServicePackageName() throws RemoteException {
+    public String getSystemCaptionsServicePackageName() throws RemoteException {
         return null;
     }
 
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/SyntheticPasswordTests.java b/services/tests/servicestests/src/com/android/server/locksettings/SyntheticPasswordTests.java
index 77515258..6a07a45 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/SyntheticPasswordTests.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/SyntheticPasswordTests.java
@@ -338,12 +338,15 @@
         initializeCredentialUnderSP(password, PRIMARY_USER_ID);
         final byte[] storageKey = mStorageManager.getUserUnlockToken(PRIMARY_USER_ID);
 
+        assertFalse(mService.hasPendingEscrowToken(PRIMARY_USER_ID));
         long handle = mLocalService.addEscrowToken(token, PRIMARY_USER_ID, null);
         assertFalse(mLocalService.isEscrowTokenActive(handle, PRIMARY_USER_ID));
+        assertTrue(mService.hasPendingEscrowToken(PRIMARY_USER_ID));
 
         mService.verifyCredential(password, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0,
                 PRIMARY_USER_ID).getResponseCode();
         assertTrue(mLocalService.isEscrowTokenActive(handle, PRIMARY_USER_ID));
+        assertFalse(mService.hasPendingEscrowToken(PRIMARY_USER_ID));
 
         mLocalService.setLockCredentialWithToken(pattern, LockPatternUtils.CREDENTIAL_TYPE_PATTERN,
                 handle, token, PASSWORD_QUALITY_SOMETHING, PRIMARY_USER_ID);
diff --git a/services/tests/servicestests/src/com/android/server/pm/LauncherAppsServiceTest.java b/services/tests/servicestests/src/com/android/server/pm/LauncherAppsServiceTest.java
deleted file mode 100644
index d7dc58d..0000000
--- a/services/tests/servicestests/src/com/android/server/pm/LauncherAppsServiceTest.java
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.pm;
-
-import static org.junit.Assert.assertEquals;
-
-import android.content.pm.PackageParser;
-import android.content.pm.Signature;
-import android.content.pm.SigningInfo;
-import android.platform.test.annotations.Presubmit;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.junit.MockitoJUnitRunner;
-
-@Presubmit
-@RunWith(MockitoJUnitRunner.class)
-public class LauncherAppsServiceTest {
-
-    private static final Signature SIGNATURE_1 = new Signature(new byte[]{0x00, 0x01, 0x02, 0x03});
-    private static final Signature SIGNATURE_2 = new Signature(new byte[]{0x04, 0x05, 0x06, 0x07});
-    private static final Signature SIGNATURE_3 = new Signature(new byte[]{0x08, 0x09, 0x10, 0x11});
-
-    @Test
-    public void testComputePackageCertDigest() {
-        String digest = LauncherAppsService.LauncherAppsImpl.computePackageCertDigest(SIGNATURE_1);
-        assertEquals("A02A05B025B928C039CF1AE7E8EE04E7C190C0DB", digest);
-    }
-
-    @Test
-    public void testGetLatestSignaturesWithSingleCert() {
-        SigningInfo signingInfo = new SigningInfo(
-                new PackageParser.SigningDetails(
-                        new Signature[]{SIGNATURE_1},
-                        PackageParser.SigningDetails.SignatureSchemeVersion.SIGNING_BLOCK_V3,
-                        null,
-                        null));
-        Signature[] signatures = LauncherAppsService.LauncherAppsImpl.getLatestSignatures(
-                signingInfo);
-        assertEquals(1, signatures.length);
-        assertEquals(SIGNATURE_1, signatures[0]);
-    }
-
-    @Test
-    public void testGetLatestSignaturesWithMultiCert() {
-        SigningInfo signingInfo = new SigningInfo(
-                new PackageParser.SigningDetails(
-                        new Signature[]{SIGNATURE_1, SIGNATURE_2},
-                        PackageParser.SigningDetails.SignatureSchemeVersion.SIGNING_BLOCK_V3,
-                        null,
-                        null));
-        Signature[] signatures = LauncherAppsService.LauncherAppsImpl.getLatestSignatures(
-                signingInfo);
-        assertEquals(2, signatures.length);
-        assertEquals(SIGNATURE_1, signatures[0]);
-        assertEquals(SIGNATURE_2, signatures[1]);
-    }
-
-    @Test
-    public void testGetLatestSignaturesWithCertHistory() {
-        SigningInfo signingInfo = new SigningInfo(
-                new PackageParser.SigningDetails(
-                        new Signature[]{SIGNATURE_1},
-                        PackageParser.SigningDetails.SignatureSchemeVersion.SIGNING_BLOCK_V3,
-                        null,
-                        new Signature[]{SIGNATURE_2, SIGNATURE_3}));
-        Signature[] signatures = LauncherAppsService.LauncherAppsImpl.getLatestSignatures(
-                signingInfo);
-        assertEquals(1, signatures.length);
-        assertEquals(SIGNATURE_2, signatures[0]);
-    }
-
-}
diff --git a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java
index 9504381..fa1bcac 100644
--- a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java
+++ b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java
@@ -35,6 +35,7 @@
 import android.app.Person;
 import android.content.ComponentName;
 import android.content.Intent;
+import android.content.LocusId;
 import android.content.pm.ShortcutInfo;
 import android.content.res.Resources;
 import android.graphics.BitmapFactory;
@@ -250,7 +251,7 @@
                 .setCategories(set(ShortcutInfo.SHORTCUT_CATEGORY_CONVERSATION, "xyz"))
                 .setRank(123)
                 .setPerson(makePerson("person", "personKey", "personUri"))
-                .setLongLived()
+                .setLongLived(true)
                 .setExtras(pb)
                 .build();
         si.addFlags(ShortcutInfo.FLAG_PINNED);
@@ -352,7 +353,7 @@
                 .setIntent(makeIntent("action", ShortcutActivity.class, "key", "val"))
                 .setRank(123)
                 .setPerson(makePerson("person", "personKey", "personUri"))
-                .setLongLived()
+                .setLongLived(true)
                 .setExtras(pb)
                 .build();
         sorig.addFlags(ShortcutInfo.FLAG_PINNED);
@@ -895,6 +896,7 @@
                 .setIntent(makeIntent("action", ShortcutActivity.class, "key", "val"))
                 .setRank(123)
                 .setExtras(pb)
+                .setLocusId(new LocusId("1.2.3.4.5"))
                 .build();
         sorig.setTimestamp(mInjectedCurrentTimeMillis);
 
@@ -906,6 +908,7 @@
                 .setPersons(list(makePerson("person1", "personKey1", "personUri1"),
                         makePerson("person2", "personKey2", "personUri2")).toArray(new Person[2]))
                 .setRank(456)
+                .setLocusId(new LocusId("6.7.8.9"))
                 .build();
         sorig2.setTimestamp(mInjectedCurrentTimeMillis);
 
@@ -946,6 +949,7 @@
         assertEquals("personUri", si.getPersons()[0].getUri());
         assertEquals(0, si.getRank());
         assertEquals(1, si.getExtras().getInt("k"));
+        assertEquals("1.2.3.4.5", si.getLocusId().getId());
 
         assertEquals(ShortcutInfo.FLAG_DYNAMIC | ShortcutInfo.FLAG_HAS_ICON_FILE
                 | ShortcutInfo.FLAG_STRINGS_RESOLVED, si.getFlags());
@@ -959,6 +963,7 @@
         assertEquals(1, si.getRank());
         assertEquals(2, si.getPersons().length);
         assertEquals("personUri2", si.getPersons()[1].getUri());
+        assertEquals("6.7.8.9", si.getLocusId().getId());
 
         dumpUserFile(USER_10);
     }
diff --git a/services/tests/servicestests/src/com/android/server/power/AttentionDetectorTest.java b/services/tests/servicestests/src/com/android/server/power/AttentionDetectorTest.java
index a2f1f01..a1a58b4 100644
--- a/services/tests/servicestests/src/com/android/server/power/AttentionDetectorTest.java
+++ b/services/tests/servicestests/src/com/android/server/power/AttentionDetectorTest.java
@@ -105,6 +105,13 @@
     }
 
     @Test
+    public void testOnUserActivity_doesntCrashIfNoAttentionService() {
+        mAttentionManagerInternal = null;
+        registerAttention();
+        // Does not crash.
+    }
+
+    @Test
     public void onUserActivity_ignoresWhiteListedActivityTypes() {
         for (int i = 0; i < NUM_USER_ACTIVITY_TYPES; i++) {
             int result = mAttentionDetector.onUserActivity(SystemClock.uptimeMillis(), i);
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 6f96759..a8da80e 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -391,7 +391,8 @@
 
         mBinderService.createNotificationChannels(
                 PKG, new ParceledListSlice(Arrays.asList(mTestNotificationChannel)));
-        assertNotNull(mBinderService.getNotificationChannel(PKG, TEST_CHANNEL_ID));
+        assertNotNull(mBinderService.getNotificationChannel(
+                PKG, mContext.getUserId(), PKG, TEST_CHANNEL_ID));
     }
 
     @After
@@ -497,7 +498,7 @@
         mBinderService.createNotificationChannels(PKG,
                 new ParceledListSlice(Arrays.asList(channel)));
         final NotificationChannel createdChannel =
-                mBinderService.getNotificationChannel(PKG, "id");
+                mBinderService.getNotificationChannel(PKG, mContext.getUserId(), PKG, "id");
         assertTrue(createdChannel != null);
     }
 
@@ -520,8 +521,10 @@
                 new NotificationChannel("id2", "name", IMPORTANCE_DEFAULT);
         mBinderService.createNotificationChannels(PKG,
                 new ParceledListSlice(Arrays.asList(channel1, channel2)));
-        assertTrue(mBinderService.getNotificationChannel(PKG, "id1") != null);
-        assertTrue(mBinderService.getNotificationChannel(PKG, "id2") != null);
+        assertTrue(mBinderService.getNotificationChannel(
+                PKG, mContext.getUserId(), PKG, "id1") != null);
+        assertTrue(mBinderService.getNotificationChannel(
+                PKG, mContext.getUserId(), PKG, "id2") != null);
     }
 
     @Test
@@ -538,7 +541,7 @@
         mBinderService.createNotificationChannels(PKG,
                 new ParceledListSlice(Arrays.asList(dupeChannel)));
         final NotificationChannel createdChannel =
-                mBinderService.getNotificationChannel(PKG, "id");
+                mBinderService.getNotificationChannel(PKG, mContext.getUserId(), PKG, "id");
         assertEquals(IMPORTANCE_DEFAULT, createdChannel.getImportance());
     }
 
@@ -556,7 +559,7 @@
         mBinderService.createNotificationChannels(PKG,
                 new ParceledListSlice(Arrays.asList(dupeChannel)));
         final NotificationChannel createdChannel =
-                mBinderService.getNotificationChannel(PKG, "id");
+                mBinderService.getNotificationChannel(PKG, mContext.getUserId(), PKG, "id");
         assertEquals(NotificationManager.IMPORTANCE_LOW, createdChannel.getImportance());
     }
 
@@ -579,7 +582,7 @@
         mBinderService.createNotificationChannels(PKG,
                 new ParceledListSlice(Arrays.asList(dupeChannel)));
         final NotificationChannel createdChannel =
-                mBinderService.getNotificationChannel(PKG, "id");
+                mBinderService.getNotificationChannel(PKG, mContext.getUserId(), PKG, "id");
         assertEquals(IMPORTANCE_HIGH, createdChannel.getImportance());
     }
 
@@ -593,7 +596,7 @@
         mBinderService.createNotificationChannels(PKG,
                 new ParceledListSlice(Arrays.asList(channel1, channel2)));
         final NotificationChannel createdChannel =
-                mBinderService.getNotificationChannel(PKG, "id");
+                mBinderService.getNotificationChannel(PKG, mContext.getUserId(), PKG, "id");
         assertEquals(IMPORTANCE_DEFAULT, createdChannel.getImportance());
     }
 
@@ -646,8 +649,8 @@
         assertEquals(1, mBinderService.getActiveNotifications(sbn.getPackageName()).length);
         assertEquals(IMPORTANCE_LOW,
                 mService.getNotificationRecord(sbn.getKey()).getImportance());
-        assertEquals(IMPORTANCE_LOW,
-                mBinderService.getNotificationChannel(PKG, channel.getId()).getImportance());
+        assertEquals(IMPORTANCE_LOW, mBinderService.getNotificationChannel(
+                PKG, mContext.getUserId(), PKG, channel.getId()).getImportance());
     }
 
     @Test
@@ -664,8 +667,8 @@
                 new NotificationChannel("blockedbyuser", "name", IMPORTANCE_NONE);
         mBinderService.updateNotificationChannelForPackage(PKG, mUid, update);
         waitForIdle();
-        assertEquals(IMPORTANCE_NONE,
-                mBinderService.getNotificationChannel(PKG, channel.getId()).getImportance());
+        assertEquals(IMPORTANCE_NONE, mBinderService.getNotificationChannel(
+                PKG, mContext.getUserId(), PKG, channel.getId()).getImportance());
 
         StatusBarNotification sbn = generateNotificationRecord(channel).sbn;
         sbn.getNotification().flags |= FLAG_FOREGROUND_SERVICE;
@@ -677,8 +680,8 @@
         assertEquals(1, mBinderService.getActiveNotifications(sbn.getPackageName()).length);
         assertEquals(IMPORTANCE_LOW,
                 mService.getNotificationRecord(sbn.getKey()).getImportance());
-        assertEquals(IMPORTANCE_LOW,
-                mBinderService.getNotificationChannel(PKG, channel.getId()).getImportance());
+        assertEquals(IMPORTANCE_LOW, mBinderService.getNotificationChannel(
+                PKG, mContext.getUserId(), PKG, channel.getId()).getImportance());
         mBinderService.cancelNotificationWithTag(PKG, "tag", sbn.getId(), sbn.getUserId());
         waitForIdle();
 
@@ -686,8 +689,8 @@
         update.setFgServiceShown(true);
         mBinderService.updateNotificationChannelForPackage(PKG, mUid, update);
         waitForIdle();
-        assertEquals(IMPORTANCE_NONE,
-                mBinderService.getNotificationChannel(PKG, channel.getId()).getImportance());
+        assertEquals(IMPORTANCE_NONE, mBinderService.getNotificationChannel(
+                PKG, mContext.getUserId(), PKG, channel.getId()).getImportance());
 
         sbn = generateNotificationRecord(channel).sbn;
         sbn.getNotification().flags |= FLAG_FOREGROUND_SERVICE;
@@ -697,8 +700,8 @@
         // The second time it is shown, we keep the user's preference.
         assertEquals(0, mBinderService.getActiveNotifications(sbn.getPackageName()).length);
         assertNull(mService.getNotificationRecord(sbn.getKey()));
-        assertEquals(IMPORTANCE_NONE,
-                mBinderService.getNotificationChannel(PKG, channel.getId()).getImportance());
+        assertEquals(IMPORTANCE_NONE, mBinderService.getNotificationChannel(
+                PKG, mContext.getUserId(), PKG, channel.getId()).getImportance());
     }
 
     @Test
@@ -2692,7 +2695,7 @@
                 mService.getNotificationRecord(sbn.getKey()).getImportance());
 
         NotificationChannel defaultChannel = mBinderService.getNotificationChannel(
-                preOPkg, NotificationChannel.DEFAULT_CHANNEL_ID);
+                preOPkg, mContext.getUserId(), preOPkg, NotificationChannel.DEFAULT_CHANNEL_ID);
         assertEquals(IMPORTANCE_UNSPECIFIED, defaultChannel.getImportance());
     }
 
@@ -4192,6 +4195,25 @@
     }
 
     @Test
+    public void testgetNotificationChannels_crossUser() throws Exception {
+        // same user no problem
+        mBinderService.getNotificationChannels("src", "target", mContext.getUserId());
+
+        // cross user, no permission, problem
+        try {
+            mBinderService.getNotificationChannels("src", "target", mContext.getUserId() + 1);
+            fail("Should not be callable cross user without cross user permission");
+        } catch (SecurityException e) {
+            // good
+        }
+
+        // cross user, with permission, no problem
+        TestablePermissions perms = mContext.getTestablePermissions();
+        perms.setPermission(android.Manifest.permission.INTERACT_ACROSS_USERS, PERMISSION_GRANTED);
+        mBinderService.getNotificationChannels("src", "target", mContext.getUserId() + 1);
+    }
+
+    @Test
     public void setDefaultAssistantForUser_fromConfigXml() {
         clearDeviceConfig();
         ComponentName xmlConfig = new ComponentName("config", "xml");
@@ -4264,4 +4286,18 @@
                 componentName,
                 false);
     }
+
+    public void testGetAllowedAssistantCapabilities() throws Exception {
+        List<String> capabilities = mBinderService.getAllowedAssistantCapabilities(null);
+        assertNotNull(capabilities);
+
+        for (int i = capabilities.size() - 1; i >= 0; i--) {
+            String capability = capabilities.get(i);
+            mBinderService.disallowAssistantCapability(capability);
+            assertEquals(i + 1, mBinderService.getAllowedAssistantCapabilities(null).size());
+            List<String> currentCapabilities = mBinderService.getAllowedAssistantCapabilities(null);
+            assertNotNull(currentCapabilities);
+            assertFalse(currentCapabilities.contains(capability));
+        }
+    }
 }
diff --git a/services/tests/wmtests/src/com/android/server/wm/AnimatingAppWindowTokenRegistryTest.java b/services/tests/wmtests/src/com/android/server/wm/AnimatingAppWindowTokenRegistryTest.java
index 5556a15..febb795 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AnimatingAppWindowTokenRegistryTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AnimatingAppWindowTokenRegistryTest.java
@@ -43,7 +43,6 @@
  */
 @SmallTest
 @Presubmit
-@FlakyTest(detail = "Promote once confirmed non-flaky")
 public class AnimatingAppWindowTokenRegistryTest extends WindowTestsBase {
 
     @Mock
diff --git a/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java
index 81133d1..9bd9930 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java
@@ -17,12 +17,16 @@
 package com.android.server.wm;
 
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
+import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
 import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
+import static android.view.WindowManager.TRANSIT_ACTIVITY_OPEN;
 import static android.view.WindowManager.TRANSIT_TASK_CHANGE_WINDOWING_MODE;
 import static android.view.WindowManager.TRANSIT_TASK_CLOSE;
 import static android.view.WindowManager.TRANSIT_TASK_OPEN;
 
 import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertFalse;
+import static junit.framework.Assert.assertTrue;
 
 import android.platform.test.annotations.Presubmit;
 import android.view.WindowManager;
@@ -95,4 +99,24 @@
                             TRANSIT_TASK_CHANGE_WINDOWING_MODE));
         }
     }
+
+    @Test
+    public void testTransitWithinTask() {
+        synchronized (mWm.mGlobalLock) {
+            final AppWindowToken opening = createAppWindowToken(mDisplayContent,
+                    WINDOWING_MODE_FREEFORM, ACTIVITY_TYPE_STANDARD);
+            opening.setFillsParent(false);
+            final AppWindowToken closing = createAppWindowToken(mDisplayContent,
+                    WINDOWING_MODE_FREEFORM, ACTIVITY_TYPE_STANDARD);
+            closing.setFillsParent(false);
+            Task task = opening.getTask();
+            mDisplayContent.mOpeningApps.add(opening);
+            mDisplayContent.mClosingApps.add(closing);
+            assertFalse(mAppTransitionController.isTransitWithinTask(TRANSIT_ACTIVITY_OPEN, task));
+            closing.getTask().removeChild(closing);
+            task.addChild(closing, 0);
+            assertTrue(mAppTransitionController.isTransitWithinTask(TRANSIT_ACTIVITY_OPEN, task));
+            assertFalse(mAppTransitionController.isTransitWithinTask(TRANSIT_TASK_OPEN, task));
+        }
+    }
 }
diff --git a/services/tests/wmtests/src/com/android/server/wm/AssistDataRequesterTest.java b/services/tests/wmtests/src/com/android/server/wm/AssistDataRequesterTest.java
index 1e02a12..329af95 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AssistDataRequesterTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AssistDataRequesterTest.java
@@ -38,9 +38,7 @@
 import static org.mockito.ArgumentMatchers.eq;
 
 import android.app.AppOpsManager;
-import android.app.IActivityManager;
 import android.app.IActivityTaskManager;
-import android.content.Context;
 import android.graphics.Bitmap;
 import android.os.Bundle;
 import android.os.Handler;
@@ -50,7 +48,6 @@
 import android.util.Log;
 import android.view.IWindowManager;
 
-import androidx.test.filters.FlakyTest;
 import androidx.test.filters.MediumTest;
 
 import com.android.server.am.AssistDataRequester;
@@ -88,12 +85,10 @@
     private static final int TEST_UID = 0;
     private static final String TEST_PACKAGE = "";
 
-    private Context mContext;
     private AssistDataRequester mDataRequester;
     private Callbacks mCallbacks;
     private Object mCallbacksLock;
     private Handler mHandler;
-    private IActivityManager mAm;
     private IActivityTaskManager mAtm;
     private IWindowManager mWm;
     private AppOpsManager mAppOpsManager;
@@ -109,7 +104,6 @@
 
     @Before
     public void setUp() throws Exception {
-        mAm = mock(IActivityManager.class);
         mAtm = mock(IActivityTaskManager.class);
         mWm = mock(IWindowManager.class);
         mAppOpsManager = mock(AppOpsManager.class);
@@ -118,7 +112,7 @@
         mCallbacks = new Callbacks();
         mDataRequester = new AssistDataRequester(mContext, mWm, mAppOpsManager, mCallbacks,
                 mCallbacksLock, OP_ASSIST_STRUCTURE, OP_ASSIST_SCREENSHOT);
-
+        mDataRequester.mActivityTaskManager = mAtm;
         // Gate the continuation of the assist data callbacks until we are ready within the tests
         mGate = new CountDownLatch(1);
         doAnswer(invocation -> {
@@ -155,7 +149,6 @@
                 .checkOpNoThrow(eq(OP_ASSIST_SCREENSHOT), anyInt(), anyString());
     }
 
-    @FlakyTest(bugId = 124088319)
     @Test
     public void testRequestData() throws Exception {
         setupMocks(CURRENT_ACTIVITY_ASSIST_ALLOWED, CALLER_ASSIST_STRUCTURE_ALLOWED,
@@ -176,7 +169,6 @@
         assertReceivedDataCount(0, 0, 0, 0);
     }
 
-    @FlakyTest(bugId = 124088319)
     @Test
     public void testCurrentAppDisallow_expectNullCallbacks() throws Exception {
         setupMocks(!CURRENT_ACTIVITY_ASSIST_ALLOWED, CALLER_ASSIST_STRUCTURE_ALLOWED,
@@ -187,7 +179,6 @@
         assertReceivedDataCount(0, 1, 0, 1);
     }
 
-    @FlakyTest(bugId = 124088319)
     @Test
     public void testProcessPendingData() throws Exception {
         setupMocks(CURRENT_ACTIVITY_ASSIST_ALLOWED, CALLER_ASSIST_STRUCTURE_ALLOWED,
@@ -245,7 +236,6 @@
         assertReceivedDataCount(0, 1, 0, 1);
     }
 
-    @FlakyTest(bugId = 124088319)
     @Test
     public void testDisallowAssistContextExtras_expectNullDataCallbacks() throws Exception {
         setupMocks(CURRENT_ACTIVITY_ASSIST_ALLOWED, CALLER_ASSIST_STRUCTURE_ALLOWED,
@@ -259,7 +249,6 @@
         assertReceivedDataCount(0, 1, 0, 1);
     }
 
-    @FlakyTest(bugId = 124088319)
     @Test
     public void testNoFetchScreenshots_expectNoScreenshotCallbacks() throws Exception {
         setupMocks(CURRENT_ACTIVITY_ASSIST_ALLOWED, CALLER_ASSIST_STRUCTURE_ALLOWED,
@@ -270,7 +259,6 @@
         assertReceivedDataCount(5, 5, 0, 0);
     }
 
-    @FlakyTest(bugId = 124088319)
     @Test
     public void testDisallowAssistScreenshot_expectNullScreenshotCallback() throws Exception {
         setupMocks(CURRENT_ACTIVITY_ASSIST_ALLOWED, CALLER_ASSIST_STRUCTURE_ALLOWED,
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 98333b2..e60e54c 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
@@ -25,6 +25,8 @@
 import static android.view.DisplayCutout.BOUNDS_POSITION_LEFT;
 import static android.view.DisplayCutout.BOUNDS_POSITION_TOP;
 import static android.view.DisplayCutout.fromBoundingRect;
+import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR;
+import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;
 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG;
 import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
@@ -58,12 +60,15 @@
 import android.app.WindowConfiguration;
 import android.content.res.Configuration;
 import android.graphics.Rect;
+import android.graphics.Region;
 import android.metrics.LogMaker;
 import android.os.SystemClock;
 import android.platform.test.annotations.Presubmit;
 import android.util.DisplayMetrics;
+import android.util.MutableBoolean;
 import android.view.DisplayCutout;
 import android.view.Gravity;
+import android.view.ISystemGestureExclusionListener;
 import android.view.MotionEvent;
 import android.view.Surface;
 import android.view.ViewRootImpl;
@@ -683,6 +688,60 @@
     }
 
     @Test
+    public void testUpdateSystemGestureExclusion() throws Exception {
+        final DisplayContent dc = createNewDisplay();
+        final WindowState win = createWindow(null, TYPE_BASE_APPLICATION, dc, "win");
+        win.getAttrs().flags |= FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR;
+        win.setSystemGestureExclusion(Collections.singletonList(new Rect(10, 20, 30, 40)));
+
+        dc.setLayoutNeeded();
+        dc.performLayout(true /* initial */, false /* updateImeWindows */);
+
+        win.setHasSurface(true);
+        dc.updateSystemGestureExclusion();
+
+        final MutableBoolean invoked = new MutableBoolean(false);
+        final ISystemGestureExclusionListener.Stub verifier =
+                new ISystemGestureExclusionListener.Stub() {
+            @Override
+            public void onSystemGestureExclusionChanged(int displayId, Region actual) {
+                Region expected = Region.obtain();
+                expected.set(10, 20, 30, 40);
+                assertEquals(expected, actual);
+                invoked.value = true;
+            }
+        };
+        try {
+            dc.registerSystemGestureExclusionListener(verifier);
+        } finally {
+            dc.unregisterSystemGestureExclusionListener(verifier);
+        }
+        assertTrue("SystemGestureExclusionListener was not invoked", invoked.value);
+    }
+
+    @Test
+    public void testCalculateSystemGestureExclusion() throws Exception {
+        final DisplayContent dc = createNewDisplay();
+        final WindowState win = createWindow(null, TYPE_BASE_APPLICATION, dc, "win");
+        win.getAttrs().flags |= FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR;
+        win.setSystemGestureExclusion(Collections.singletonList(new Rect(10, 20, 30, 40)));
+
+        final WindowState win2 = createWindow(null, TYPE_APPLICATION, dc, "win2");
+        win2.getAttrs().flags |= FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR;
+        win2.setSystemGestureExclusion(Collections.singletonList(new Rect(20, 30, 40, 50)));
+
+        dc.setLayoutNeeded();
+        dc.performLayout(true /* initial */, false /* updateImeWindows */);
+
+        win.setHasSurface(true);
+        win2.setHasSurface(true);
+
+        final Region expected = Region.obtain();
+        expected.set(20, 30, 40, 50);
+        assertEquals(expected, dc.calculateSystemGestureExclusion());
+    }
+
+    @Test
     public void testOrientationChangeLogging() {
         MetricsLogger mockLogger = mock(MetricsLogger.class);
         Configuration oldConfig = new Configuration();
diff --git a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java
index a03d28b..e392353 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java
@@ -20,17 +20,23 @@
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
 import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
 import static android.view.Display.DEFAULT_DISPLAY;
+import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
 
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.atLeast;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.verifyNoMoreInteractions;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.when;
 import static com.android.server.wm.RecentsAnimationController.REORDER_KEEP_IN_PLACE;
 import static com.android.server.wm.RecentsAnimationController.REORDER_MOVE_TO_ORIGINAL_POSITION;
 
+import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
+import static org.mockito.ArgumentMatchers.anyBoolean;
 import static org.mockito.ArgumentMatchers.eq;
 
 import android.os.Binder;
@@ -67,7 +73,11 @@
     @Before
     public void setUp() throws Exception {
         MockitoAnnotations.initMocks(this);
-
+        synchronized (mWm.mGlobalLock) {
+            // Hold the lock to protect the stubbing from being accessed by other threads.
+            spyOn(mWm.mRoot);
+            doNothing().when(mWm.mRoot).performSurfacePlacement(anyBoolean());
+        }
         when(mMockRunner.asBinder()).thenReturn(new Binder());
         mController = new RecentsAnimationController(mWm, mMockRunner, mAnimationCallbacks,
                 DEFAULT_DISPLAY);
@@ -88,7 +98,7 @@
         // Verify that the finish callback to reparent the leash is called
         verify(mFinishedCallback).onAnimationFinished(eq(adapter));
         // Verify the animation canceled callback to the app was made
-        verify(mMockRunner).onAnimationCanceled();
+        verify(mMockRunner).onAnimationCanceled(false);
         verifyNoMoreInteractionsExceptAsBinder(mMockRunner);
     }
 
@@ -131,6 +141,31 @@
         assertFalse(mController.isAnimatingTask(hiddenAppWindow.getTask()));
     }
 
+    @Test
+    public void testCancelAnimationWithScreenShot() throws Exception {
+        mWm.setRecentsAnimationController(mController);
+        final AppWindowToken appWindow = createAppWindowToken(mDisplayContent,
+                WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD);
+        final WindowState win1 = createWindow(null, TYPE_BASE_APPLICATION, appWindow, "win1");
+        appWindow.addWindow(win1);
+        assertEquals(appWindow.getTask().getTopVisibleAppToken(), appWindow);
+        assertEquals(appWindow.findMainWindow(), win1);
+
+        mController.addAnimation(appWindow.getTask(), false /* isRecentTaskInvisible */);
+        assertTrue(mController.isAnimatingTask(appWindow.getTask()));
+
+        mController.setCancelWithDeferredScreenshotLocked(true);
+        mController.cancelAnimationWithScreenShot();
+        verify(mMockRunner).onAnimationCanceled(true /* deferredWithScreenshot */);
+        assertNotNull(mController.mRecentScreenshotAnimator);
+        assertTrue(mController.mRecentScreenshotAnimator.isAnimating());
+
+        // Assume IRecentsAnimationController#cleanupScreenshot called to finish screenshot
+        // animation.
+        mController.mRecentScreenshotAnimator.cancelAnimation();
+        verify(mAnimationCallbacks).onAnimationFinished(REORDER_KEEP_IN_PLACE, true);
+    }
+
     private static void verifyNoMoreInteractionsExceptAsBinder(IInterface binder) {
         verify(binder, atLeast(0)).asBinder();
         verifyNoMoreInteractions(binder);
diff --git a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationTest.java b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationTest.java
index 5f3a290..5625ea4 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationTest.java
@@ -20,7 +20,6 @@
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
 import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
 
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.any;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.eq;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
@@ -29,6 +28,8 @@
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
 import static com.android.server.wm.RecentsAnimationController.REORDER_KEEP_IN_PLACE;
 
+import static org.mockito.ArgumentMatchers.any;
+
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
@@ -51,11 +52,15 @@
 
     private Context mContext = InstrumentationRegistry.getContext();
     private ComponentName mRecentsComponent;
+    private RecentsAnimationController mRecentsAnimationController;
 
     @Before
     public void setUp() throws Exception {
         mRecentsComponent = new ComponentName(mContext.getPackageName(), "RecentsActivity");
         mService = new TestActivityTaskManagerService(mContext);
+        mRecentsAnimationController = mock(RecentsAnimationController.class);
+        doReturn(mRecentsAnimationController).when(
+                mService.mWindowManager).getRecentsAnimationController();
 
         final RecentTasks recentTasks = mService.getRecentTasks();
         spyOn(recentTasks);
@@ -96,9 +101,18 @@
 
         fullscreenStack.moveToFront("Activity start");
 
-        // Ensure that the recents animation was canceled
+        // Ensure that the recents animation was canceled by cancelAnimationSynchronously().
         verify(mService.mWindowManager, times(1)).cancelRecentsAnimationSynchronously(
                 eq(REORDER_KEEP_IN_PLACE), any());
+
+        // Assume recents animation already started, set a state that cancel recents animation
+        // with screenshot.
+        doReturn(true).when(mRecentsAnimationController).shouldCancelWithDeferredScreenshot();
+        // Start another fullscreen activity.
+        fullscreenStack2.moveToFront("Activity start");
+
+        // Ensure that the recents animation was canceled by cancelOnNextTransitionStart().
+        verify(mRecentsAnimationController, times(1)).cancelOnNextTransitionStart();
     }
 
     @Test
@@ -137,5 +151,6 @@
         // Ensure that the recents animation was NOT canceled
         verify(mService.mWindowManager, times(0)).cancelRecentsAnimationSynchronously(
                 eq(REORDER_KEEP_IN_PLACE), any());
+        verify(mRecentsAnimationController, times(0)).cancelOnNextTransitionStart();
     }
 }
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskStackChangedListenerTest.java b/services/tests/wmtests/src/com/android/server/wm/TaskStackChangedListenerTest.java
index b9e9909..d8a01b9 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskStackChangedListenerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskStackChangedListenerTest.java
@@ -159,7 +159,6 @@
      * Tests for onTaskCreated, onTaskMovedToFront, onTaskRemoved and onTaskRemovalStarted.
      */
     @Test
-    @FlakyTest(detail = "Promote to presubmit when shown to be stable.")
     public void testTaskChangeCallBacks() throws Exception {
         final Object[] params = new Object[2];
         final CountDownLatch taskCreatedLaunchLatch = new CountDownLatch(1);
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 b03f63b..4f8fe5b 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
@@ -87,7 +87,6 @@
  */
 @SmallTest
 @Presubmit
-@FlakyTest(bugId = 124127512)
 public class WindowStateTests extends WindowTestsBase {
     private static int sPreviousNewInsetsMode;
 
@@ -363,7 +362,6 @@
         assertFalse(app.canAffectSystemUiFlags());
     }
 
-    @FlakyTest(detail = "Promote to presubmit when shown to be stable.")
     @Test
     public void testVisibleWithInsetsProvider() throws Exception {
         final WindowState topBar = createWindow(null, TYPE_STATUS_BAR, "topBar");
diff --git a/startop/view_compiler/Android.bp b/startop/view_compiler/Android.bp
index f5b4308..92ea872 100644
--- a/startop/view_compiler/Android.bp
+++ b/startop/view_compiler/Android.bp
@@ -22,7 +22,6 @@
     ],
     shared_libs: [
         "libbase",
-        "libz",
         "slicer",
     ],
     static_libs: [
diff --git a/telecomm/java/android/telecom/Call.java b/telecomm/java/android/telecom/Call.java
index dcaa499..c05a346 100644
--- a/telecomm/java/android/telecom/Call.java
+++ b/telecomm/java/android/telecom/Call.java
@@ -144,6 +144,16 @@
     public static final String EXTRA_LAST_EMERGENCY_CALLBACK_TIME_MILLIS =
             "android.telecom.extra.LAST_EMERGENCY_CALLBACK_TIME_MILLIS";
 
+
+    /**
+     * Extra key used to indicate whether a {@link CallScreeningService} has requested to silence
+     * the ringtone for a call.  If the {@link InCallService} declares
+     * {@link TelecomManager#METADATA_IN_CALL_SERVICE_RINGING} in its manifest, it should not
+     * play a ringtone for an incoming call with this extra key set.
+     */
+    public static final String EXTRA_SILENT_RINGING_REQUESTED =
+            "android.telecom.extra.SILENT_RINGING_REQUESTED";
+
     /**
      * Call event sent from a {@link Call} via {@link #sendCallEvent(String, Bundle)} to inform
      * Telecom that the user has requested that the current {@link Call} should be handed over
diff --git a/telecomm/java/android/telecom/CallScreeningService.java b/telecomm/java/android/telecom/CallScreeningService.java
index 2fa388f..b1aece7 100644
--- a/telecomm/java/android/telecom/CallScreeningService.java
+++ b/telecomm/java/android/telecom/CallScreeningService.java
@@ -259,12 +259,14 @@
     public static class CallResponse {
         private final boolean mShouldDisallowCall;
         private final boolean mShouldRejectCall;
+        private final boolean mShouldSilenceCall;
         private final boolean mShouldSkipCallLog;
         private final boolean mShouldSkipNotification;
 
         private CallResponse(
                 boolean shouldDisallowCall,
                 boolean shouldRejectCall,
+                boolean shouldSilenceCall,
                 boolean shouldSkipCallLog,
                 boolean shouldSkipNotification) {
             if (!shouldDisallowCall
@@ -276,6 +278,7 @@
             mShouldRejectCall = shouldRejectCall;
             mShouldSkipCallLog = shouldSkipCallLog;
             mShouldSkipNotification = shouldSkipNotification;
+            mShouldSilenceCall = shouldSilenceCall;
         }
 
         /*
@@ -294,6 +297,13 @@
         }
 
         /*
+         * @return Whether the ringtone should be silenced for the incoming call.
+         */
+        public boolean getSilenceCall() {
+            return mShouldSilenceCall;
+        }
+
+        /*
          * @return Whether the incoming call should not be displayed in the call log.
          */
         public boolean getSkipCallLog() {
@@ -310,6 +320,7 @@
         public static class Builder {
             private boolean mShouldDisallowCall;
             private boolean mShouldRejectCall;
+            private boolean mShouldSilenceCall;
             private boolean mShouldSkipCallLog;
             private boolean mShouldSkipNotification;
 
@@ -331,6 +342,21 @@
             }
 
             /**
+             * Sets whether ringing should be silenced for the incoming call.  When set
+             * to {@code true}, the Telecom framework will not play a ringtone for the call.
+             * The call will, however, still be sent to the default dialer app if it is not blocked.
+             * A {@link CallScreeningService} can use this to ensure a potential nuisance call is
+             * still surfaced to the user, but in a less intrusive manner.
+             *
+             * Setting this to true only makes sense when the call has not been disallowed
+             * using {@link #setDisallowCall(boolean)}.
+             */
+            public @NonNull Builder setSilenceCall(boolean shouldSilenceCall) {
+                mShouldSilenceCall = shouldSilenceCall;
+                return this;
+            }
+
+            /**
              * Sets whether the incoming call should not be displayed in the call log. This property
              * should only be set to true if the call is disallowed.
              * <p>
@@ -356,6 +382,7 @@
                 return new CallResponse(
                         mShouldDisallowCall,
                         mShouldRejectCall,
+                        mShouldSilenceCall,
                         mShouldSkipCallLog,
                         mShouldSkipNotification);
             }
@@ -411,10 +438,11 @@
     public abstract void onScreenCall(@NonNull Call.Details callDetails);
 
     /**
-     * Responds to the given incoming call, either allowing it or disallowing it.
+     * Responds to the given incoming call, either allowing it, silencing it or disallowing it.
      * <p>
      * The {@link CallScreeningService} calls this method to inform the system whether the call
-     * should be silently blocked or not.
+     * should be silently blocked or not. In the event that it should not be blocked, it may
+     * also be requested to ring silently.
      * <p>
      * Calls to this method are ignored unless the {@link Call.Details#getCallDirection()} is
      * {@link Call.Details#DIRECTION_INCOMING}.
@@ -436,6 +464,8 @@
                         !response.getSkipCallLog(),
                         !response.getSkipNotification(),
                         new ComponentName(getPackageName(), getClass().getName()));
+            } else if (response.getSilenceCall()) {
+                mCallScreeningAdapter.silenceCall(callDetails.getTelecomCallId());
             } else {
                 mCallScreeningAdapter.allowCall(callDetails.getTelecomCallId());
             }
diff --git a/telecomm/java/android/telecom/Log.java b/telecomm/java/android/telecom/Log.java
index 16791a4..7d4ee76 100644
--- a/telecomm/java/android/telecom/Log.java
+++ b/telecomm/java/android/telecom/Log.java
@@ -16,6 +16,7 @@
 
 package android.telecom;
 
+import android.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.net.Uri;
 import android.os.Build;
@@ -97,6 +98,7 @@
         }
     }
 
+    @UnsupportedAppUsage
     public static void i(String prefix, String format, Object... args) {
         if (INFO) {
             android.util.Slog.i(TAG, buildMessage(prefix, format, args));
@@ -127,6 +129,7 @@
         }
     }
 
+    @UnsupportedAppUsage
     public static void w(String prefix, String format, Object... args) {
         if (WARN) {
             android.util.Slog.w(TAG, buildMessage(prefix, format, args));
diff --git a/telecomm/java/com/android/internal/telecom/ICallScreeningAdapter.aidl b/telecomm/java/com/android/internal/telecom/ICallScreeningAdapter.aidl
index a86c830..1160d27 100644
--- a/telecomm/java/com/android/internal/telecom/ICallScreeningAdapter.aidl
+++ b/telecomm/java/com/android/internal/telecom/ICallScreeningAdapter.aidl
@@ -29,6 +29,8 @@
 oneway interface ICallScreeningAdapter {
     void allowCall(String callId);
 
+    void silenceCall(String callId);
+
     void disallowCall(
             String callId,
             boolean shouldReject,
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index 524d080..5f9ef3c 100755
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -1520,6 +1520,14 @@
             "carrier_app_no_wake_signal_config";
 
     /**
+     * Determines whether the carrier app needed to be involved when users try to finish setting up
+     * the SIM card to get network service.
+     * @hide
+     */
+    public static final String KEY_CARRIER_APP_REQUIRED_DURING_SIM_SETUP_BOOL =
+            "carrier_app_required_during_setup_bool";
+
+    /**
      * Default value for {@link Settings.Global#DATA_ROAMING}
      * @hide
      */
@@ -2307,9 +2315,9 @@
             "undelivered_sms_message_expiration_time";
 
     /**
-     * Specifies a carrier-defined {@link CallRedirectionService} which Telecom will bind
-     * to for outgoing calls.  An empty string indicates that no carrier-defined
-     * {@link CallRedirectionService} is specified.
+     * Specifies a carrier-defined {@link android.telecom.CallRedirectionService} which Telecom
+     * will bind to for outgoing calls.  An empty string indicates that no carrier-defined
+     * {@link android.telecom.CallRedirectionService} is specified.
      * @hide
      */
     public static final String KEY_CALL_REDIRECTION_SERVICE_COMPONENT_NAME_STRING =
@@ -2867,6 +2875,7 @@
         sDefaults.putString(KEY_CARRIER_NAME_STRING, "");
         sDefaults.putString(KEY_SIM_COUNTRY_ISO_OVERRIDE_STRING, "");
         sDefaults.putString(KEY_CARRIER_CALL_SCREENING_APP_STRING, "");
+        sDefaults.putString(KEY_CALL_REDIRECTION_SERVICE_COMPONENT_NAME_STRING, null);
         sDefaults.putBoolean(KEY_CDMA_HOME_REGISTERED_PLMN_NAME_OVERRIDE_BOOL, false);
         sDefaults.putString(KEY_CDMA_HOME_REGISTERED_PLMN_NAME_STRING, "");
         sDefaults.putBoolean(KEY_SUPPORT_DIRECT_FDN_DIALING_BOOL, false);
@@ -2922,6 +2931,7 @@
                                 + "com.android.internal.telephony.CARRIER_SIGNAL_RESET"
                 });
         sDefaults.putStringArray(KEY_CARRIER_APP_NO_WAKE_SIGNAL_CONFIG_STRING_ARRAY, null);
+        sDefaults.putBoolean(KEY_CARRIER_APP_REQUIRED_DURING_SIM_SETUP_BOOL, false);
 
 
         // Default carrier app configurations
diff --git a/telephony/java/android/telephony/CellIdentityTdscdma.java b/telephony/java/android/telephony/CellIdentityTdscdma.java
index 10ffb80..19b11b6 100644
--- a/telephony/java/android/telephony/CellIdentityTdscdma.java
+++ b/telephony/java/android/telephony/CellIdentityTdscdma.java
@@ -16,6 +16,7 @@
 
 package android.telephony;
 
+import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.os.Parcel;
 import android.telephony.gsm.GsmCellLocation;
@@ -205,6 +206,12 @@
 
     /** Implement the Parcelable interface */
     @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    /** Implement the Parcelable interface */
+    @Override
     public void writeToParcel(Parcel dest, int flags) {
         if (DBG) log("writeToParcel(Parcel, int): " + toString());
         super.writeToParcel(dest, CellInfo.TYPE_TDSCDMA);
@@ -226,16 +233,17 @@
 
     /** Implement the Parcelable interface */
     @SuppressWarnings("hiding")
-    public static final @android.annotation.NonNull Creator<CellIdentityTdscdma> CREATOR =
+    @NonNull
+    public static final Creator<CellIdentityTdscdma> CREATOR =
             new Creator<CellIdentityTdscdma>() {
                 @Override
-                public CellIdentityTdscdma createFromParcel(Parcel in) {
+                public @NonNull CellIdentityTdscdma createFromParcel(Parcel in) {
                     in.readInt();   // skip
                     return createFromParcelBody(in);
                 }
 
                 @Override
-                public CellIdentityTdscdma[] newArray(int size) {
+                public @NonNull CellIdentityTdscdma[] newArray(int size) {
                     return new CellIdentityTdscdma[size];
                 }
             };
diff --git a/telephony/java/android/telephony/CellInfoTdscdma.java b/telephony/java/android/telephony/CellInfoTdscdma.java
index 93baabf..1830086 100644
--- a/telephony/java/android/telephony/CellInfoTdscdma.java
+++ b/telephony/java/android/telephony/CellInfoTdscdma.java
@@ -16,6 +16,7 @@
 
 package android.telephony;
 
+import android.annotation.NonNull;
 import android.os.Parcel;
 import android.os.Parcelable;
 
@@ -24,7 +25,9 @@
 /**
  * A {@link CellInfo} representing a TD-SCDMA cell that provides identity and measurement info.
  *
- * @hide
+ * @see android.telephony.CellInfo
+ * @see android.telephony.CellSignalStrengthTdscdma
+ * @see android.telephony.CellIdentityTdscdma
  */
 public final class CellInfoTdscdma extends CellInfo implements Parcelable {
 
@@ -72,18 +75,21 @@
         mCellSignalStrengthTdscdma = new CellSignalStrengthTdscdma(cit.signalStrengthTdscdma);
     }
 
-    @Override public CellIdentityTdscdma getCellIdentity() {
+    @Override
+    public @NonNull CellIdentityTdscdma getCellIdentity() {
         return mCellIdentityTdscdma;
     }
+
     /** @hide */
     public void setCellIdentity(CellIdentityTdscdma cid) {
         mCellIdentityTdscdma = cid;
     }
 
     @Override
-    public CellSignalStrengthTdscdma getCellSignalStrength() {
+    public @NonNull CellSignalStrengthTdscdma getCellSignalStrength() {
         return mCellSignalStrengthTdscdma;
     }
+
     /** @hide */
     public void setCellSignalStrength(CellSignalStrengthTdscdma css) {
         mCellSignalStrengthTdscdma = css;
@@ -149,15 +155,16 @@
     }
 
     /** Implement the Parcelable interface */
-    public static final @android.annotation.NonNull Creator<CellInfoTdscdma> CREATOR = new Creator<CellInfoTdscdma>() {
+    @NonNull
+    public static final Creator<CellInfoTdscdma> CREATOR = new Creator<CellInfoTdscdma>() {
         @Override
-        public CellInfoTdscdma createFromParcel(Parcel in) {
+        public @NonNull CellInfoTdscdma createFromParcel(Parcel in) {
             in.readInt(); // Skip past token, we know what it is
             return createFromParcelBody(in);
         }
 
         @Override
-        public CellInfoTdscdma[] newArray(int size) {
+        public @NonNull CellInfoTdscdma[] newArray(int size) {
             return new CellInfoTdscdma[size];
         }
     };
diff --git a/telephony/java/android/telephony/CellSignalStrengthTdscdma.java b/telephony/java/android/telephony/CellSignalStrengthTdscdma.java
index e79643f..ddbd851 100644
--- a/telephony/java/android/telephony/CellSignalStrengthTdscdma.java
+++ b/telephony/java/android/telephony/CellSignalStrengthTdscdma.java
@@ -16,6 +16,7 @@
 
 package android.telephony;
 
+import android.annotation.NonNull;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.os.PersistableBundle;
@@ -25,7 +26,8 @@
 /**
  * Tdscdma signal strength related information.
  *
- * @hide
+ * This class provides signal strength and signal quality information for the TD-SCDMA air
+ * interface. For more information see 3gpp 25.225.
  */
 public final class CellSignalStrengthTdscdma extends CellSignalStrength implements Parcelable {
 
@@ -59,7 +61,9 @@
      * @param rssi in dBm [-113, -51] or UNAVAILABLE
      * @param ber [0-7], 99 or UNAVAILABLE
      * @param rscp in dBm [-120, -24] or UNAVAILABLE
-     * @hide */
+     *
+     * @hide
+     */
     public CellSignalStrengthTdscdma(int rssi, int ber, int rscp) {
         mRssi = inRangeOrUnavailable(rssi, -113, -51);
         mBitErrorRate = inRangeOrUnavailable(ber, 0, 7, 99);
@@ -148,8 +152,7 @@
     }
 
     /**
-     * Get the RSCP as dBm
-     * @hide
+     * Get the RSCP as dBm value -120..-24dBm or {@link CellInfo#UNAVAILABLE UNAVAILABLE}.
      */
     public int getRscp() {
         return mRscp;
@@ -160,7 +163,7 @@
      *
      * Asu is calculated based on 3GPP RSRP. Refer to 3GPP 27.007 (Ver 10.3.0) Sec 8.69
      *
-     * @return RSCP in ASU 0..96, 255, or UNAVAILABLE
+     * @return RSCP in ASU 0..96, 255, or {@link CellInfo#UNAVAILABLE UNAVAILABLE}.
      */
     @Override
     public int getAsuLevel() {
@@ -237,15 +240,16 @@
 
     /** Implement the Parcelable interface */
     @SuppressWarnings("hiding")
-    public static final @android.annotation.NonNull Parcelable.Creator<CellSignalStrengthTdscdma> CREATOR =
+    @NonNull
+    public static final Parcelable.Creator<CellSignalStrengthTdscdma> CREATOR =
             new Parcelable.Creator<CellSignalStrengthTdscdma>() {
         @Override
-        public CellSignalStrengthTdscdma createFromParcel(Parcel in) {
+        public @NonNull CellSignalStrengthTdscdma createFromParcel(Parcel in) {
             return new CellSignalStrengthTdscdma(in);
         }
 
         @Override
-        public CellSignalStrengthTdscdma[] newArray(int size) {
+        public @NonNull CellSignalStrengthTdscdma[] newArray(int size) {
             return new CellSignalStrengthTdscdma[size];
         }
     };
diff --git a/telephony/java/android/telephony/DataFailCause.java b/telephony/java/android/telephony/DataFailCause.java
index f0a26f5..ca264f7 100644
--- a/telephony/java/android/telephony/DataFailCause.java
+++ b/telephony/java/android/telephony/DataFailCause.java
@@ -318,8 +318,8 @@
     public static final int LOW_POWER_MODE_OR_POWERING_DOWN = 0x7FC;
     /** APN has been disabled. */
     public static final int APN_DISABLED = 0x7FD;
-    /** PPP inactivity timer expired. */
-    public static final int PPP_INACTIVITY_TIMER_EXPIRED = 0x7FE;
+    /** Maximum PPP inactivity timer expired. */
+    public static final int MAX_PPP_INACTIVITY_TIMER_EXPIRED = 0x7FE;
     /** IPv6 address transfer failed. */
     public static final int IPV6_ADDRESS_TRANSFER_FAILED = 0x7FF;
     /** Target RAT swap failed. */
@@ -339,12 +339,12 @@
      * IPv4 data call bring up is rejected because the UE already maintains the allotted maximum
      * number of IPv4 data connections.
      */
-    public static final int IPV4_CONNECTIONS_LIMIT_REACHED = 0x804;
+    public static final int MAX_IPV4_CONNECTIONS = 0x804;
     /**
      * IPv6 data call bring up is rejected because the UE already maintains the allotted maximum
      * number of IPv6 data connections.
      */
-    public static final int IPV6_CONNECTIONS_LIMIT_REACHED = 0x805;
+    public static final int MAX_IPV6_CONNECTIONS = 0x805;
     /**
      * New PDN bring up is rejected during interface selection because the UE has already allotted
      * the available interfaces for other PDNs.
@@ -416,7 +416,7 @@
      */
     public static final int CHANNEL_ACQUISITION_FAILURE = 0x81E;
     /** Maximum access probes transmitted. */
-    public static final int ACCESS_PROBE_LIMIT_REACHED = 0x81F;
+    public static final int MAX_ACCESS_PROBE = 0x81F;
     /** Concurrent service is not supported by base station. */
     public static final int CONCURRENT_SERVICE_NOT_SUPPORTED_BY_BASE_STATION = 0x820;
     /** There was no response received from the base station. */
@@ -1079,14 +1079,14 @@
             SIM_CARD_CHANGED,
             LOW_POWER_MODE_OR_POWERING_DOWN,
             APN_DISABLED,
-            PPP_INACTIVITY_TIMER_EXPIRED,
+            MAX_PPP_INACTIVITY_TIMER_EXPIRED,
             IPV6_ADDRESS_TRANSFER_FAILED,
             TRAT_SWAP_FAILED,
             EHRPD_TO_HRPD_FALLBACK,
             MIP_CONFIG_FAILURE,
             PDN_INACTIVITY_TIMER_EXPIRED,
-            IPV4_CONNECTIONS_LIMIT_REACHED,
-            IPV6_CONNECTIONS_LIMIT_REACHED,
+            MAX_IPV4_CONNECTIONS,
+            MAX_IPV6_CONNECTIONS,
             APN_MISMATCH,
             IP_VERSION_MISMATCH,
             DUN_CALL_DISALLOWED,
@@ -1112,7 +1112,7 @@
             CDMA_INCOMING_CALL,
             CDMA_ALERT_STOP,
             CHANNEL_ACQUISITION_FAILURE,
-            ACCESS_PROBE_LIMIT_REACHED,
+            MAX_ACCESS_PROBE,
             CONCURRENT_SERVICE_NOT_SUPPORTED_BY_BASE_STATION,
             NO_RESPONSE_FROM_BASE_STATION,
             REJECTED_BY_BASE_STATION,
@@ -1447,14 +1447,14 @@
         sFailCauseMap.put(SIM_CARD_CHANGED, "SIM_CARD_CHANGED");
         sFailCauseMap.put(LOW_POWER_MODE_OR_POWERING_DOWN, "LOW_POWER_MODE_OR_POWERING_DOWN");
         sFailCauseMap.put(APN_DISABLED, "APN_DISABLED");
-        sFailCauseMap.put(PPP_INACTIVITY_TIMER_EXPIRED, "PPP_INACTIVITY_TIMER_EXPIRED");
+        sFailCauseMap.put(MAX_PPP_INACTIVITY_TIMER_EXPIRED, "MAX_PPP_INACTIVITY_TIMER_EXPIRED");
         sFailCauseMap.put(IPV6_ADDRESS_TRANSFER_FAILED, "IPV6_ADDRESS_TRANSFER_FAILED");
         sFailCauseMap.put(TRAT_SWAP_FAILED, "TRAT_SWAP_FAILED");
         sFailCauseMap.put(EHRPD_TO_HRPD_FALLBACK, "EHRPD_TO_HRPD_FALLBACK");
         sFailCauseMap.put(MIP_CONFIG_FAILURE, "MIP_CONFIG_FAILURE");
         sFailCauseMap.put(PDN_INACTIVITY_TIMER_EXPIRED, "PDN_INACTIVITY_TIMER_EXPIRED");
-        sFailCauseMap.put(IPV4_CONNECTIONS_LIMIT_REACHED, "IPV4_CONNECTIONS_LIMIT_REACHED");
-        sFailCauseMap.put(IPV6_CONNECTIONS_LIMIT_REACHED, "IPV6_CONNECTIONS_LIMIT_REACHED");
+        sFailCauseMap.put(MAX_IPV4_CONNECTIONS, "MAX_IPV4_CONNECTIONS");
+        sFailCauseMap.put(MAX_IPV6_CONNECTIONS, "MAX_IPV6_CONNECTIONS");
         sFailCauseMap.put(APN_MISMATCH, "APN_MISMATCH");
         sFailCauseMap.put(IP_VERSION_MISMATCH, "IP_VERSION_MISMATCH");
         sFailCauseMap.put(DUN_CALL_DISALLOWED, "DUN_CALL_DISALLOWED");
@@ -1480,7 +1480,7 @@
         sFailCauseMap.put(CDMA_INCOMING_CALL, "CDMA_INCOMING_CALL");
         sFailCauseMap.put(CDMA_ALERT_STOP, "CDMA_ALERT_STOP");
         sFailCauseMap.put(CHANNEL_ACQUISITION_FAILURE, "CHANNEL_ACQUISITION_FAILURE");
-        sFailCauseMap.put(ACCESS_PROBE_LIMIT_REACHED, "ACCESS_PROBE_LIMIT_REACHED");
+        sFailCauseMap.put(MAX_ACCESS_PROBE, "MAX_ACCESS_PROBE");
         sFailCauseMap.put(CONCURRENT_SERVICE_NOT_SUPPORTED_BY_BASE_STATION,
                 "CONCURRENT_SERVICE_NOT_SUPPORTED_BY_BASE_STATION");
         sFailCauseMap.put(NO_RESPONSE_FROM_BASE_STATION, "NO_RESPONSE_FROM_BASE_STATION");
diff --git a/telephony/java/android/telephony/INetworkService.aidl b/telephony/java/android/telephony/INetworkService.aidl
index 67e5650..3a9c3a5 100644
--- a/telephony/java/android/telephony/INetworkService.aidl
+++ b/telephony/java/android/telephony/INetworkService.aidl
@@ -25,7 +25,7 @@
 {
     void createNetworkServiceProvider(int slotId);
     void removeNetworkServiceProvider(int slotId);
-    void getNetworkRegistrationInfo(int slotId, int domain, INetworkServiceCallback callback);
+    void requestNetworkRegistrationInfo(int slotId, int domain, INetworkServiceCallback callback);
     void registerForNetworkRegistrationInfoChanged(int slotId, INetworkServiceCallback callback);
     void unregisterForNetworkRegistrationInfoChanged(int slotId, INetworkServiceCallback callback);
 }
diff --git a/telephony/java/android/telephony/INetworkServiceCallback.aidl b/telephony/java/android/telephony/INetworkServiceCallback.aidl
index 33b3ac0..c35986c 100644
--- a/telephony/java/android/telephony/INetworkServiceCallback.aidl
+++ b/telephony/java/android/telephony/INetworkServiceCallback.aidl
@@ -24,6 +24,6 @@
  */
 oneway interface INetworkServiceCallback
 {
-    void onGetNetworkRegistrationInfoComplete(int result, in NetworkRegistrationInfo state);
+    void onRequestNetworkRegistrationInfoComplete(int result, in NetworkRegistrationInfo state);
     void onNetworkStateChanged();
 }
diff --git a/telephony/java/android/telephony/JapanesePhoneNumberFormatter.java b/telephony/java/android/telephony/JapanesePhoneNumberFormatter.java
index f5e53ef..92a674c 100644
--- a/telephony/java/android/telephony/JapanesePhoneNumberFormatter.java
+++ b/telephony/java/android/telephony/JapanesePhoneNumberFormatter.java
@@ -16,6 +16,7 @@
 
 package android.telephony;
 
+import android.annotation.UnsupportedAppUsage;
 import android.text.Editable;
 
 /*
@@ -154,6 +155,7 @@
     -35, -35, -35, -35, -35, -35, -35, -35, -35, -45,
     -26, -15, -15, -15, -15, -15, -15, -15, -15, -15};
 
+    @UnsupportedAppUsage
     public static void format(Editable text) {
         // Here, "root" means the position of "'":
         // 0'3, 0'90, and +81'-90
diff --git a/telephony/java/android/telephony/NetworkRegistrationInfo.java b/telephony/java/android/telephony/NetworkRegistrationInfo.java
index c31a14e..9145b25 100644
--- a/telephony/java/android/telephony/NetworkRegistrationInfo.java
+++ b/telephony/java/android/telephony/NetworkRegistrationInfo.java
@@ -27,7 +27,9 @@
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
-import java.util.Arrays;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
 import java.util.Objects;
 import java.util.stream.Collectors;
 
@@ -36,7 +38,7 @@
  * @hide
  */
 @SystemApi
-public class NetworkRegistrationInfo implements Parcelable {
+public final class NetworkRegistrationInfo implements Parcelable {
     /**
      * Network domain
      * @hide
@@ -51,41 +53,42 @@
     public static final int DOMAIN_PS = 2;
 
     /**
-     * Registration state
+     * Network registration state
      * @hide
      */
     @Retention(RetentionPolicy.SOURCE)
-    @IntDef(prefix = "REG_STATE_",
-            value = {REG_STATE_NOT_REG_NOT_SEARCHING, REG_STATE_HOME, REG_STATE_NOT_REG_SEARCHING,
-                    REG_STATE_DENIED, REG_STATE_UNKNOWN, REG_STATE_ROAMING})
-    public @interface RegState {}
+    @IntDef(prefix = "REGISTRATION_STATE_",
+            value = {REGISTRATION_STATE_NOT_REGISTERED_OR_SEARCHING, REGISTRATION_STATE_HOME,
+                    REGISTRATION_STATE_NOT_REGISTERED_SEARCHING, REGISTRATION_STATE_DENIED,
+                    REGISTRATION_STATE_UNKNOWN, REGISTRATION_STATE_ROAMING})
+    public @interface RegistrationState {}
 
-    /** Not registered. The device is not currently searching a new operator to register */
-    public static final int REG_STATE_NOT_REG_NOT_SEARCHING = 0;
-    /** Registered on home network */
-    public static final int REG_STATE_HOME                  = 1;
-    /** Not registered. The device is currently searching a new operator to register */
-    public static final int REG_STATE_NOT_REG_SEARCHING     = 2;
-    /** Registration denied */
-    public static final int REG_STATE_DENIED                = 3;
-    /** Registration state is unknown */
-    public static final int REG_STATE_UNKNOWN               = 4;
-    /** Registered on roaming network */
-    public static final int REG_STATE_ROAMING               = 5;
+    /** Not registered. The device is not currently searching a new operator to register. */
+    public static final int REGISTRATION_STATE_NOT_REGISTERED_OR_SEARCHING = 0;
+    /** Registered on home network. */
+    public static final int REGISTRATION_STATE_HOME = 1;
+    /** Not registered. The device is currently searching a new operator to register. */
+    public static final int REGISTRATION_STATE_NOT_REGISTERED_SEARCHING = 2;
+    /** Registration denied. */
+    public static final int REGISTRATION_STATE_DENIED = 3;
+    /** Registration state is unknown. */
+    public static final int REGISTRATION_STATE_UNKNOWN = 4;
+    /** Registered on roaming network. */
+    public static final int REGISTRATION_STATE_ROAMING = 5;
 
     /** @hide */
     @Retention(RetentionPolicy.SOURCE)
-    @IntDef(prefix = "NR_STATUS_",
-            value = {NR_STATUS_NONE, NR_STATUS_RESTRICTED, NR_STATUS_NOT_RESTRICTED,
-                    NR_STATUS_CONNECTED})
-    public @interface NRStatus {}
+    @IntDef(prefix = "NR_STATE_",
+            value = {NR_STATE_NONE, NR_STATE_RESTRICTED, NR_STATE_NOT_RESTRICTED,
+                    NR_STATE_CONNECTED})
+    public @interface NRState {}
 
     /**
      * The device isn't camped on an LTE cell or the LTE cell doesn't support E-UTRA-NR
      * Dual Connectivity(EN-DC).
      * @hide
      */
-    public static final int NR_STATUS_NONE = -1;
+    public static final int NR_STATE_NONE = -1;
 
     /**
      * The device is camped on an LTE cell that supports E-UTRA-NR Dual Connectivity(EN-DC) but
@@ -93,7 +96,7 @@
      * the selected PLMN.
      * @hide
      */
-    public static final int NR_STATUS_RESTRICTED = 1;
+    public static final int NR_STATE_RESTRICTED = 1;
 
     /**
      * The device is camped on an LTE cell that supports E-UTRA-NR Dual Connectivity(EN-DC) and both
@@ -101,14 +104,14 @@
      * selected PLMN.
      * @hide
      */
-    public static final int NR_STATUS_NOT_RESTRICTED = 2;
+    public static final int NR_STATE_NOT_RESTRICTED = 2;
 
     /**
      * The device is camped on an LTE cell that supports E-UTRA-NR Dual Connectivity(EN-DC) and
      * also connected to at least one 5G cell as a secondary serving cell.
      * @hide
      */
-    public static final int NR_STATUS_CONNECTED = 3;
+    public static final int NR_STATE_CONNECTED = 3;
 
     /**
      * Supported service type
@@ -116,23 +119,36 @@
      */
     @Retention(RetentionPolicy.SOURCE)
     @IntDef(prefix = "SERVICE_TYPE_",
-            value = {SERVICE_TYPE_VOICE, SERVICE_TYPE_DATA, SERVICE_TYPE_SMS, SERVICE_TYPE_VIDEO,
-                    SERVICE_TYPE_EMERGENCY})
+            value = {SERVICE_TYPE_UNKNOWN, SERVICE_TYPE_VOICE, SERVICE_TYPE_DATA, SERVICE_TYPE_SMS,
+                    SERVICE_TYPE_VIDEO, SERVICE_TYPE_EMERGENCY})
     public @interface ServiceType {}
 
+    /** Unkown service */
+    public static final int SERVICE_TYPE_UNKNOWN    = 0;
+
+    /** Voice service */
     public static final int SERVICE_TYPE_VOICE      = 1;
+
+    /** Data service */
     public static final int SERVICE_TYPE_DATA       = 2;
+
+    /** SMS service */
     public static final int SERVICE_TYPE_SMS        = 3;
+
+    /** Video service */
     public static final int SERVICE_TYPE_VIDEO      = 4;
+
+    /** Emergency service */
     public static final int SERVICE_TYPE_EMERGENCY  = 5;
 
     @Domain
     private final int mDomain;
 
+    @TransportType
     private final int mTransportType;
 
-    @RegState
-    private final int mRegState;
+    @RegistrationState
+    private final int mRegistrationState;
 
     /**
      * Save the {@link ServiceState.RoamingType roaming type}. it can be overridden roaming type
@@ -144,15 +160,15 @@
     @NetworkType
     private int mAccessNetworkTechnology;
 
-    @NRStatus
-    private int mNrStatus;
+    @NRState
+    private int mNrState;
 
     private final int mRejectCause;
 
     private final boolean mEmergencyOnly;
 
     @ServiceType
-    private final int[] mAvailableServices;
+    private final ArrayList<Integer> mAvailableServices;
 
     @Nullable
     private CellIdentity mCellIdentity;
@@ -167,54 +183,56 @@
      * @param domain Network domain. Must be a {@link Domain}. For transport type
      * {@link AccessNetworkConstants#TRANSPORT_TYPE_WLAN}, this must set to {@link #DOMAIN_PS}.
      * @param transportType Transport type.
-     * @param regState Network registration state. Must be one of the {@link RegState}. For
-     * transport type {@link AccessNetworkConstants#TRANSPORT_TYPE_WLAN}, only
-     * {@link #REG_STATE_HOME} and {@link #REG_STATE_NOT_REG_NOT_SEARCHING} are valid states.
+     * @param registrationState Network registration state. For transport type
+     * {@link AccessNetworkConstants#TRANSPORT_TYPE_WLAN}, only
+     * {@link #REGISTRATION_STATE_HOME} and {@link #REGISTRATION_STATE_NOT_REGISTERED_OR_SEARCHING}
+     * are valid states.
      * @param accessNetworkTechnology Access network technology.For transport type
      * {@link AccessNetworkConstants#TRANSPORT_TYPE_WLAN}, set to
      * {@link TelephonyManager#NETWORK_TYPE_IWLAN}.
-     * @param rejectCause Reason for denial if the registration state is {@link #REG_STATE_DENIED}.
-     * Depending on {@code accessNetworkTechnology}, the values are defined in 3GPP TS 24.008
-     * 10.5.3.6 for UMTS, 3GPP TS 24.301 9.9.3.9 for LTE, and 3GPP2 A.S0001 6.2.2.44 for CDMA. If
-     * the reject cause is not supported or unknown, set it to 0.
+     * @param rejectCause Reason for denial if the registration state is
+     * {@link #REGISTRATION_STATE_DENIED}. Depending on {@code accessNetworkTechnology}, the values
+     * are defined in 3GPP TS 24.008 10.5.3.6 for UMTS, 3GPP TS 24.301 9.9.3.9 for LTE, and 3GPP2
+     * A.S0001 6.2.2.44 for CDMA. If the reject cause is not supported or unknown, set it to 0.
      * // TODO: Add IWLAN reject cause reference
      * @param emergencyOnly True if this registration is for emergency only.
-     * @param availableServices The list of the supported services. Each element must be one of
-     * the {@link ServiceType}.
+     * @param availableServices The list of the supported services.
      * @param cellIdentity The identity representing a unique cell or wifi AP. Set to null if the
      * information is not available.
      */
-    public NetworkRegistrationInfo(@Domain int domain, @TransportType int transportType,
-                                   @RegState int regState,
+    private NetworkRegistrationInfo(@Domain int domain, @TransportType int transportType,
+                                   @RegistrationState int registrationState,
                                    @NetworkType int accessNetworkTechnology, int rejectCause,
                                    boolean emergencyOnly,
-                                   @NonNull @ServiceType int[] availableServices,
+                                   @Nullable @ServiceType List<Integer> availableServices,
                                    @Nullable CellIdentity cellIdentity) {
         mDomain = domain;
         mTransportType = transportType;
-        mRegState = regState;
-        mRoamingType = (regState == REG_STATE_ROAMING)
+        mRegistrationState = registrationState;
+        mRoamingType = (registrationState == REGISTRATION_STATE_ROAMING)
                 ? ServiceState.ROAMING_TYPE_UNKNOWN : ServiceState.ROAMING_TYPE_NOT_ROAMING;
         mAccessNetworkTechnology = accessNetworkTechnology;
         mRejectCause = rejectCause;
-        mAvailableServices = availableServices;
+        mAvailableServices = (availableServices != null)
+                ? new ArrayList<>(availableServices) : new ArrayList<>();
         mCellIdentity = cellIdentity;
         mEmergencyOnly = emergencyOnly;
-        mNrStatus = NR_STATUS_NONE;
+        mNrState = NR_STATE_NONE;
     }
 
     /**
      * Constructor for voice network registration info.
      * @hide
      */
-    public NetworkRegistrationInfo(int domain, @TransportType int transportType, int regState,
-                                   int accessNetworkTechnology, int rejectCause,
-                                   boolean emergencyOnly, int[] availableServices,
+    public NetworkRegistrationInfo(int domain, @TransportType int transportType,
+                                   int registrationState, int accessNetworkTechnology,
+                                   int rejectCause, boolean emergencyOnly,
+                                   @Nullable List<Integer> availableServices,
                                    @Nullable CellIdentity cellIdentity, boolean cssSupported,
                                    int roamingIndicator, int systemIsInPrl,
                                    int defaultRoamingIndicator) {
-        this(domain, transportType, regState, accessNetworkTechnology, rejectCause, emergencyOnly,
-                availableServices, cellIdentity);
+        this(domain, transportType, registrationState, accessNetworkTechnology, rejectCause,
+                emergencyOnly, availableServices, cellIdentity);
 
         mVoiceSpecificStates = new VoiceSpecificRegistrationStates(cssSupported, roamingIndicator,
                 systemIsInPrl, defaultRoamingIndicator);
@@ -224,42 +242,44 @@
      * Constructor for data network registration info.
      * @hide
      */
-    public NetworkRegistrationInfo(int domain, @TransportType int transportType, int regState,
-                                   int accessNetworkTechnology, int rejectCause,
-                                   boolean emergencyOnly, int[] availableServices,
+    public NetworkRegistrationInfo(int domain, @TransportType int transportType,
+                                   int registrationState, int accessNetworkTechnology,
+                                   int rejectCause, boolean emergencyOnly,
+                                   @Nullable List<Integer> availableServices,
                                    @Nullable CellIdentity cellIdentity, int maxDataCalls,
                                    boolean isDcNrRestricted, boolean isNrAvailable,
                                    boolean isEndcAvailable,
                                    LteVopsSupportInfo lteVopsSupportInfo) {
-        this(domain, transportType, regState, accessNetworkTechnology, rejectCause, emergencyOnly,
-                availableServices, cellIdentity);
+        this(domain, transportType, registrationState, accessNetworkTechnology, rejectCause,
+                emergencyOnly, availableServices, cellIdentity);
 
         mDataSpecificStates = new DataSpecificRegistrationStates(
                 maxDataCalls, isDcNrRestricted, isNrAvailable, isEndcAvailable, lteVopsSupportInfo);
-        updateNrStatus(mDataSpecificStates);
+        updateNrState(mDataSpecificStates);
     }
 
     private NetworkRegistrationInfo(Parcel source) {
         mDomain = source.readInt();
         mTransportType = source.readInt();
-        mRegState = source.readInt();
+        mRegistrationState = source.readInt();
         mRoamingType = source.readInt();
         mAccessNetworkTechnology = source.readInt();
         mRejectCause = source.readInt();
         mEmergencyOnly = source.readBoolean();
-        mAvailableServices = source.createIntArray();
+        mAvailableServices = new ArrayList<>();
+        source.readList(mAvailableServices, Integer.class.getClassLoader());
         mCellIdentity = source.readParcelable(CellIdentity.class.getClassLoader());
         mVoiceSpecificStates = source.readParcelable(
                 VoiceSpecificRegistrationStates.class.getClassLoader());
         mDataSpecificStates = source.readParcelable(
                 DataSpecificRegistrationStates.class.getClassLoader());
-        mNrStatus = source.readInt();
+        mNrState = source.readInt();
     }
 
     /**
      * @return The transport type.
      */
-    public int getTransportType() { return mTransportType; }
+    public @TransportType int getTransportType() { return mTransportType; }
 
     /**
      * @return The network domain.
@@ -267,23 +287,23 @@
     public @Domain int getDomain() { return mDomain; }
 
     /**
-     * @return the 5G NR connection status.
+     * @return the 5G NR connection state.
      * @hide
      */
-    public @NRStatus int getNrStatus() {
-        return mNrStatus;
+    public @NRState int getNrState() {
+        return mNrState;
     }
 
     /** @hide */
-    public void setNrStatus(@NRStatus int nrStatus) {
-        mNrStatus = nrStatus;
+    public void setNrState(@NRState int nrState) {
+        mNrState = nrState;
     }
 
     /**
      * @return The registration state.
      */
-    public @RegState int getRegState() {
-        return mRegState;
+    public @RegistrationState int getRegistrationState() {
+        return mRegistrationState;
     }
 
     /**
@@ -298,7 +318,8 @@
      * @return {@code true} if in service.
      */
     public boolean isInService() {
-        return mRegState == REG_STATE_HOME || mRegState == REG_STATE_ROAMING;
+        return mRegistrationState == REGISTRATION_STATE_HOME
+                || mRegistrationState == REGISTRATION_STATE_ROAMING;
     }
 
     /**
@@ -328,7 +349,9 @@
      */
     @NonNull
     @ServiceType
-    public int[] getAvailableServices() { return mAvailableServices; }
+    public List<Integer> getAvailableServices() {
+        return Collections.unmodifiableList(mAvailableServices);
+    }
 
     /**
      * @return The access network technology {@link NetworkType}.
@@ -346,7 +369,7 @@
     }
 
     /**
-     * @return Reason for denial if the registration state is {@link #REG_STATE_DENIED}.
+     * @return Reason for denial if the registration state is {@link #REGISTRATION_STATE_DENIED}.
      * Depending on {@code accessNetworkTechnology}, the values are defined in 3GPP TS 24.008
      * 10.5.3.6 for UMTS, 3GPP TS 24.301 9.9.3.9 for LTE, and 3GPP2 A.S0001 6.2.2.44 for CDMA
      */
@@ -407,28 +430,28 @@
      *
      * @hide
      *
-     * @param regState The registration state
+     * @param registrationState The registration state
      * @return The reg state in string
      */
-    public static String regStateToString(@RegState int regState) {
-        switch (regState) {
-            case REG_STATE_NOT_REG_NOT_SEARCHING: return "NOT_REG_NOT_SEARCHING";
-            case REG_STATE_HOME: return "HOME";
-            case REG_STATE_NOT_REG_SEARCHING: return "NOT_REG_SEARCHING";
-            case REG_STATE_DENIED: return "DENIED";
-            case REG_STATE_UNKNOWN: return "UNKNOWN";
-            case REG_STATE_ROAMING: return "ROAMING";
+    public static String registrationStateToString(@RegistrationState int registrationState) {
+        switch (registrationState) {
+            case REGISTRATION_STATE_NOT_REGISTERED_OR_SEARCHING: return "NOT_REG_OR_SEARCHING";
+            case REGISTRATION_STATE_HOME: return "HOME";
+            case REGISTRATION_STATE_NOT_REGISTERED_SEARCHING: return "NOT_REG_SEARCHING";
+            case REGISTRATION_STATE_DENIED: return "DENIED";
+            case REGISTRATION_STATE_UNKNOWN: return "UNKNOWN";
+            case REGISTRATION_STATE_ROAMING: return "ROAMING";
         }
-        return "Unknown reg state " + regState;
+        return "Unknown reg state " + registrationState;
     }
 
-    private static String nrStatusToString(@NRStatus int nrStatus) {
-        switch (nrStatus) {
-            case NR_STATUS_RESTRICTED:
+    private static String nrStateToString(@NRState int nrState) {
+        switch (nrState) {
+            case NR_STATE_RESTRICTED:
                 return "RESTRICTED";
-            case NR_STATUS_NOT_RESTRICTED:
+            case NR_STATE_NOT_RESTRICTED:
                 return "NOT_RESTRICTED";
-            case NR_STATUS_CONNECTED:
+            case NR_STATE_CONNECTED:
                 return "CONNECTED";
             default:
                 return "NONE";
@@ -441,28 +464,27 @@
                 .append(" domain=").append((mDomain == DOMAIN_CS) ? "CS" : "PS")
                 .append(" transportType=").append(
                         AccessNetworkConstants.transportTypeToString(mTransportType))
-                .append(" regState=").append(regStateToString(mRegState))
+                .append(" registrationState=").append(registrationStateToString(mRegistrationState))
                 .append(" roamingType=").append(ServiceState.roamingTypeToString(mRoamingType))
                 .append(" accessNetworkTechnology=")
                 .append(TelephonyManager.getNetworkTypeName(mAccessNetworkTechnology))
                 .append(" rejectCause=").append(mRejectCause)
                 .append(" emergencyEnabled=").append(mEmergencyOnly)
                 .append(" availableServices=").append("[" + (mAvailableServices != null
-                        ? Arrays.stream(mAvailableServices)
-                        .mapToObj(type -> serviceTypeToString(type))
+                        ? mAvailableServices.stream().map(type -> serviceTypeToString(type))
                         .collect(Collectors.joining(",")) : null) + "]")
                 .append(" cellIdentity=").append(mCellIdentity)
                 .append(" voiceSpecificStates=").append(mVoiceSpecificStates)
                 .append(" dataSpecificStates=").append(mDataSpecificStates)
-                .append(" nrStatus=").append(nrStatusToString(mNrStatus))
+                .append(" nrState=").append(nrStateToString(mNrState))
                 .append("}").toString();
     }
 
     @Override
     public int hashCode() {
-        return Objects.hash(mDomain, mTransportType, mRegState, mRoamingType,
+        return Objects.hash(mDomain, mTransportType, mRegistrationState, mRoamingType,
                 mAccessNetworkTechnology, mRejectCause, mEmergencyOnly, mAvailableServices,
-                mCellIdentity, mVoiceSpecificStates, mDataSpecificStates, mNrStatus);
+                mCellIdentity, mVoiceSpecificStates, mDataSpecificStates, mNrState);
     }
 
     @Override
@@ -476,37 +498,37 @@
         NetworkRegistrationInfo other = (NetworkRegistrationInfo) o;
         return mDomain == other.mDomain
                 && mTransportType == other.mTransportType
-                && mRegState == other.mRegState
+                && mRegistrationState == other.mRegistrationState
                 && mRoamingType == other.mRoamingType
                 && mAccessNetworkTechnology == other.mAccessNetworkTechnology
                 && mRejectCause == other.mRejectCause
                 && mEmergencyOnly == other.mEmergencyOnly
-                && Arrays.equals(mAvailableServices, other.mAvailableServices)
+                && mAvailableServices.equals(other.mAvailableServices)
                 && Objects.equals(mCellIdentity, other.mCellIdentity)
                 && Objects.equals(mVoiceSpecificStates, other.mVoiceSpecificStates)
                 && Objects.equals(mDataSpecificStates, other.mDataSpecificStates)
-                && mNrStatus == other.mNrStatus;
+                && mNrState == other.mNrState;
     }
 
     @Override
     public void writeToParcel(Parcel dest, int flags) {
         dest.writeInt(mDomain);
         dest.writeInt(mTransportType);
-        dest.writeInt(mRegState);
+        dest.writeInt(mRegistrationState);
         dest.writeInt(mRoamingType);
         dest.writeInt(mAccessNetworkTechnology);
         dest.writeInt(mRejectCause);
         dest.writeBoolean(mEmergencyOnly);
-        dest.writeIntArray(mAvailableServices);
+        dest.writeList(mAvailableServices);
         dest.writeParcelable(mCellIdentity, 0);
         dest.writeParcelable(mVoiceSpecificStates, 0);
         dest.writeParcelable(mDataSpecificStates, 0);
-        dest.writeInt(mNrStatus);
+        dest.writeInt(mNrState);
     }
 
     /**
      * Use the 5G NR Non-Standalone indicators from the network registration state to update the
-     * NR status. There are 3 indicators in the network registration state:
+     * NR state. There are 3 indicators in the network registration state:
      *
      * 1. if E-UTRA-NR Dual Connectivity (EN-DC) is supported by the primary serving cell.
      * 2. if NR is supported by the selected PLMN.
@@ -521,13 +543,13 @@
      *
      * @param state data specific registration state contains the 5G NR indicators.
      */
-    private void updateNrStatus(DataSpecificRegistrationStates state) {
-        mNrStatus = NR_STATUS_NONE;
+    private void updateNrState(DataSpecificRegistrationStates state) {
+        mNrState = NR_STATE_NONE;
         if (state.isEnDcAvailable) {
             if (!state.isDcNrRestricted && state.isNrAvailable) {
-                mNrStatus = NR_STATUS_NOT_RESTRICTED;
+                mNrState = NR_STATE_NOT_RESTRICTED;
             } else {
-                mNrStatus = NR_STATUS_RESTRICTED;
+                mNrState = NR_STATE_RESTRICTED;
             }
         }
     }
@@ -571,40 +593,31 @@
      *
      * <pre><code>
      *
-     * NetworkRegistrationInfo nrs = new NetworkRegistrationInfo.Builder()
-     *     .setApnTypeBitmask(ApnSetting.TYPE_DEFAULT | ApnSetting.TYPE_MMS)
-     *     .setApnName("apn.example.com")
-     *     .setEntryName("Example Carrier APN")
-     *     .setMmsc(Uri.parse("http://mms.example.com:8002"))
-     *     .setMmsProxyAddress(mmsProxy)
-     *     .setMmsProxyPort(8799)
+     * NetworkRegistrationInfo nri = new NetworkRegistrationInfo.Builder()
+     *     .setAccessNetworkTechnology(TelephonyManager.NETWORK_TYPE_LTE)
+     *     .setRegistrationState(REGISTRATION_STATE_HOME)
      *     .build();
      * </code></pre>
      */
-    public static class Builder{
+    public static final class Builder{
         @Domain
         private int mDomain;
 
+        @TransportType
         private int mTransportType;
 
-        @RegState
-        private int mRegState;
-
-        @ServiceState.RoamingType
-        private int mRoamingType;
+        @RegistrationState
+        private int mRegistrationState;
 
         @NetworkType
         private int mAccessNetworkTechnology;
 
-        @NRStatus
-        private int mNrStatus;
-
         private int mRejectCause;
 
         private boolean mEmergencyOnly;
 
         @ServiceType
-        private int[] mAvailableServices;
+        private List<Integer> mAvailableServices;
 
         @Nullable
         private CellIdentity mCellIdentity;
@@ -641,24 +654,12 @@
         /**
          * Set the registration state.
          *
-         * @param regState The registration state.
+         * @param registrationState The registration state.
          *
          * @return The same instance of the builder.
          */
-        public @NonNull Builder setRegState(@RegState int regState) {
-            mRegState = regState;
-            return this;
-        }
-
-        /**
-         * Set the roaming type.
-         *
-         * @param roamingType Roaming type.
-         *
-         * @return The same instance of the builder.
-         */
-        public @NonNull Builder setRoamingType(@ServiceState.RoamingType int roamingType) {
-            mRoamingType = roamingType;
+        public @NonNull Builder setRegistrationState(@RegistrationState int registrationState) {
+            mRegistrationState = registrationState;
             return this;
         }
 
@@ -676,24 +677,13 @@
         }
 
         /**
-         * Set the 5G NR connection status.
-         *
-         * @param nrStatus 5G NR connection status.
-         *
-         * @return The same instance of the builder.
-         */
-        public @NonNull Builder setNrStatus(@NRStatus int nrStatus) {
-            mNrStatus = nrStatus;
-            return this;
-        }
-
-        /**
          * Set the network reject cause.
          *
          * @param rejectCause Reason for denial if the registration state is
-         * {@link #REG_STATE_DENIED}.Depending on {@code accessNetworkTechnology}, the values are
-         * defined in 3GPP TS 24.008 10.5.3.6 for UMTS, 3GPP TS 24.301 9.9.3.9 for LTE, and 3GPP2
-         * A.S0001 6.2.2.44 for CDMA. If the reject cause is not supported or unknown, set it to 0.
+         * {@link #REGISTRATION_STATE_DENIED}.Depending on {@code accessNetworkTechnology}, the
+         * values are defined in 3GPP TS 24.008 10.5.3.6 for UMTS, 3GPP TS 24.301 9.9.3.9 for LTE,
+         * and 3GPP2 A.S0001 6.2.2.44 for CDMA. If the reject cause is not supported or unknown, set
+         * it to 0.
          *
          * @return The same instance of the builder.
          */
@@ -722,7 +712,7 @@
          * @return The same instance of the builder.
          */
         public @NonNull Builder setAvailableServices(
-                @NonNull @ServiceType int[] availableServices) {
+                @NonNull @ServiceType List<Integer> availableServices) {
             mAvailableServices = availableServices;
             return this;
         }
@@ -745,7 +735,7 @@
          * @return the NetworkRegistrationInfo object.
          */
         public @NonNull NetworkRegistrationInfo build() {
-            return new NetworkRegistrationInfo(mDomain, mTransportType, mRegState,
+            return new NetworkRegistrationInfo(mDomain, mTransportType, mRegistrationState,
                     mAccessNetworkTechnology, mRejectCause, mEmergencyOnly, mAvailableServices,
                     mCellIdentity);
         }
diff --git a/telephony/java/android/telephony/NetworkService.java b/telephony/java/android/telephony/NetworkService.java
index bc989dd..8c5e107 100644
--- a/telephony/java/android/telephony/NetworkService.java
+++ b/telephony/java/android/telephony/NetworkService.java
@@ -18,6 +18,7 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.SdkConstant;
 import android.annotation.SystemApi;
 import android.app.Service;
 import android.content.Intent;
@@ -54,7 +55,8 @@
 
     private final String TAG = NetworkService.class.getSimpleName();
 
-    public static final String NETWORK_SERVICE_INTERFACE = "android.telephony.NetworkService";
+    @SdkConstant(SdkConstant.SdkConstantType.SERVICE_ACTION)
+    public static final String SERVICE_INTERFACE = "android.telephony.NetworkService";
 
     private static final int NETWORK_SERVICE_CREATE_NETWORK_SERVICE_PROVIDER                 = 1;
     private static final int NETWORK_SERVICE_REMOVE_NETWORK_SERVICE_PROVIDER                 = 2;
@@ -104,13 +106,14 @@
         }
 
         /**
-         * API to get network registration info. The result will be passed to the callback.
+         * Request network registration info. The result will be passed to the callback.
+         *
          * @param domain Network domain
          * @param callback The callback for reporting network registration info
          */
-        public void getNetworkRegistrationInfo(@Domain int domain,
-                                               @NonNull NetworkServiceCallback callback) {
-            callback.onGetNetworkRegistrationInfoComplete(
+        public void requestNetworkRegistrationInfo(@Domain int domain,
+                                                   @NonNull NetworkServiceCallback callback) {
+            callback.onRequestNetworkRegistrationInfoComplete(
                     NetworkServiceCallback.RESULT_ERROR_UNSUPPORTED, null);
         }
 
@@ -192,7 +195,7 @@
                 case NETWORK_SERVICE_GET_REGISTRATION_INFO:
                     if (serviceProvider == null) break;
                     int domainId = message.arg2;
-                    serviceProvider.getNetworkRegistrationInfo(domainId,
+                    serviceProvider.requestNetworkRegistrationInfo(domainId,
                             new NetworkServiceCallback(callback));
 
                     break;
@@ -231,14 +234,15 @@
      * will call this method after binding the network service for each active SIM slot id.
      *
      * @param slotIndex SIM slot id the network service associated with.
-     * @return Network service object
+     * @return Network service object. Null if failed to create the provider (e.g. invalid slot
+     * index)
      */
     @Nullable
     public abstract NetworkServiceProvider onCreateNetworkServiceProvider(int slotIndex);
 
     @Override
     public IBinder onBind(Intent intent) {
-        if (intent == null || !NETWORK_SERVICE_INTERFACE.equals(intent.getAction())) {
+        if (intent == null || !SERVICE_INTERFACE.equals(intent.getAction())) {
             loge("Unexpected intent " + intent);
             return null;
         }
@@ -280,8 +284,8 @@
         }
 
         @Override
-        public void getNetworkRegistrationInfo(
-                int slotIndex, int domain, INetworkServiceCallback callback) {
+        public void requestNetworkRegistrationInfo(int slotIndex, int domain,
+                                                   INetworkServiceCallback callback) {
             mHandler.obtainMessage(NETWORK_SERVICE_GET_REGISTRATION_INFO, slotIndex,
                     domain, callback).sendToTarget();
         }
diff --git a/telephony/java/android/telephony/NetworkServiceCallback.java b/telephony/java/android/telephony/NetworkServiceCallback.java
index cc25240..1c64bcd 100644
--- a/telephony/java/android/telephony/NetworkServiceCallback.java
+++ b/telephony/java/android/telephony/NetworkServiceCallback.java
@@ -28,9 +28,9 @@
 
 /**
  * Network service callback. Object of this class is passed to NetworkServiceProvider upon
- * calling getNetworkRegistrationInfo, to receive asynchronous feedback from NetworkServiceProvider
- * upon onGetNetworkRegistrationInfoComplete. It's like a wrapper of INetworkServiceCallback
- * because INetworkServiceCallback can't be a parameter type in public APIs.
+ * calling requestNetworkRegistrationInfo, to receive asynchronous feedback from
+ * NetworkServiceProvider upon onRequestNetworkRegistrationInfoComplete. It's like a wrapper of
+ * INetworkServiceCallback because INetworkServiceCallback can't be a parameter type in public APIs.
  *
  * @hide
  */
@@ -70,20 +70,20 @@
 
     /**
      * Called to indicate result of
-     * {@link NetworkServiceProvider#getNetworkRegistrationInfo(int, NetworkServiceCallback)}
+     * {@link NetworkServiceProvider#requestNetworkRegistrationInfo(int, NetworkServiceCallback)}
      *
      * @param result Result status like {@link NetworkServiceCallback#RESULT_SUCCESS} or
-     *                {@link NetworkServiceCallback#RESULT_ERROR_UNSUPPORTED}
+     * {@link NetworkServiceCallback#RESULT_ERROR_UNSUPPORTED}
      * @param state The state information to be returned to callback.
      */
-    public void onGetNetworkRegistrationInfoComplete(int result,
-                                                      @Nullable NetworkRegistrationInfo state) {
+    public void onRequestNetworkRegistrationInfoComplete(int result,
+                                                         @Nullable NetworkRegistrationInfo state) {
         INetworkServiceCallback callback = mCallback.get();
         if (callback != null) {
             try {
-                callback.onGetNetworkRegistrationInfoComplete(result, state);
+                callback.onRequestNetworkRegistrationInfoComplete(result, state);
             } catch (RemoteException e) {
-                Rlog.e(mTag, "Failed to onGetNetworkRegistrationInfoComplete on the remote");
+                Rlog.e(mTag, "Failed to onRequestNetworkRegistrationInfoComplete on the remote");
             }
         } else {
             Rlog.e(mTag, "Weak reference of callback is null.");
diff --git a/telephony/java/android/telephony/ServiceState.java b/telephony/java/android/telephony/ServiceState.java
index adbe295..df31f50 100644
--- a/telephony/java/android/telephony/ServiceState.java
+++ b/telephony/java/android/telephony/ServiceState.java
@@ -30,7 +30,7 @@
 import android.telephony.AccessNetworkConstants.AccessNetworkType;
 import android.telephony.AccessNetworkConstants.TransportType;
 import android.telephony.NetworkRegistrationInfo.Domain;
-import android.telephony.NetworkRegistrationInfo.NRStatus;
+import android.telephony.NetworkRegistrationInfo.NRState;
 import android.text.TextUtils;
 
 import java.lang.annotation.Retention;
@@ -53,6 +53,9 @@
  *   <li>Operator name, short name and numeric id
  *   <li>Network selection mode
  * </ul>
+ *
+ * For historical reasons this class is not declared as final; however,
+ * it should be treated as though it were final.
  */
 public class ServiceState implements Parcelable {
 
@@ -647,7 +650,8 @@
         final NetworkRegistrationInfo regState = getNetworkRegistrationInfo(
                 NetworkRegistrationInfo.DOMAIN_PS, AccessNetworkConstants.TRANSPORT_TYPE_WWAN);
         if (regState != null) {
-            return (regState.getRegState() == NetworkRegistrationInfo.REG_STATE_ROAMING);
+            return regState.getRegistrationState()
+                    == NetworkRegistrationInfo.REGISTRATION_STATE_ROAMING;
         }
         return false;
     }
@@ -1133,10 +1137,10 @@
         NetworkRegistrationInfo regState = getNetworkRegistrationInfo(
                 NetworkRegistrationInfo.DOMAIN_CS, AccessNetworkConstants.TRANSPORT_TYPE_WWAN);
         if (regState == null) {
-            regState = new NetworkRegistrationInfo(
-                    NetworkRegistrationInfo.DOMAIN_CS, AccessNetworkConstants.TRANSPORT_TYPE_WWAN,
-                    ServiceState.ROAMING_TYPE_NOT_ROAMING, TelephonyManager.NETWORK_TYPE_UNKNOWN, 0,
-                    false, null, null);
+            regState = new NetworkRegistrationInfo.Builder()
+                    .setDomain(NetworkRegistrationInfo.DOMAIN_CS)
+                    .setTransportType(AccessNetworkConstants.TRANSPORT_TYPE_WWAN)
+                    .build();
             addNetworkRegistrationInfo(regState);
         }
         regState.setRoamingType(type);
@@ -1154,10 +1158,10 @@
         NetworkRegistrationInfo regState = getNetworkRegistrationInfo(
                 NetworkRegistrationInfo.DOMAIN_PS, AccessNetworkConstants.TRANSPORT_TYPE_WWAN);
         if (regState == null) {
-            regState = new NetworkRegistrationInfo(
-                    NetworkRegistrationInfo.DOMAIN_PS, AccessNetworkConstants.TRANSPORT_TYPE_WWAN,
-                    ServiceState.ROAMING_TYPE_NOT_ROAMING, TelephonyManager.NETWORK_TYPE_UNKNOWN, 0,
-                    false, null, null);
+            regState = new NetworkRegistrationInfo.Builder()
+                    .setDomain(NetworkRegistrationInfo.DOMAIN_PS)
+                    .setTransportType(AccessNetworkConstants.TRANSPORT_TYPE_WWAN)
+                    .build();
             addNetworkRegistrationInfo(regState);
         }
         regState.setRoamingType(type);
@@ -1329,10 +1333,10 @@
         NetworkRegistrationInfo regState = getNetworkRegistrationInfo(
                 NetworkRegistrationInfo.DOMAIN_CS, AccessNetworkConstants.TRANSPORT_TYPE_WWAN);
         if (regState == null) {
-            regState = new NetworkRegistrationInfo(
-                    NetworkRegistrationInfo.DOMAIN_CS, AccessNetworkConstants.TRANSPORT_TYPE_WWAN,
-                    ServiceState.ROAMING_TYPE_NOT_ROAMING, TelephonyManager.NETWORK_TYPE_UNKNOWN,
-                    0, false, null, null);
+            regState = new NetworkRegistrationInfo.Builder()
+                    .setDomain(NetworkRegistrationInfo.DOMAIN_CS)
+                    .setTransportType(AccessNetworkConstants.TRANSPORT_TYPE_WWAN)
+                    .build();
             addNetworkRegistrationInfo(regState);
         }
         regState.setAccessNetworkTechnology(
@@ -1357,10 +1361,10 @@
                 NetworkRegistrationInfo.DOMAIN_PS, AccessNetworkConstants.TRANSPORT_TYPE_WWAN);
 
         if (regState == null) {
-            regState = new NetworkRegistrationInfo(
-                    NetworkRegistrationInfo.DOMAIN_PS, AccessNetworkConstants.TRANSPORT_TYPE_WWAN,
-                    ServiceState.ROAMING_TYPE_NOT_ROAMING, TelephonyManager.NETWORK_TYPE_UNKNOWN,
-                    0, false, null, null);
+            regState = new NetworkRegistrationInfo.Builder()
+                    .setDomain(NetworkRegistrationInfo.DOMAIN_PS)
+                    .setTransportType(AccessNetworkConstants.TRANSPORT_TYPE_WWAN)
+                    .build();
             addNetworkRegistrationInfo(regState);
         }
         regState.setAccessNetworkTechnology(
@@ -1386,15 +1390,15 @@
     }
 
     /**
-     * Get the NR 5G status of the mobile data network.
-     * @return the NR 5G status.
+     * Get the NR 5G state of the mobile data network.
+     * @return the NR 5G state.
      * @hide
      */
-    public @NRStatus int getNrStatus() {
+    public @NRState int getNrState() {
         final NetworkRegistrationInfo regState = getNetworkRegistrationInfo(
                 NetworkRegistrationInfo.DOMAIN_PS, AccessNetworkConstants.TRANSPORT_TYPE_WWAN);
-        if (regState == null) return NetworkRegistrationInfo.NR_STATUS_NONE;
-        return regState.getNrStatus();
+        if (regState == null) return NetworkRegistrationInfo.NR_STATE_NONE;
+        return regState.getNrState();
     }
 
     /**
@@ -1578,11 +1582,11 @@
     public @TelephonyManager.NetworkType int getDataNetworkType() {
         final NetworkRegistrationInfo iwlanRegState = getNetworkRegistrationInfo(
                 NetworkRegistrationInfo.DOMAIN_PS, AccessNetworkConstants.TRANSPORT_TYPE_WLAN);
-        if (iwlanRegState != null
-                && iwlanRegState.getRegState() == NetworkRegistrationInfo.REG_STATE_HOME) {
+        if (iwlanRegState != null && iwlanRegState.getRegistrationState()
+                == NetworkRegistrationInfo.REGISTRATION_STATE_HOME) {
             // If the device is on IWLAN, return IWLAN as the network type. This is to simulate the
             // behavior of legacy mode device. In the future caller should use
-            // getNetworkRegistrationInfo() to retrieve the actual data network type on cellular
+            // requestNetworkRegistrationInfo() to retrieve the actual data network type on cellular
             // or on IWLAN.
             return iwlanRegState.getAccessNetworkTechnology();
         }
diff --git a/telephony/java/android/telephony/SubscriptionInfo.java b/telephony/java/android/telephony/SubscriptionInfo.java
index 245f5b3..ac11940 100644
--- a/telephony/java/android/telephony/SubscriptionInfo.java
+++ b/telephony/java/android/telephony/SubscriptionInfo.java
@@ -161,11 +161,6 @@
     private String mGroupUUID;
 
     /**
-     *  A property in opportunistic subscription to indicate whether it is metered or not.
-     */
-    private boolean mIsMetered;
-
-    /**
      * Whether group of the subscription is disabled.
      * This is only useful if it's a grouped opportunistic subscription. In this case, if all
      * primary (non-opportunistic) subscriptions in the group are deactivated (unplugged pSIM
@@ -197,7 +192,7 @@
             @Nullable UiccAccessRule[] accessRules, String cardString) {
         this(id, iccId, simSlotIndex, displayName, carrierName, nameSource, iconTint, number,
                 roaming, icon, mcc, mnc, countryIso, isEmbedded, accessRules, cardString,
-                false, null, true, TelephonyManager.UNKNOWN_CARRIER_ID,
+                false, null, TelephonyManager.UNKNOWN_CARRIER_ID,
                 SubscriptionManager.PROFILE_CLASS_DEFAULT);
     }
 
@@ -208,10 +203,10 @@
             CharSequence carrierName, int nameSource, int iconTint, String number, int roaming,
             Bitmap icon, String mcc, String mnc, String countryIso, boolean isEmbedded,
             @Nullable UiccAccessRule[] accessRules, String cardString, boolean isOpportunistic,
-            @Nullable String groupUUID, boolean isMetered, int carrierId, int profileClass) {
+            @Nullable String groupUUID, int carrierId, int profileClass) {
         this(id, iccId, simSlotIndex, displayName, carrierName, nameSource, iconTint, number,
                 roaming, icon, mcc, mnc, countryIso, isEmbedded, accessRules, cardString, -1,
-                isOpportunistic, groupUUID, isMetered, false, carrierId, profileClass,
+                isOpportunistic, groupUUID, false, carrierId, profileClass,
                 SubscriptionManager.SUBSCRIPTION_TYPE_LOCAL_SIM);
     }
 
@@ -222,7 +217,7 @@
             CharSequence carrierName, int nameSource, int iconTint, String number, int roaming,
             Bitmap icon, String mcc, String mnc, String countryIso, boolean isEmbedded,
             @Nullable UiccAccessRule[] accessRules, String cardString, int cardId,
-            boolean isOpportunistic, @Nullable String groupUUID, boolean isMetered,
+            boolean isOpportunistic, @Nullable String groupUUID,
             boolean isGroupDisabled, int carrierId, int profileClass, int subType) {
         this.mId = id;
         this.mIccId = iccId;
@@ -243,7 +238,6 @@
         this.mCardId = cardId;
         this.mIsOpportunistic = isOpportunistic;
         this.mGroupUUID = groupUUID;
-        this.mIsMetered = isMetered;
         this.mIsGroupDisabled = isGroupDisabled;
         this.mCarrierId = carrierId;
         this.mProfileClass = profileClass;
@@ -472,18 +466,6 @@
     }
 
     /**
-     * Used in opportunistic subscription ({@link #isOpportunistic()}) to indicate whether it's
-     * metered or not.This is one of the factors when deciding to switch to the subscription.
-     * (a non-metered subscription, for example, would likely be preferred over a metered one).
-     *
-     * @return whether subscription is metered.
-     * @hide
-     */
-    public boolean isMetered() {
-        return mIsMetered;
-    }
-
-    /**
      * @return the profile class of this subscription.
      * @hide
      */
@@ -624,7 +606,6 @@
             int cardId = source.readInt();
             boolean isOpportunistic = source.readBoolean();
             String groupUUID = source.readString();
-            boolean isMetered = source.readBoolean();
             boolean isGroupDisabled = source.readBoolean();
             int carrierid = source.readInt();
             int profileClass = source.readInt();
@@ -633,7 +614,7 @@
             return new SubscriptionInfo(id, iccId, simSlotIndex, displayName, carrierName,
                     nameSource, iconTint, number, dataRoaming, iconBitmap, mcc, mnc, countryIso,
                     isEmbedded, accessRules, cardString, cardId, isOpportunistic, groupUUID,
-                    isMetered, isGroupDisabled, carrierid, profileClass, subType);
+                    isGroupDisabled, carrierid, profileClass, subType);
         }
 
         @Override
@@ -663,7 +644,6 @@
         dest.writeInt(mCardId);
         dest.writeBoolean(mIsOpportunistic);
         dest.writeString(mGroupUUID);
-        dest.writeBoolean(mIsMetered);
         dest.writeBoolean(mIsGroupDisabled);
         dest.writeInt(mCarrierId);
         dest.writeInt(mProfileClass);
@@ -703,7 +683,7 @@
                 + " accessRules " + Arrays.toString(mAccessRules)
                 + " cardString=" + cardStringToPrint + " cardId=" + mCardId
                 + " isOpportunistic " + mIsOpportunistic + " mGroupUUID=" + mGroupUUID
-                + " isMetered=" + mIsMetered + " mIsGroupDisabled=" + mIsGroupDisabled
+                + " mIsGroupDisabled=" + mIsGroupDisabled
                 + " profileClass=" + mProfileClass
                 + " subscriptionType=" + mSubscriptionType + "}";
     }
@@ -711,7 +691,7 @@
     @Override
     public int hashCode() {
         return Objects.hash(mId, mSimSlotIndex, mNameSource, mIconTint, mDataRoaming, mIsEmbedded,
-                mIsOpportunistic, mGroupUUID, mIsMetered, mIccId, mNumber, mMcc, mMnc,
+                mIsOpportunistic, mGroupUUID, mIccId, mNumber, mMcc, mMnc,
                 mCountryIso, mCardString, mCardId, mDisplayName, mCarrierName, mAccessRules,
                 mIsGroupDisabled, mCarrierId, mProfileClass);
     }
@@ -737,7 +717,6 @@
                 && mIsOpportunistic == toCompare.mIsOpportunistic
                 && mIsGroupDisabled == toCompare.mIsGroupDisabled
                 && mCarrierId == toCompare.mCarrierId
-                && mIsMetered == toCompare.mIsMetered
                 && Objects.equals(mGroupUUID, toCompare.mGroupUUID)
                 && Objects.equals(mIccId, toCompare.mIccId)
                 && Objects.equals(mNumber, toCompare.mNumber)
diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java
index 3707aa4..2edef83 100644
--- a/telephony/java/android/telephony/SubscriptionManager.java
+++ b/telephony/java/android/telephony/SubscriptionManager.java
@@ -2595,7 +2595,9 @@
      *              {@link SubscriptionManager#DEFAULT_SUBSCRIPTION_ID}, it means
      *              it's unset and {@link SubscriptionManager#getDefaultDataSubscriptionId()}
      *              is used to determine which modem is preferred.
-     * @param needValidation whether validation is needed before switch happens.
+     * @param needValidation whether Telephony will wait until the network is validated by
+     *              connectivity service before switching data to it. More details see
+     *              {@link NetworkCapabilities#NET_CAPABILITY_VALIDATED}.
      * @param executor The executor of where the callback will execute.
      * @param callback Callback will be triggered once it succeeds or failed.
      *                 See {@link TelephonyManager.SetOpportunisticSubscriptionResult}
@@ -2853,29 +2855,6 @@
     }
 
     /**
-     * Set if a subscription is metered or not. Similar to Wi-Fi, metered means
-     * user may be charged more if more data is used.
-     *
-     * By default all Cellular networks are considered metered. System or carrier privileged apps
-     * can set a subscription un-metered which will be considered when system switches data between
-     * primary subscription and opportunistic subscription.
-     *
-     * Caller will either have {@link android.Manifest.permission#MODIFY_PHONE_STATE} or carrier
-     * privilege permission of the subscription.
-     *
-     * @param isMetered whether it’s a metered subscription.
-     * @param subId the unique SubscriptionInfo index in database
-     * @return {@code true} if the operation is succeed, {@code false} otherwise.
-     */
-    @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges
-    @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
-    public boolean setMetered(boolean isMetered, int subId) {
-        if (VDBG) logd("[setIsMetered]+ isMetered:" + isMetered + " subId:" + subId);
-        return setSubscriptionPropertyHelper(subId, "setIsMetered",
-                (iSub)-> iSub.setMetered(isMetered, subId, mContext.getOpPackageName())) == 1;
-    }
-
-    /**
      * Whether a subscription is visible to API caller. If it's a bundled opportunistic
      * subscription, it should be hidden anywhere in Settings, dialer, status bar etc.
      * Exception is if caller owns carrier privilege, in which case they will
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index f7ab921..d296b2f 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -58,6 +58,8 @@
 import android.os.WorkSource;
 import android.provider.Settings.SettingNotFoundException;
 import android.service.carrier.CarrierIdentifier;
+import android.telecom.CallScreeningService;
+import android.telecom.InCallService;
 import android.telecom.PhoneAccount;
 import android.telecom.PhoneAccountHandle;
 import android.telecom.TelecomManager;
@@ -617,7 +619,13 @@
      * <p class="note">
      * Retrieve with
      * {@link android.content.Intent#getStringExtra(String)}.
+     * <p>
+     *
+     * @deprecated Companion apps for wearable devices should use the {@link InCallService} API
+     * to retrieve the phone number for calls instead.  Apps performing call screening should use
+     * the {@link CallScreeningService} API instead.
      */
+    @Deprecated
     public static final String EXTRA_INCOMING_NUMBER = "incoming_number";
 
     /**
@@ -4771,18 +4779,22 @@
      * Registers a listener object to receive notification of changes
      * in specified telephony states.
      * <p>
-     * To register a listener, pass a {@link PhoneStateListener}
-     * and specify at least one telephony state of interest in
-     * the events argument.
+     * To register a listener, pass a {@link PhoneStateListener} and specify at least one telephony
+     * state of interest in the events argument.
      *
-     * At registration, and when a specified telephony state
-     * changes, the telephony manager invokes the appropriate
-     * callback method on the listener object and passes the
-     * current (updated) values.
+     * At registration, and when a specified telephony state changes, the telephony manager invokes
+     * the appropriate callback method on the listener object and passes the current (updated)
+     * values.
      * <p>
-     * To unregister a listener, pass the listener object and set the
-     * events argument to
+     * To un-register a listener, pass the listener object and set the events argument to
      * {@link PhoneStateListener#LISTEN_NONE LISTEN_NONE} (0).
+     *
+     * If this TelephonyManager object has been created with {@link #createForSubscriptionId},
+     * applies to the given subId. Otherwise, applies to
+     * {@link SubscriptionManager#getDefaultSubscriptionId()}. To listen events for multiple subIds,
+     * pass a separate listener object to each TelephonyManager object created with
+     * {@link #createForSubscriptionId}.
+     *
      * Note: if you call this method while in the middle of a binder transaction, you <b>must</b>
      * call {@link android.os.Binder#clearCallingIdentity()} before calling this method. A
      * {@link SecurityException} will be thrown otherwise.
@@ -4797,17 +4809,18 @@
         if (mContext == null) return;
         try {
             boolean notifyNow = (getITelephony() != null);
-            // If the listener has not explicitly set the subId (for example, created with the
-            // default constructor), replace the subId so it will listen to the account the
-            // telephony manager is created with.
-            if (listener.mSubId == null) {
-                listener.mSubId = mSubId;
-            }
-
             ITelephonyRegistry registry = getTelephonyRegistry();
             if (registry != null) {
-                registry.listenForSubscriber(listener.mSubId, getOpPackageName(),
+                // listen to the subId the telephony manager is created with. Ignore subId in
+                // PhoneStateListener.
+                registry.listenForSubscriber(mSubId, getOpPackageName(),
                         listener.callback, events, notifyNow);
+                // TODO: remove this once we remove PhoneStateListener constructor with subId.
+                if (events == PhoneStateListener.LISTEN_NONE) {
+                    listener.mSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
+                } else {
+                    listener.mSubId = mSubId;
+                }
             } else {
                 Rlog.w(TAG, "telephony registry not ready.");
             }
@@ -5283,7 +5296,6 @@
      */
     @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE)
     @SystemApi
-    @Nullable
     public boolean iccCloseLogicalChannelBySlot(int slotIndex, int channel) {
         try {
             ITelephony telephony = getITelephony();
@@ -5360,8 +5372,8 @@
      * @param p3 P3 value of the APDU command. If p3 is negative a 4 byte APDU
      *            is sent to the SIM.
      * @param data Data to be sent with the APDU.
-     * @return The APDU response from the ICC card with the status appended at
-     *            the end.
+     * @return The APDU response from the ICC card with the status appended at the end, or null if
+     * there is an issue connecting to the Telephony service.
      * @hide
      */
     @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE)
@@ -8285,7 +8297,7 @@
      * @see SubscriptionManager#getDefaultSubscriptionId()
      * @hide
      */
-    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
+    @UnsupportedAppUsage
     public boolean isVolteAvailable() {
         try {
             return getITelephony().isAvailable(getSubId(),
@@ -8304,7 +8316,7 @@
      * @return true if VT is available, or false if it is unavailable or unknown.
      * @hide
      */
-    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
+    @UnsupportedAppUsage
     public boolean isVideoTelephonyAvailable() {
         try {
             return getITelephony().isVideoTelephonyAvailable(getSubId());
@@ -8319,7 +8331,7 @@
      * @return true if VoWiFi is available, or false if it is unavailable or unknown.
      * @hide
      */
-    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
+    @UnsupportedAppUsage
     public boolean isWifiCallingAvailable() {
        try {
            return getITelephony().isWifiCallingAvailable(getSubId());
@@ -9857,8 +9869,11 @@
      * <p>Requires Permission:
      *   {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}
      *
+     *
+     * @deprecated
      * @hide
      */
+    @Deprecated
     @TestApi
     public void setCarrierTestOverride(String mccmnc, String imsi, String iccid, String gid1,
             String gid2, String plmn, String spn) {
@@ -9866,7 +9881,35 @@
             ITelephony telephony = getITelephony();
             if (telephony != null) {
                 telephony.setCarrierTestOverride(
-                        getSubId(), mccmnc, imsi, iccid, gid1, gid2, plmn, spn);
+                        getSubId(), mccmnc, imsi, iccid, gid1, gid2, plmn, spn,
+                        null, null);
+            }
+        } catch (RemoteException ex) {
+            // This could happen if binder process crashes.
+        }
+    }
+
+    /**
+     * A test API to override carrier information including mccmnc, imsi, iccid, gid1, gid2,
+     * plmn, spn, apn and carrier priviledge. This would be handy for, eg, forcing a particular
+     * carrier id, carrier's config (also any country or carrier overlays) to be loaded when using
+     * a test SIM with a call box.
+     *
+     * <p>Requires Permission:
+     *   {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}
+     *
+     * @hide
+     */
+    @TestApi
+    public void setCarrierTestOverride(String mccmnc, String imsi, String iccid, String gid1,
+                                       String gid2, String plmn, String spn,
+                                       String carrierPriviledgeRules, String apn) {
+        try {
+            ITelephony telephony = getITelephony();
+            if (telephony != null) {
+                telephony.setCarrierTestOverride(
+                        getSubId(), mccmnc, imsi, iccid, gid1, gid2, plmn, spn,
+                        carrierPriviledgeRules, apn);
             }
         } catch (RemoteException ex) {
             // This could happen if binder process crashes.
@@ -10149,6 +10192,24 @@
     }
 
     /**
+     * Determine whether the emergency assistance feature is available on the device.
+     * <p>
+     * Requires permission: {@link android.Manifest.permission#READ_PRIVILEGED_PHONE_STATE}
+     *
+     * @return whether the emergency assistance feature is available on the device
+     *
+     * @hide
+     */
+    @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+    @SystemApi
+    public boolean isEmergencyAssistanceEnabled() {
+        mContext.enforceCallingOrSelfPermission(
+                android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE,
+                "isEmergencyAssistanceEnabled");
+        return EMERGENCY_ASSISTANCE_ENABLED;
+    }
+
+    /**
      * Get the emergency number list based on current locale, sim, default, modem and network.
      *
      * <p>In each returned list, the emergency number {@link EmergencyNumber} coming from higher
@@ -10329,7 +10390,7 @@
     @IntDef(prefix = {"SET_OPPORTUNISTIC_SUB"}, value = {
             SET_OPPORTUNISTIC_SUB_SUCCESS,
             SET_OPPORTUNISTIC_SUB_VALIDATION_FAILED,
-            SET_OPPORTUNISTIC_SUB_INVALID_PARAMETER})
+            SET_OPPORTUNISTIC_SUB_INACTIVE_SUBSCRIPTION})
     public @interface SetOpportunisticSubscriptionResult {}
 
     /**
@@ -10343,9 +10404,9 @@
     public static final int SET_OPPORTUNISTIC_SUB_VALIDATION_FAILED = 1;
 
     /**
-     * The parameter passed in is invalid.
+     * The subscription is not valid. It must be an active opportunistic subscription.
      */
-    public static final int SET_OPPORTUNISTIC_SUB_INVALID_PARAMETER = 2;
+    public static final int SET_OPPORTUNISTIC_SUB_INACTIVE_SUBSCRIPTION = 2;
 
     /** @hide */
     @Retention(RetentionPolicy.SOURCE)
@@ -10565,45 +10626,77 @@
      * <p>Note: the API does not prevent access to the SIM cards for operations that don't require
      * access to the network.
      *
-     * @param isMultisimCarrierRestricted true if usage of multiple SIMs is restricted, false
+     * @param isMultiSimCarrierRestricted true if usage of multiple SIMs is restricted, false
      * otherwise.
      *
      * @hide
      */
     @SystemApi
     @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
-    public void setMultisimCarrierRestriction(boolean isMultisimCarrierRestricted) {
+    public void setMultiSimCarrierRestriction(boolean isMultiSimCarrierRestricted) {
         try {
             ITelephony service = getITelephony();
             if (service != null) {
-                service.setMultisimCarrierRestriction(isMultisimCarrierRestricted);
+                service.setMultiSimCarrierRestriction(isMultiSimCarrierRestricted);
             }
         } catch (RemoteException e) {
-            Log.e(TAG, "setMultisimCarrierRestriction RemoteException", e);
+            Log.e(TAG, "setMultiSimCarrierRestriction RemoteException", e);
         }
     }
 
     /**
+     * The usage of multiple SIM cards at the same time to register on the network (e.g. Dual
+     * Standby or Dual Active) is supported.
+     */
+    public static final int MULTISIM_ALLOWED = 0;
+
+    /**
+     * The usage of multiple SIM cards at the same time to register on the network (e.g. Dual
+     * Standby or Dual Active) is not supported by the hardware.
+     */
+    public static final int MULTISIM_NOT_SUPPORTED_BY_HARDWARE = 1;
+
+    /**
+     * The usage of multiple SIM cards at the same time to register on the network (e.g. Dual
+     * Standby or Dual Active) is supported by the hardware, but restricted by the carrier.
+     */
+    public static final int MULTISIM_NOT_SUPPORTED_BY_CARRIER = 2;
+
+    /** @hide */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(prefix = {"MULTISIM_"},
+            value = {
+                    MULTISIM_ALLOWED,
+                    MULTISIM_NOT_SUPPORTED_BY_HARDWARE,
+                    MULTISIM_NOT_SUPPORTED_BY_CARRIER
+            })
+    public @interface IsMultiSimSupportedResult {}
+
+    /**
      * Returns if the usage of multiple SIM cards at the same time to register on the network
      * (e.g. Dual Standby or Dual Active) is supported by the device and by the carrier.
      *
      * <p>Requires Permission: {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
      * or that the calling app has carrier privileges (see {@link #hasCarrierPrivileges}).
      *
-     * @return true if usage of multiple SIMs is supported, false otherwise.
+     * @return {@link #MULTISIM_ALLOWED} if the device supports multiple SIMs.
+     * {@link #MULTISIM_NOT_SUPPORTED_BY_HARDWARE} if the device does not support multiple SIMs.
+     * {@link #MULTISIM_NOT_SUPPORTED_BY_CARRIER} in the device supports multiple SIMs, but the
+     * functionality is restricted by the carrier.
      */
     @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges
     @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
-    public boolean isMultisimSupported() {
+    @IsMultiSimSupportedResult
+    public int isMultiSimSupported() {
         try {
             ITelephony service = getITelephony();
             if (service != null) {
-                return service.isMultisimSupported(getOpPackageName());
+                return service.isMultiSimSupported(getOpPackageName());
             }
         } catch (RemoteException e) {
-            Log.e(TAG, "isMultisimSupported RemoteException", e);
+            Log.e(TAG, "isMultiSimSupported RemoteException", e);
         }
-        return false;
+        return MULTISIM_NOT_SUPPORTED_BY_HARDWARE;
     }
 
     /**
diff --git a/telephony/java/android/telephony/data/DataCallResponse.java b/telephony/java/android/telephony/data/DataCallResponse.java
index 0622cdd..17699d7 100644
--- a/telephony/java/android/telephony/data/DataCallResponse.java
+++ b/telephony/java/android/telephony/data/DataCallResponse.java
@@ -17,16 +17,21 @@
 
 package android.telephony.data;
 
+import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.SystemApi;
 import android.net.LinkAddress;
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.telephony.DataFailCause;
+import android.telephony.DataFailCause.FailCause;
 import android.telephony.data.ApnSetting.ProtocolType;
 
 import com.android.internal.annotations.VisibleForTesting;
 
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
 import java.net.InetAddress;
 import java.util.ArrayList;
 import java.util.List;
@@ -39,83 +44,114 @@
  */
 @SystemApi
 public final class DataCallResponse implements Parcelable {
-    private final int mStatus;
+
+    /** {@hide} */
+    @IntDef(prefix = "LINK_STATUS_", value = {
+            LINK_STATUS_UNKNOWN,
+            LINK_STATUS_INACTIVE,
+            LINK_STATUS_DORMANT,
+            LINK_STATUS_ACTIVE
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface LinkStatus {}
+
+    /** Unknown status */
+    public static final int LINK_STATUS_UNKNOWN = -1;
+
+    /** Indicates the data connection is inactive. */
+    public static final int LINK_STATUS_INACTIVE = 0;
+
+    /** Indicates the data connection is active with physical link dormant. */
+    public static final int LINK_STATUS_DORMANT = 1;
+
+    /** Indicates the data connection is active with physical link up. */
+    public static final int LINK_STATUS_ACTIVE = 2;
+
+    private final @FailCause int mCause;
     private final int mSuggestedRetryTime;
-    private final int mCid;
-    private final int mActive;
-    private final int mProtocolType;
-    private final String mIfname;
+    private final int mId;
+    private final @LinkStatus int mLinkStatus;
+    private final @ProtocolType int mProtocolType;
+    private final String mInterfaceName;
     private final List<LinkAddress> mAddresses;
-    private final List<InetAddress> mDnses;
-    private final List<InetAddress> mGateways;
-    private final List<String> mPcscfs;
+    private final List<InetAddress> mDnsAddresses;
+    private final List<InetAddress> mGatewayAddresses;
+    private final List<InetAddress> mPcscfAddresses;
     private final int mMtu;
 
     /**
-     * @param status Data call fail cause. 0 indicates no error.
+     * @param cause Data call fail cause. {@link DataFailCause#NONE} indicates no error.
      * @param suggestedRetryTime The suggested data retry time in milliseconds.
-     * @param cid The unique id of the data connection.
-     * @param active Data connection active status. 0 = inactive, 1 = dormant, 2 = active.
+     * @param id The unique id of the data connection.
+     * @param linkStatus Data connection link status.
      * @param protocolType The connection protocol, should be one of the PDP_type values in 3GPP
-     *                     TS 27.007 section 10.1.1. For example, "IP", "IPV6", "IPV4V6", or "PPP".
-     * @param ifname The network interface name.
+     * TS 27.007 section 10.1.1. For example, "IP", "IPV6", "IPV4V6", or "PPP".
+     * @param interfaceName The network interface name.
      * @param addresses A list of addresses with optional "/" prefix length, e.g.,
-     *                  "192.0.1.3" or "192.0.1.11/16 2001:db8::1/64". Typically 1 IPv4 or 1 IPv6 or
-     *                  one of each. If the prefix length is absent the addresses are assumed to be
-     *                  point to point with IPv4 having a prefix length of 32 and IPv6 128.
-     * @param dnses A list of DNS server addresses, e.g., "192.0.1.3" or
-     *              "192.0.1.11 2001:db8::1". Null if no dns server addresses returned.
-     * @param gateways A list of default gateway addresses, e.g., "192.0.1.3" or
-     *                 "192.0.1.11 2001:db8::1". When null, the addresses represent point to point
-     *                 connections.
-     * @param pcscfs A list of Proxy Call State Control Function address via PCO(Protocol
-     *               Configuration Option) for IMS client.
-     * @param mtu MTU (Maximum transmission unit) received from network Value <= 0 means network has
-     *            either not sent a value or sent an invalid value.
+     * "192.0.1.3" or "192.0.1.11/16 2001:db8::1/64". Typically 1 IPv4 or 1 IPv6 or
+     * one of each. If the prefix length is absent the addresses are assumed to be
+     * point to point with IPv4 having a prefix length of 32 and IPv6 128.
+     * @param dnsAddresses A list of DNS server addresses, e.g., "192.0.1.3" or
+     * "192.0.1.11 2001:db8::1". Null if no dns server addresses returned.
+     * @param gatewayAddresses A list of default gateway addresses, e.g., "192.0.1.3" or
+     * "192.0.1.11 2001:db8::1". When null, the addresses represent point to point connections.
+     * @param pcscfAddresses A list of Proxy Call State Control Function address via PCO (Protocol
+     * Configuration Option) for IMS client.
+     * @param mtu MTU (maximum transmission unit) in bytes received from network. Zero or negative
+     * values means network has either not sent a value or sent an invalid value.
+     * either not sent a value or sent an invalid value.
+     *
+     * @removed Use the {@link Builder()} instead.
      */
-    public DataCallResponse(int status, int suggestedRetryTime, int cid, int active,
-                            @ProtocolType int protocolType, @Nullable String ifname,
+    public DataCallResponse(@FailCause int cause, int suggestedRetryTime, int id,
+                            @LinkStatus int linkStatus,
+                            @ProtocolType int protocolType, @Nullable String interfaceName,
                             @Nullable List<LinkAddress> addresses,
-                            @Nullable List<InetAddress> dnses,
-                            @Nullable List<InetAddress> gateways,
-                            @Nullable List<String> pcscfs, int mtu) {
-        mStatus = status;
+                            @Nullable List<InetAddress> dnsAddresses,
+                            @Nullable List<InetAddress> gatewayAddresses,
+                            @Nullable List<InetAddress> pcscfAddresses, int mtu) {
+        mCause = cause;
         mSuggestedRetryTime = suggestedRetryTime;
-        mCid = cid;
-        mActive = active;
+        mId = id;
+        mLinkStatus = linkStatus;
         mProtocolType = protocolType;
-        mIfname = (ifname == null) ? "" : ifname;
-        mAddresses = (addresses == null) ? new ArrayList<>() : addresses;
-        mDnses = (dnses == null) ? new ArrayList<>() : dnses;
-        mGateways = (gateways == null) ? new ArrayList<>() : gateways;
-        mPcscfs = (pcscfs == null) ? new ArrayList<>() : pcscfs;
+        mInterfaceName = (interfaceName == null) ? "" : interfaceName;
+        mAddresses = (addresses == null)
+                ? new ArrayList<>() : new ArrayList<>(addresses);
+        mDnsAddresses = (dnsAddresses == null)
+                ? new ArrayList<>() : new ArrayList<>(dnsAddresses);
+        mGatewayAddresses = (gatewayAddresses == null)
+                ? new ArrayList<>() : new ArrayList<>(gatewayAddresses);
+        mPcscfAddresses = (pcscfAddresses == null)
+                ? new ArrayList<>() : new ArrayList<>(pcscfAddresses);
         mMtu = mtu;
     }
 
     /** @hide */
     @VisibleForTesting
     public DataCallResponse(Parcel source) {
-        mStatus = source.readInt();
+        mCause = source.readInt();
         mSuggestedRetryTime = source.readInt();
-        mCid = source.readInt();
-        mActive = source.readInt();
+        mId = source.readInt();
+        mLinkStatus = source.readInt();
         mProtocolType = source.readInt();
-        mIfname = source.readString();
+        mInterfaceName = source.readString();
         mAddresses = new ArrayList<>();
         source.readList(mAddresses, LinkAddress.class.getClassLoader());
-        mDnses = new ArrayList<>();
-        source.readList(mDnses, InetAddress.class.getClassLoader());
-        mGateways = new ArrayList<>();
-        source.readList(mGateways, InetAddress.class.getClassLoader());
-        mPcscfs = new ArrayList<>();
-        source.readList(mPcscfs, InetAddress.class.getClassLoader());
+        mDnsAddresses = new ArrayList<>();
+        source.readList(mDnsAddresses, InetAddress.class.getClassLoader());
+        mGatewayAddresses = new ArrayList<>();
+        source.readList(mGatewayAddresses, InetAddress.class.getClassLoader());
+        mPcscfAddresses = new ArrayList<>();
+        source.readList(mPcscfAddresses, InetAddress.class.getClassLoader());
         mMtu = source.readInt();
     }
 
     /**
-     * @return Data call fail cause. 0 indicates no error.
+     * @return Data call fail cause. {@link DataFailCause#NONE} indicates no error.
      */
-    public int getStatus() { return mStatus; }
+    @FailCause
+    public int getCause() { return mCause; }
 
     /**
      * @return The suggested data retry time in milliseconds.
@@ -125,12 +161,12 @@
     /**
      * @return The unique id of the data connection.
      */
-    public int getCallId() { return mCid; }
+    public int getId() { return mId; }
 
     /**
-     * @return 0 = inactive, 1 = dormant, 2 = active.
+     * @return The link status
      */
-    public int getActive() { return mActive; }
+    @LinkStatus public int getLinkStatus() { return mLinkStatus; }
 
     /**
      * @return The connection protocol type.
@@ -139,13 +175,13 @@
     public int getProtocolType() { return mProtocolType; }
 
     /**
-     * @return The network interface name.
+     * @return The network interface name (e.g. "rmnet_data1").
      */
     @NonNull
-    public String getIfname() { return mIfname; }
+    public String getInterfaceName() { return mInterfaceName; }
 
     /**
-     * @return A list of {@link LinkAddress}
+     * @return A list of addresses of this data connection.
      */
     @NonNull
     public List<LinkAddress> getAddresses() { return mAddresses; }
@@ -155,25 +191,25 @@
      * "192.0.1.11 2001:db8::1". Empty list if no dns server addresses returned.
      */
     @NonNull
-    public List<InetAddress> getDnses() { return mDnses; }
+    public List<InetAddress> getDnsAddresses() { return mDnsAddresses; }
 
     /**
      * @return A list of default gateway addresses, e.g., "192.0.1.3" or
      * "192.0.1.11 2001:db8::1". Empty list if the addresses represent point to point connections.
      */
     @NonNull
-    public List<InetAddress> getGateways() { return mGateways; }
+    public List<InetAddress> getGatewayAddresses() { return mGatewayAddresses; }
 
     /**
-     * @return A list of Proxy Call State Control Function address via PCO(Protocol Configuration
+     * @return A list of Proxy Call State Control Function address via PCO (Protocol Configuration
      * Option) for IMS client.
      */
     @NonNull
-    public List<String> getPcscfs() { return mPcscfs; }
+    public List<InetAddress> getPcscfAddresses() { return mPcscfAddresses; }
 
     /**
-     * @return MTU received from network Value <= 0 means network has either not sent a value or
-     * sent an invalid value
+     * @return MTU (maximum transmission unit) in bytes received from network. Zero or negative
+     * values means network has either not sent a value or sent an invalid value.
      */
     public int getMtu() { return mMtu; }
 
@@ -181,16 +217,16 @@
     public String toString() {
         StringBuffer sb = new StringBuffer();
         sb.append("DataCallResponse: {")
-           .append(" status=").append(mStatus)
+           .append(" cause=").append(mCause)
            .append(" retry=").append(mSuggestedRetryTime)
-           .append(" cid=").append(mCid)
-           .append(" active=").append(mActive)
+           .append(" cid=").append(mId)
+           .append(" linkStatus=").append(mLinkStatus)
            .append(" protocolType=").append(mProtocolType)
-           .append(" ifname=").append(mIfname)
+           .append(" ifname=").append(mInterfaceName)
            .append(" addresses=").append(mAddresses)
-           .append(" dnses=").append(mDnses)
-           .append(" gateways=").append(mGateways)
-           .append(" pcscf=").append(mPcscfs)
+           .append(" dnses=").append(mDnsAddresses)
+           .append(" gateways=").append(mGatewayAddresses)
+           .append(" pcscf=").append(mPcscfAddresses)
            .append(" mtu=").append(mMtu)
            .append("}");
         return sb.toString();
@@ -200,32 +236,33 @@
     public boolean equals (Object o) {
         if (this == o) return true;
 
-        if (o == null || !(o instanceof DataCallResponse)) {
+        if (!(o instanceof DataCallResponse)) {
             return false;
         }
 
         DataCallResponse other = (DataCallResponse) o;
-        return this.mStatus == other.mStatus
+        return this.mCause == other.mCause
                 && this.mSuggestedRetryTime == other.mSuggestedRetryTime
-                && this.mCid == other.mCid
-                && this.mActive == other.mActive
+                && this.mId == other.mId
+                && this.mLinkStatus == other.mLinkStatus
                 && this.mProtocolType == other.mProtocolType
-                && this.mIfname.equals(other.mIfname)
+                && this.mInterfaceName.equals(other.mInterfaceName)
                 && mAddresses.size() == other.mAddresses.size()
                 && mAddresses.containsAll(other.mAddresses)
-                && mDnses.size() == other.mDnses.size()
-                && mDnses.containsAll(other.mDnses)
-                && mGateways.size() == other.mGateways.size()
-                && mGateways.containsAll(other.mGateways)
-                && mPcscfs.size() == other.mPcscfs.size()
-                && mPcscfs.containsAll(other.mPcscfs)
+                && mDnsAddresses.size() == other.mDnsAddresses.size()
+                && mDnsAddresses.containsAll(other.mDnsAddresses)
+                && mGatewayAddresses.size() == other.mGatewayAddresses.size()
+                && mGatewayAddresses.containsAll(other.mGatewayAddresses)
+                && mPcscfAddresses.size() == other.mPcscfAddresses.size()
+                && mPcscfAddresses.containsAll(other.mPcscfAddresses)
                 && mMtu == other.mMtu;
     }
 
     @Override
     public int hashCode() {
-        return Objects.hash(mStatus, mSuggestedRetryTime, mCid, mActive, mProtocolType, mIfname,
-                mAddresses, mDnses, mGateways, mPcscfs, mMtu);
+        return Objects.hash(mCause, mSuggestedRetryTime, mId, mLinkStatus, mProtocolType,
+                mInterfaceName, mAddresses, mDnsAddresses, mGatewayAddresses, mPcscfAddresses,
+                mMtu);
     }
 
     @Override
@@ -235,16 +272,16 @@
 
     @Override
     public void writeToParcel(Parcel dest, int flags) {
-        dest.writeInt(mStatus);
+        dest.writeInt(mCause);
         dest.writeInt(mSuggestedRetryTime);
-        dest.writeInt(mCid);
-        dest.writeInt(mActive);
+        dest.writeInt(mId);
+        dest.writeInt(mLinkStatus);
         dest.writeInt(mProtocolType);
-        dest.writeString(mIfname);
+        dest.writeString(mInterfaceName);
         dest.writeList(mAddresses);
-        dest.writeList(mDnses);
-        dest.writeList(mGateways);
-        dest.writeList(mPcscfs);
+        dest.writeList(mDnsAddresses);
+        dest.writeList(mGatewayAddresses);
+        dest.writeList(mPcscfAddresses);
         dest.writeInt(mMtu);
     }
 
@@ -260,4 +297,183 @@
                     return new DataCallResponse[size];
                 }
             };
-}
\ No newline at end of file
+
+    /**
+     * Provides a convenient way to set the fields of a {@link DataCallResponse} when creating a new
+     * instance.
+     *
+     * <p>The example below shows how you might create a new {@code DataCallResponse}:
+     *
+     * <pre><code>
+     *
+     * DataCallResponse response = new DataCallResponse.Builder()
+     *     .setAddresses(Arrays.asList("192.168.1.2"))
+     *     .setProtocolType(ApnSetting.PROTOCOL_IPV4V6)
+     *     .build();
+     * </code></pre>
+     */
+    public static final class Builder {
+        private @FailCause int mCause;
+
+        private int mSuggestedRetryTime;
+
+        private int mId;
+
+        private @LinkStatus int mLinkStatus;
+
+        private @ProtocolType int mProtocolType;
+
+        private String mInterfaceName;
+
+        private List<LinkAddress> mAddresses;
+
+        private List<InetAddress> mDnsAddresses;
+
+        private List<InetAddress> mGatewayAddresses;
+
+        private List<InetAddress> mPcscfAddresses;
+
+        private int mMtu;
+
+        /**
+         * Default constructor for Builder.
+         */
+        public Builder() {
+        }
+
+        /**
+         * Set data call fail cause.
+         *
+         * @param cause Data call fail cause. {@link DataFailCause#NONE} indicates no error.
+         * @return The same instance of the builder.
+         */
+        public @NonNull Builder setCause(@FailCause int cause) {
+            mCause = cause;
+            return this;
+        }
+
+        /**
+         * Set the suggested data retry time.
+         *
+         * @param suggestedRetryTime The suggested data retry time in milliseconds.
+         * @return The same instance of the builder.
+         */
+        public @NonNull Builder setSuggestedRetryTime(int suggestedRetryTime) {
+            mSuggestedRetryTime = suggestedRetryTime;
+            return this;
+        }
+
+        /**
+         * Set the unique id of the data connection.
+         *
+         * @param id The unique id of the data connection.
+         * @return The same instance of the builder.
+         */
+        public @NonNull Builder setId(int id) {
+            mId = id;
+            return this;
+        }
+
+        /**
+         * Set the link status
+         *
+         * @param linkStatus The link status
+         * @return The same instance of the builder.
+         */
+        public @NonNull Builder setLinkStatus(@LinkStatus int linkStatus) {
+            mLinkStatus = linkStatus;
+            return this;
+        }
+
+        /**
+         * Set the connection protocol type.
+         *
+         * @param protocolType The connection protocol type.
+         * @return The same instance of the builder.
+         */
+        public @NonNull Builder setProtocolType(@ProtocolType int protocolType) {
+            mProtocolType = protocolType;
+            return this;
+        }
+
+        /**
+         * Set the network interface name.
+         *
+         * @param interfaceName The network interface name (e.g. "rmnet_data1").
+         * @return The same instance of the builder.
+         */
+        public @NonNull Builder setInterfaceName(@NonNull String interfaceName) {
+            mInterfaceName = interfaceName;
+            return this;
+        }
+
+        /**
+         * Set the addresses of this data connection.
+         *
+         * @param addresses The list of address of the data connection.
+         * @return The same instance of the builder.
+         */
+        public @NonNull Builder setAddresses(@NonNull List<LinkAddress> addresses) {
+            mAddresses = addresses;
+            return this;
+        }
+
+        /**
+         * Set the DNS addresses of this data connection
+         *
+         * @param dnsAddresses The list of DNS address of the data connection.
+         * @return The same instance of the builder.
+         */
+        public @NonNull Builder setDnsAddresses(@NonNull List<InetAddress> dnsAddresses) {
+            mDnsAddresses = dnsAddresses;
+            return this;
+        }
+
+        /**
+         * Set the gateway addresses of this data connection
+         *
+         * @param gatewayAddresses The list of gateway address of the data connection.
+         * @return The same instance of the builder.
+         */
+        public @NonNull Builder setGatewayAddresses(@NonNull List<InetAddress> gatewayAddresses) {
+            mGatewayAddresses = gatewayAddresses;
+            return this;
+        }
+
+        /**
+         * Set the Proxy Call State Control Function address via PCO(Protocol Configuration
+         * Option) for IMS client.
+         *
+         * @param pcscfAddresses The list of pcscf address of the data connection.
+         * @return The same instance of the builder.
+         */
+        public @NonNull Builder setPcscfAddresses(@NonNull List<InetAddress> pcscfAddresses) {
+            mPcscfAddresses = pcscfAddresses;
+            return this;
+        }
+
+        /**
+         * Set maximum transmission unit of the data connection.
+         *
+         * @param mtu MTU (maximum transmission unit) in bytes received from network. Zero or
+         * negative values means network has either not sent a value or sent an invalid value.
+         *
+         * @return The same instance of the builder.
+         */
+        public @NonNull Builder setMtu(int mtu) {
+            mMtu = mtu;
+            return this;
+        }
+
+        /**
+         * Build the DataCallResponse.
+         *
+         * @return the DataCallResponse object.
+         */
+        public @NonNull DataCallResponse build() {
+            return new DataCallResponse(mCause, mSuggestedRetryTime, mId, mLinkStatus,
+                    mProtocolType, mInterfaceName, mAddresses, mDnsAddresses, mGatewayAddresses,
+                    mPcscfAddresses, mMtu);
+        }
+    }
+}
diff --git a/telephony/java/android/telephony/data/DataProfile.java b/telephony/java/android/telephony/data/DataProfile.java
index bcb47f7..c53ade1 100644
--- a/telephony/java/android/telephony/data/DataProfile.java
+++ b/telephony/java/android/telephony/data/DataProfile.java
@@ -34,6 +34,7 @@
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
+import java.util.Objects;
 
 /**
  * Description of a mobile data profile used for establishing
@@ -50,7 +51,7 @@
                     TYPE_COMMON,
                     TYPE_3GPP,
                     TYPE_3GPP2})
-    public @interface DataProfileType {}
+    public @interface Type {}
 
     /** Common data profile */
     public static final int TYPE_COMMON = 0;
@@ -75,25 +76,25 @@
 
     private final String mPassword;
 
-    @DataProfileType
+    @Type
     private final int mType;
 
-    private final int mMaxConnsTime;
+    private final int mMaxConnectionsTime;
 
-    private final int mMaxConns;
+    private final int mMaxConnections;
 
     private final int mWaitTime;
 
     private final boolean mEnabled;
 
     @ApnType
-    private final int mSupportedApnTypesBitmap;
+    private final int mSupportedApnTypesBitmask;
 
     @ProtocolType
     private final int mRoamingProtocolType;
 
     @NetworkTypeBitMask
-    private final int mBearerBitmap;
+    private final int mBearerBitmask;
 
     private final int mMtu;
 
@@ -102,11 +103,13 @@
     private final boolean mPreferred;
 
     /** @hide */
-    public DataProfile(int profileId, String apn, @ProtocolType int protocolType, int authType,
-                       String userName, String password, int type, int maxConnsTime, int maxConns,
-                       int waitTime, boolean enabled, @ApnType int supportedApnTypesBitmap,
-                       @ProtocolType int roamingProtocolType, @NetworkTypeBitMask int bearerBitmap,
-                       int mtu, boolean persistent, boolean preferred) {
+    private DataProfile(int profileId, String apn, @ProtocolType int protocolType, int authType,
+                        String userName, String password, int type, int maxConnectionsTime,
+                        int maxConnections, int waitTime, boolean enabled,
+                        @ApnType int supportedApnTypesBitmask,
+                        @ProtocolType int roamingProtocolType,
+                        @NetworkTypeBitMask int bearerBitmask, int mtu, boolean persistent,
+                        boolean preferred) {
         this.mProfileId = profileId;
         this.mApn = apn;
         this.mProtocolType = protocolType;
@@ -118,21 +121,19 @@
         this.mUserName = userName;
         this.mPassword = password;
         this.mType = type;
-        this.mMaxConnsTime = maxConnsTime;
-        this.mMaxConns = maxConns;
+        this.mMaxConnectionsTime = maxConnectionsTime;
+        this.mMaxConnections = maxConnections;
         this.mWaitTime = waitTime;
         this.mEnabled = enabled;
-
-        this.mSupportedApnTypesBitmap = supportedApnTypesBitmap;
+        this.mSupportedApnTypesBitmask = supportedApnTypesBitmask;
         this.mRoamingProtocolType = roamingProtocolType;
-        this.mBearerBitmap = bearerBitmap;
+        this.mBearerBitmask = bearerBitmask;
         this.mMtu = mtu;
         this.mPersistent = persistent;
         this.mPreferred = preferred;
     }
 
-    /** @hide */
-    public DataProfile(Parcel source) {
+    private DataProfile(Parcel source) {
         mProfileId = source.readInt();
         mApn = source.readString();
         mProtocolType = source.readInt();
@@ -140,13 +141,13 @@
         mUserName = source.readString();
         mPassword = source.readString();
         mType = source.readInt();
-        mMaxConnsTime = source.readInt();
-        mMaxConns = source.readInt();
+        mMaxConnectionsTime = source.readInt();
+        mMaxConnections = source.readInt();
         mWaitTime = source.readInt();
         mEnabled = source.readBoolean();
-        mSupportedApnTypesBitmap = source.readInt();
+        mSupportedApnTypesBitmask = source.readInt();
         mRoamingProtocolType = source.readInt();
-        mBearerBitmap = source.readInt();
+        mBearerBitmask = source.readInt();
         mMtu = source.readInt();
         mPersistent = source.readBoolean();
         mPreferred = source.readBoolean();
@@ -158,7 +159,8 @@
     public int getProfileId() { return mProfileId; }
 
     /**
-     * @return The APN to establish data connection.
+     * @return The APN (Access Point Name) to establish data connection. This is a string
+     * specifically defined by the carrier.
      */
     @NonNull
     public String getApn() { return mApn; }
@@ -166,7 +168,7 @@
     /**
      * @return The connection protocol defined in 3GPP TS 27.007 section 10.1.1.
      */
-    public @ProtocolType int getProtocol() { return mProtocolType; }
+    public @ProtocolType int getProtocolType() { return mProtocolType; }
 
     /**
      * @return The authentication protocol used for this PDP context.
@@ -188,22 +190,28 @@
     /**
      * @return The profile type.
      */
-    public @DataProfileType int getType() { return mType; }
+    public @Type int getType() { return mType; }
 
     /**
      * @return The period in seconds to limit the maximum connections.
+     *
+     * @hide
      */
-    public int getMaxConnsTime() { return mMaxConnsTime; }
+    public int getMaxConnectionsTime() { return mMaxConnectionsTime; }
 
     /**
      * @return The maximum connections allowed.
+     *
+     * @hide
      */
-    public int getMaxConns() { return mMaxConns; }
+    public int getMaxConnections() { return mMaxConnections; }
 
     /**
      * @return The required wait time in seconds after a successful UE initiated disconnect of a
      * given PDN connection before the device can send a new PDN connection request for that given
      * PDN.
+     *
+     * @hide
      */
     public int getWaitTime() { return mWaitTime; }
 
@@ -213,19 +221,19 @@
     public boolean isEnabled() { return mEnabled; }
 
     /**
-     * @return The supported APN types bitmap.
+     * @return The supported APN types bitmask.
      */
-    public @ApnType int getSupportedApnTypesBitmap() { return mSupportedApnTypesBitmap; }
+    public @ApnType int getSupportedApnTypesBitmask() { return mSupportedApnTypesBitmask; }
 
     /**
      * @return The connection protocol on roaming network defined in 3GPP TS 27.007 section 10.1.1.
      */
-    public @ProtocolType int getRoamingProtocol() { return mRoamingProtocolType; }
+    public @ProtocolType int getRoamingProtocolType() { return mRoamingProtocolType; }
 
     /**
-     * @return The bearer bitmap indicating the applicable networks for this data profile.
+     * @return The bearer bitmask indicating the applicable networks for this data profile.
      */
-    public @NetworkTypeBitMask int getBearerBitmap() { return mBearerBitmap; }
+    public @NetworkTypeBitMask int getBearerBitmask() { return mBearerBitmask; }
 
     /**
      * @return The maximum transmission unit (MTU) size in bytes.
@@ -239,7 +247,8 @@
 
     /**
      * @return {@code true} if this data profile was used to bring up the last default
-     * (i.e internet) data connection successfully.
+     * (i.e internet) data connection successfully, or the one chosen by the user in Settings'
+     * APN editor. For one carrier there can be only one profiled preferred.
      */
     public boolean isPreferred() { return  mPreferred; }
 
@@ -253,19 +262,13 @@
         return "DataProfile=" + mProfileId + "/" + mProtocolType + "/" + mAuthType
                 + "/" + (Build.IS_USER ? "***/***/***" :
                          (mApn + "/" + mUserName + "/" + mPassword)) + "/" + mType + "/"
-                + mMaxConnsTime + "/" + mMaxConns + "/"
-                + mWaitTime + "/" + mEnabled + "/" + mSupportedApnTypesBitmap + "/"
-                + mRoamingProtocolType + "/" + mBearerBitmap + "/" + mMtu + "/" + mPersistent + "/"
+                + mMaxConnectionsTime + "/" + mMaxConnections + "/"
+                + mWaitTime + "/" + mEnabled + "/" + mSupportedApnTypesBitmask + "/"
+                + mRoamingProtocolType + "/" + mBearerBitmask + "/" + mMtu + "/" + mPersistent + "/"
                 + mPreferred;
     }
 
     @Override
-    public boolean equals(Object o) {
-        if (o instanceof DataProfile == false) return false;
-        return (o == this || toString().equals(o.toString()));
-    }
-
-    @Override
     public void writeToParcel(Parcel dest, int flags) {
         dest.writeInt(mProfileId);
         dest.writeString(mApn);
@@ -274,13 +277,13 @@
         dest.writeString(mUserName);
         dest.writeString(mPassword);
         dest.writeInt(mType);
-        dest.writeInt(mMaxConnsTime);
-        dest.writeInt(mMaxConns);
+        dest.writeInt(mMaxConnectionsTime);
+        dest.writeInt(mMaxConnections);
         dest.writeInt(mWaitTime);
         dest.writeBoolean(mEnabled);
-        dest.writeInt(mSupportedApnTypesBitmap);
+        dest.writeInt(mSupportedApnTypesBitmask);
         dest.writeInt(mRoamingProtocolType);
-        dest.writeInt(mBearerBitmap);
+        dest.writeInt(mBearerBitmask);
         dest.writeInt(mMtu);
         dest.writeBoolean(mPersistent);
         dest.writeBoolean(mPreferred);
@@ -298,4 +301,312 @@
             return new DataProfile[size];
         }
     };
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+        DataProfile that = (DataProfile) o;
+        return mProfileId == that.mProfileId
+                && mProtocolType == that.mProtocolType
+                && mAuthType == that.mAuthType
+                && mType == that.mType
+                && mMaxConnectionsTime == that.mMaxConnectionsTime
+                && mMaxConnections == that.mMaxConnections
+                && mWaitTime == that.mWaitTime
+                && mEnabled == that.mEnabled
+                && mSupportedApnTypesBitmask == that.mSupportedApnTypesBitmask
+                && mRoamingProtocolType == that.mRoamingProtocolType
+                && mBearerBitmask == that.mBearerBitmask
+                && mMtu == that.mMtu
+                && mPersistent == that.mPersistent
+                && mPreferred == that.mPreferred
+                && Objects.equals(mApn, that.mApn)
+                && Objects.equals(mUserName, that.mUserName)
+                && Objects.equals(mPassword, that.mPassword);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(mProfileId, mApn, mProtocolType, mAuthType, mUserName, mPassword, mType,
+                mMaxConnectionsTime, mMaxConnections, mWaitTime, mEnabled,
+                mSupportedApnTypesBitmask, mRoamingProtocolType, mBearerBitmask, mMtu, mPersistent,
+                mPreferred);
+    }
+
+    /**
+     * Provides a convenient way to set the fields of a {@link DataProfile} when creating a new
+     * instance.
+     *
+     * <p>The example below shows how you might create a new {@code DataProfile}:
+     *
+     * <pre><code>
+     *
+     * DataProfile dp = new DataProfile.Builder()
+     *     .setApn("apn.xyz.com")
+     *     .setProtocol(ApnSetting.PROTOCOL_IPV4V6)
+     *     .build();
+     * </code></pre>
+     */
+    public static final class Builder {
+        private int mProfileId;
+
+        private String mApn;
+
+        @ProtocolType
+        private int mProtocolType;
+
+        @AuthType
+        private int mAuthType;
+
+        private String mUserName;
+
+        private String mPassword;
+
+        @Type
+        private int mType;
+
+        private int mMaxConnectionsTime;
+
+        private int mMaxConnections;
+
+        private int mWaitTime;
+
+        private boolean mEnabled;
+
+        @ApnType
+        private int mSupportedApnTypesBitmask;
+
+        @ProtocolType
+        private int mRoamingProtocolType;
+
+        @NetworkTypeBitMask
+        private int mBearerBitmask;
+
+        private int mMtu;
+
+        private boolean mPersistent;
+
+        private boolean mPreferred;
+
+        /**
+         * Default constructor for Builder.
+         */
+        public Builder() {
+        }
+
+        /**
+         * Set profile id. Note that this is not a global unique id of the data profile. This id
+         * is only used by certain CDMA carriers to identify the type of data profile.
+         *
+         * @param profileId Network domain.
+         * @return The same instance of the builder.
+         */
+        public @NonNull Builder setProfileId(int profileId) {
+            mProfileId = profileId;
+            return this;
+        }
+
+        /**
+         * Set the APN (Access Point Name) to establish data connection. This is a string
+         * specifically defined by the carrier.
+         *
+         * @param apn Access point name
+         * @return The same instance of the builder.
+         */
+        public @NonNull Builder setApn(@NonNull String apn) {
+            mApn = apn;
+            return this;
+        }
+
+        /**
+         * Set the connection protocol type.
+         *
+         * @param protocolType The connection protocol defined in 3GPP TS 27.007 section 10.1.1.
+         * @return The same instance of the builder.
+         */
+        public @NonNull Builder setProtocolType(@ProtocolType int protocolType) {
+            mProtocolType = protocolType;
+            return this;
+        }
+
+        /**
+         * Set the authentication type.
+         *
+         * @param authType The authentication type
+         * @return The same instance of the builder.
+         */
+        public @NonNull Builder setAuthType(@AuthType int authType) {
+            mAuthType = authType;
+            return this;
+        }
+
+        /**
+         * Set the user name
+         *
+         * @param userName The user name
+         * @return The same instance of the builder.
+         */
+        public @NonNull Builder setUserName(@NonNull String userName) {
+            mUserName = userName;
+            return this;
+        }
+
+        /**
+         * Set the password
+         *
+         * @param password The password
+         * @return The same instance of the builder.
+         */
+        public @NonNull Builder setPassword(@NonNull String password) {
+            mPassword = password;
+            return this;
+        }
+
+        /**
+         * Set the type
+         *
+         * @param type The profile type
+         * @return The same instance of the builder.
+         */
+        public @NonNull Builder setType(@Type int type) {
+            mType = type;
+            return this;
+        }
+
+        /**
+         * Set the period in seconds to limit the maximum connections.
+         *
+         * @param maxConnectionsTime The profile type
+         * @return The same instance of the builder.
+         *
+         * @hide
+         */
+        public @NonNull Builder setMaxConnectionsTime(int maxConnectionsTime) {
+            mMaxConnectionsTime = maxConnectionsTime;
+            return this;
+        }
+
+        /**
+         * Set the maximum connections allowed.
+         *
+         * @param maxConnections The maximum connections allowed.
+         * @return The same instance of the builder.
+         *
+         * @hide
+         */
+        public @NonNull Builder setMaxConnections(int maxConnections) {
+            mMaxConnections = maxConnections;
+            return this;
+        }
+
+        /**
+         * Set the period in seconds to limit the maximum connections.
+         *
+         * @param waitTime The required wait time in seconds after a successful UE initiated
+         * disconnect of a given PDN connection before the device can send a new PDN connection
+         * request for that given PDN.
+         *
+         * @return The same instance of the builder.
+         *
+         * @hide
+         */
+        public @NonNull Builder setWaitTime(int waitTime) {
+            mWaitTime = waitTime;
+            return this;
+        }
+
+        /**
+         * Enable the data profile
+         *
+         * @param isEnabled {@code true} to enable the data profile, otherwise disable.
+         * @return The same instance of the builder.
+         */
+        public @NonNull Builder enable(boolean isEnabled) {
+            mEnabled = isEnabled;
+            return this;
+        }
+
+        /**
+         * Set the supported APN types bitmask.
+         *
+         * @param supportedApnTypesBitmask The supported APN types bitmask.
+         * @return The same instance of the builder.
+         */
+        public @NonNull Builder setSupportedApnTypesBitmask(@ApnType int supportedApnTypesBitmask) {
+            mSupportedApnTypesBitmask = supportedApnTypesBitmask;
+            return this;
+        }
+
+        /**
+         * Set the connection protocol type for roaming.
+         *
+         * @param protocolType The connection protocol defined in 3GPP TS 27.007 section 10.1.1.
+         * @return The same instance of the builder.
+         */
+        public @NonNull Builder setRoamingProtocolType(@ProtocolType int protocolType) {
+            mRoamingProtocolType = protocolType;
+            return this;
+        }
+
+        /**
+         * Set the bearer bitmask indicating the applicable networks for this data profile.
+         *
+         * @param bearerBitmask The bearer bitmask indicating the applicable networks for this data
+         * profile.
+         * @return The same instance of the builder.
+         */
+        public @NonNull Builder setBearerBitmask(@NetworkTypeBitMask int bearerBitmask) {
+            mBearerBitmask = bearerBitmask;
+            return this;
+        }
+
+        /**
+         * Set the maximum transmission unit (MTU) size in bytes.
+         *
+         * @param mtu The maximum transmission unit (MTU) size in bytes.
+         * @return The same instance of the builder.
+         */
+        public @NonNull Builder setMtu(int mtu) {
+            mMtu = mtu;
+            return this;
+        }
+
+        /**
+         * Set data profile as preferred/non-preferred.
+         *
+         * @param isPreferred {@code true} if this data profile was used to bring up the last
+         * default (i.e internet) data connection successfully, or the one chosen by the user in
+         * Settings' APN editor. For one carrier there can be only one profiled preferred.
+         * @return The same instance of the builder.
+         */
+        public @NonNull Builder setPreferred(boolean isPreferred) {
+            mPreferred = isPreferred;
+            return this;
+        }
+
+        /**
+         * Set data profile as persistent/non-persistent
+         *
+         * @param isPersistent {@code true} if this data profile was used to bring up the last
+         * default (i.e internet) data connection successfully.
+         * @return The same instance of the builder.
+         */
+        public @NonNull Builder setPersistent(boolean isPersistent) {
+            mPersistent = isPersistent;
+            return this;
+        }
+
+        /**
+         * Build the DataProfile object
+         *
+         * @return The data profile object
+         */
+        public @NonNull DataProfile build() {
+            return new DataProfile(mProfileId, mApn, mProtocolType, mAuthType, mUserName, mPassword,
+                    mType, mMaxConnectionsTime, mMaxConnections, mWaitTime, mEnabled,
+                    mSupportedApnTypesBitmask, mRoamingProtocolType, mBearerBitmask, mMtu,
+                    mPersistent, mPreferred);
+        }
+    }
 }
diff --git a/telephony/java/android/telephony/data/DataService.java b/telephony/java/android/telephony/data/DataService.java
index 59d1e1e..372bdf1 100644
--- a/telephony/java/android/telephony/data/DataService.java
+++ b/telephony/java/android/telephony/data/DataService.java
@@ -19,6 +19,7 @@
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.SdkConstant;
 import android.annotation.SystemApi;
 import android.app.Service;
 import android.content.Intent;
@@ -58,10 +59,12 @@
 public abstract class DataService extends Service {
     private static final String TAG = DataService.class.getSimpleName();
 
-    public static final String DATA_SERVICE_INTERFACE = "android.telephony.data.DataService";
+    @SdkConstant(SdkConstant.SdkConstantType.SERVICE_ACTION)
+    public static final String SERVICE_INTERFACE = "android.telephony.data.DataService";
 
     /** {@hide} */
     @IntDef(prefix = "REQUEST_REASON_", value = {
+            REQUEST_REASON_UNKNOWN,
             REQUEST_REASON_NORMAL,
             REQUEST_REASON_HANDOVER,
     })
@@ -70,6 +73,7 @@
 
     /** {@hide} */
     @IntDef(prefix = "REQUEST_REASON_", value = {
+            REQUEST_REASON_UNKNOWN,
             REQUEST_REASON_NORMAL,
             REQUEST_REASON_SHUTDOWN,
             REQUEST_REASON_HANDOVER,
@@ -77,6 +81,8 @@
     @Retention(RetentionPolicy.SOURCE)
     public @interface DeactivateDataReason {}
 
+    /** The reason of the data request is unknown */
+    public static final int REQUEST_REASON_UNKNOWN = 0;
 
     /** The reason of the data request is normal */
     public static final int REQUEST_REASON_NORMAL = 1;
@@ -94,7 +100,7 @@
     private static final int DATA_SERVICE_REQUEST_DEACTIVATE_DATA_CALL                 = 5;
     private static final int DATA_SERVICE_REQUEST_SET_INITIAL_ATTACH_APN               = 6;
     private static final int DATA_SERVICE_REQUEST_SET_DATA_PROFILE                     = 7;
-    private static final int DATA_SERVICE_REQUEST_GET_DATA_CALL_LIST                   = 8;
+    private static final int DATA_SERVICE_REQUEST_REQUEST_DATA_CALL_LIST               = 8;
     private static final int DATA_SERVICE_REQUEST_REGISTER_DATA_CALL_LIST_CHANGED      = 9;
     private static final int DATA_SERVICE_REQUEST_UNREGISTER_DATA_CALL_LIST_CHANGED    = 10;
     private static final int DATA_SERVICE_INDICATION_DATA_CALL_LIST_CHANGED            = 11;
@@ -149,14 +155,13 @@
          *        {@link #REQUEST_REASON_HANDOVER}.
          * @param linkProperties If {@code reason} is {@link #REQUEST_REASON_HANDOVER}, this is the
          *        link properties of the existing data connection, otherwise null.
-         * @param callback The result callback for this request. Null if the client does not care
-         *        about the result.
+         * @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,
-                                  @Nullable DataServiceCallback callback) {
+                                  @NonNull DataServiceCallback callback) {
             // The default implementation is to return unsupported.
             if (callback != null) {
                 callback.onSetupDataCallComplete(DataServiceCallback.RESULT_ERROR_UNSUPPORTED,
@@ -190,11 +195,10 @@
          *
          * @param dataProfile Data profile used for data call setup. See {@link DataProfile}.
          * @param isRoaming True if the device is data roaming.
-         * @param callback The result callback for this request. Null if the client does not care
-         *        about the result.
+         * @param callback The result callback for this request.
          */
         public void setInitialAttachApn(@NonNull DataProfile dataProfile, boolean isRoaming,
-                                        @Nullable DataServiceCallback callback) {
+                                        @NonNull DataServiceCallback callback) {
             // The default implementation is to return unsupported.
             if (callback != null) {
                 callback.onSetInitialAttachApnComplete(
@@ -209,11 +213,10 @@
          *
          * @param dps A list of data profiles.
          * @param isRoaming True if the device is data roaming.
-         * @param callback The result callback for this request. Null if the client does not care
-         *        about the result.
+         * @param callback The result callback for this request.
          */
         public void setDataProfile(@NonNull List<DataProfile> dps, boolean isRoaming,
-                                   @Nullable DataServiceCallback callback) {
+                                   @NonNull DataServiceCallback callback) {
             // The default implementation is to return unsupported.
             if (callback != null) {
                 callback.onSetDataProfileComplete(DataServiceCallback.RESULT_ERROR_UNSUPPORTED);
@@ -225,9 +228,10 @@
          *
          * @param callback The result callback for this request.
          */
-        public void getDataCallList(@NonNull DataServiceCallback callback) {
+        public void requestDataCallList(@NonNull DataServiceCallback callback) {
             // The default implementation is to return unsupported.
-            callback.onGetDataCallListComplete(DataServiceCallback.RESULT_ERROR_UNSUPPORTED, null);
+            callback.onRequestDataCallListComplete(DataServiceCallback.RESULT_ERROR_UNSUPPORTED,
+                    null);
         }
 
         private void registerForDataCallListChanged(IDataServiceCallback callback) {
@@ -409,10 +413,10 @@
                                     ? new DataServiceCallback(setDataProfileRequest.callback)
                                     : null);
                     break;
-                case DATA_SERVICE_REQUEST_GET_DATA_CALL_LIST:
+                case DATA_SERVICE_REQUEST_REQUEST_DATA_CALL_LIST:
                     if (serviceProvider == null) break;
 
-                    serviceProvider.getDataCallList(new DataServiceCallback(
+                    serviceProvider.requestDataCallList(new DataServiceCallback(
                             (IDataServiceCallback) message.obj));
                     break;
                 case DATA_SERVICE_REQUEST_REGISTER_DATA_CALL_LIST_CHANGED:
@@ -455,14 +459,14 @@
      * will call this method after binding the data service for each active SIM slot id.
      *
      * @param slotIndex SIM slot id the data service associated with.
-     * @return Data service object
+     * @return Data service object. Null if failed to create the provider (e.g. invalid slot index)
      */
     @Nullable
     public abstract DataServiceProvider onCreateDataServiceProvider(int slotIndex);
 
     @Override
     public IBinder onBind(Intent intent) {
-        if (intent == null || !DATA_SERVICE_INTERFACE.equals(intent.getAction())) {
+        if (intent == null || !SERVICE_INTERFACE.equals(intent.getAction())) {
             loge("Unexpected intent " + intent);
             return null;
         }
@@ -531,12 +535,12 @@
         }
 
         @Override
-        public void getDataCallList(int slotIndex, IDataServiceCallback callback) {
+        public void requestDataCallList(int slotIndex, IDataServiceCallback callback) {
             if (callback == null) {
-                loge("getDataCallList: callback is null");
+                loge("requestDataCallList: callback is null");
                 return;
             }
-            mHandler.obtainMessage(DATA_SERVICE_REQUEST_GET_DATA_CALL_LIST, slotIndex, 0,
+            mHandler.obtainMessage(DATA_SERVICE_REQUEST_REQUEST_DATA_CALL_LIST, slotIndex, 0,
                     callback).sendToTarget();
         }
 
diff --git a/telephony/java/android/telephony/data/DataServiceCallback.java b/telephony/java/android/telephony/data/DataServiceCallback.java
index 2d0cfe8..5d8d793 100644
--- a/telephony/java/android/telephony/data/DataServiceCallback.java
+++ b/telephony/java/android/telephony/data/DataServiceCallback.java
@@ -140,21 +140,21 @@
     }
 
     /**
-     * Called to indicate result for the request {@link DataServiceProvider#getDataCallList(
+     * Called to indicate result for the request {@link DataServiceProvider#requestDataCallList(
      * DataServiceCallback)}.
      *
      * @param result The result code. Must be one of the {@link ResultCode}.
      * @param dataCallList List of the current active data connection. If no data call is presented,
      * set it to an empty list.
      */
-    public void onGetDataCallListComplete(@ResultCode int result,
-                                          @NonNull List<DataCallResponse> dataCallList) {
+    public void onRequestDataCallListComplete(@ResultCode int result,
+                                              @NonNull List<DataCallResponse> dataCallList) {
         IDataServiceCallback callback = mCallback.get();
         if (callback != null) {
             try {
-                callback.onGetDataCallListComplete(result, dataCallList);
+                callback.onRequestDataCallListComplete(result, dataCallList);
             } catch (RemoteException e) {
-                Rlog.e(TAG, "Failed to onGetDataCallListComplete on the remote");
+                Rlog.e(TAG, "Failed to onRequestDataCallListComplete on the remote");
             }
         }
     }
diff --git a/telephony/java/android/telephony/data/IDataService.aidl b/telephony/java/android/telephony/data/IDataService.aidl
index d4d9be8..9c74dcc 100644
--- a/telephony/java/android/telephony/data/IDataService.aidl
+++ b/telephony/java/android/telephony/data/IDataService.aidl
@@ -35,7 +35,7 @@
                              IDataServiceCallback callback);
     void setDataProfile(int slotId, in List<DataProfile> dps, boolean isRoaming,
                         IDataServiceCallback callback);
-    void getDataCallList(int slotId, IDataServiceCallback callback);
+    void requestDataCallList(int slotId, IDataServiceCallback callback);
     void registerForDataCallListChanged(int slotId, IDataServiceCallback callback);
     void unregisterForDataCallListChanged(int slotId, IDataServiceCallback callback);
 }
diff --git a/telephony/java/android/telephony/data/IDataServiceCallback.aidl b/telephony/java/android/telephony/data/IDataServiceCallback.aidl
index 856185b..cec757d 100644
--- a/telephony/java/android/telephony/data/IDataServiceCallback.aidl
+++ b/telephony/java/android/telephony/data/IDataServiceCallback.aidl
@@ -28,6 +28,6 @@
     void onDeactivateDataCallComplete(int result);
     void onSetInitialAttachApnComplete(int result);
     void onSetDataProfileComplete(int result);
-    void onGetDataCallListComplete(int result, in List<DataCallResponse> dataCallList);
+    void onRequestDataCallListComplete(int result, in List<DataCallResponse> dataCallList);
     void onDataCallListChanged(in List<DataCallResponse> dataCallList);
 }
diff --git a/telephony/java/android/telephony/data/IQualifiedNetworksService.aidl b/telephony/java/android/telephony/data/IQualifiedNetworksService.aidl
index 9c80cb7..3bf09bc 100644
--- a/telephony/java/android/telephony/data/IQualifiedNetworksService.aidl
+++ b/telephony/java/android/telephony/data/IQualifiedNetworksService.aidl
@@ -23,6 +23,6 @@
  */
 interface IQualifiedNetworksService
 {
-    oneway void createNetworkAvailabilityUpdater(int slotId, IQualifiedNetworksServiceCallback callback);
-    oneway void removeNetworkAvailabilityUpdater(int slotId);
+    oneway void createNetworkAvailabilityProvider(int slotId, IQualifiedNetworksServiceCallback callback);
+    oneway void removeNetworkAvailabilityProvider(int slotId);
 }
diff --git a/telephony/java/android/telephony/data/QualifiedNetworksService.java b/telephony/java/android/telephony/data/QualifiedNetworksService.java
index c38f278..0e1751d 100644
--- a/telephony/java/android/telephony/data/QualifiedNetworksService.java
+++ b/telephony/java/android/telephony/data/QualifiedNetworksService.java
@@ -17,7 +17,6 @@
 package android.telephony.data;
 
 import android.annotation.NonNull;
-import android.annotation.Nullable;
 import android.annotation.SystemApi;
 import android.app.Service;
 import android.content.Intent;
@@ -34,14 +33,21 @@
 
 import com.android.internal.annotations.VisibleForTesting;
 
+import java.util.List;
+
 /**
- * Base class of the qualified networks service. Services that extend QualifiedNetworksService must
- * register the service in their AndroidManifest to be detected by the framework. They must be
- * protected by the permission "android.permission.BIND_TELEPHONY_QUALIFIED_NETWORKS_SERVICE".
- * The qualified networks service definition in the manifest must follow the following format:
+ * Base class of the qualified networks service, which is a vendor service providing up-to-date
+ * qualified network information to the frameworks for data handover control. A qualified network
+ * is defined as an access network that is ready for bringing up data connection for given APN
+ * types.
+ *
+ * Services that extend QualifiedNetworksService must register the service in their AndroidManifest
+ * to be detected by the framework. They must be protected by the permission
+ * "android.permission.BIND_TELEPHONY_DATA_SERVICE". The qualified networks service definition in
+ * the manifest must follow the following format:
  * ...
  * <service android:name=".xxxQualifiedNetworksService"
- *     android:permission="android.permission.BIND_TELEPHONY_QUALIFIED_NETWORKS_SERVICE" >
+ *     android:permission="android.permission.BIND_TELEPHONY_DATA_SERVICE" >
  *     <intent-filter>
  *         <action android:name="android.telephony.data.QualifiedNetworksService" />
  *     </intent-filter>
@@ -55,28 +61,28 @@
     public static final String QUALIFIED_NETWORKS_SERVICE_INTERFACE =
             "android.telephony.data.QualifiedNetworksService";
 
-    private static final int QNS_CREATE_NETWORK_AVAILABILITY_UPDATER                = 1;
-    private static final int QNS_REMOVE_NETWORK_AVAILABILITY_UPDATER                = 2;
-    private static final int QNS_REMOVE_ALL_NETWORK_AVAILABILITY_UPDATERS           = 3;
+    private static final int QNS_CREATE_NETWORK_AVAILABILITY_PROVIDER               = 1;
+    private static final int QNS_REMOVE_NETWORK_AVAILABILITY_PROVIDER               = 2;
+    private static final int QNS_REMOVE_ALL_NETWORK_AVAILABILITY_PROVIDERS          = 3;
     private static final int QNS_UPDATE_QUALIFIED_NETWORKS                          = 4;
 
     private final HandlerThread mHandlerThread;
 
     private final QualifiedNetworksServiceHandler mHandler;
 
-    private final SparseArray<NetworkAvailabilityUpdater> mUpdaters = new SparseArray<>();
+    private final SparseArray<NetworkAvailabilityProvider> mProviders = new SparseArray<>();
 
     /** @hide */
     @VisibleForTesting
     public final IQualifiedNetworksServiceWrapper mBinder = new IQualifiedNetworksServiceWrapper();
 
     /**
-     * The abstract class of the network availability updater implementation. The vendor qualified
+     * The abstract class of the network availability provider implementation. The vendor qualified
      * network service must extend this class to report the available networks for data
-     * connection setup. Note that each instance of network availability updater is associated with
+     * connection setup. Note that each instance of network availability provider is associated with
      * one physical SIM slot.
      */
-    public abstract class NetworkAvailabilityUpdater implements AutoCloseable {
+    public abstract class NetworkAvailabilityProvider implements AutoCloseable {
         private final int mSlotIndex;
 
         private IQualifiedNetworksServiceCallback mCallback;
@@ -89,14 +95,14 @@
 
         /**
          * Constructor
-         * @param slotIndex SIM slot index the network availability updater associated with.
+         * @param slotIndex SIM slot index the network availability provider associated with.
          */
-        public NetworkAvailabilityUpdater(int slotIndex) {
+        public NetworkAvailabilityProvider(int slotIndex) {
             mSlotIndex = slotIndex;
         }
 
         /**
-         * @return SIM slot index the network availability updater associated with.
+         * @return SIM slot index the network availability provider associated with.
          */
         public final int getSlotIndex() {
             return mSlotIndex;
@@ -121,7 +127,7 @@
         }
 
         /**
-         * Update the qualified networks list. Network availability updater must invoke this method
+         * Update the qualified networks list. Network availability provider must invoke this method
          * whenever the qualified networks changes. If this method is never invoked for certain
          * APN types, then frameworks will always use the default (i.e. cellular) data and network
          * service.
@@ -129,14 +135,16 @@
          * @param apnTypes APN types of the qualified networks. This must be a bitmask combination
          * of {@link ApnSetting.ApnType}.
          * @param qualifiedNetworkTypes List of network types which are qualified for data
-         * connection setup for {@link @apnType} in the preferred order. Each element in the array
-         * is a {@link AccessNetworkType}. An empty list or null indicates no networks are qualified
+         * connection setup for {@link @apnType} in the preferred order. Each element in the list
+         * is a {@link AccessNetworkType}. An empty list indicates no networks are qualified
          * for data setup.
          */
-        public final void updateQualifiedNetworkTypes(@ApnType int apnTypes,
-                                                      @Nullable int[] qualifiedNetworkTypes) {
+        public final void updateQualifiedNetworkTypes(
+                @ApnType int apnTypes, @NonNull List<Integer> qualifiedNetworkTypes) {
+            int[] qualifiedNetworkTypesArray =
+                    qualifiedNetworkTypes.stream().mapToInt(i->i).toArray();
             mHandler.obtainMessage(QNS_UPDATE_QUALIFIED_NETWORKS, mSlotIndex, apnTypes,
-                    qualifiedNetworkTypes).sendToTarget();
+                    qualifiedNetworkTypesArray).sendToTarget();
         }
 
         private void onUpdateQualifiedNetworkTypes(@ApnType int apnTypes,
@@ -152,7 +160,7 @@
         }
 
         /**
-         * Called when the qualified networks updater is removed. The extended class should
+         * Called when the qualified networks provider is removed. The extended class should
          * implement this method to perform cleanup works.
          */
         @Override
@@ -168,48 +176,48 @@
         public void handleMessage(Message message) {
             IQualifiedNetworksServiceCallback callback;
             final int slotIndex = message.arg1;
-            NetworkAvailabilityUpdater updater = mUpdaters.get(slotIndex);
+            NetworkAvailabilityProvider provider = mProviders.get(slotIndex);
 
             switch (message.what) {
-                case QNS_CREATE_NETWORK_AVAILABILITY_UPDATER:
-                    if (mUpdaters.get(slotIndex) != null) {
-                        loge("Network availability updater for slot " + slotIndex
+                case QNS_CREATE_NETWORK_AVAILABILITY_PROVIDER:
+                    if (mProviders.get(slotIndex) != null) {
+                        loge("Network availability provider for slot " + slotIndex
                                 + " already existed.");
                         return;
                     }
 
-                    updater = createNetworkAvailabilityUpdater(slotIndex);
-                    if (updater != null) {
-                        mUpdaters.put(slotIndex, updater);
+                    provider = onCreateNetworkAvailabilityProvider(slotIndex);
+                    if (provider != null) {
+                        mProviders.put(slotIndex, provider);
 
                         callback = (IQualifiedNetworksServiceCallback) message.obj;
-                        updater.registerForQualifiedNetworkTypesChanged(callback);
+                        provider.registerForQualifiedNetworkTypesChanged(callback);
                     } else {
-                        loge("Failed to create network availability updater. slot index = "
+                        loge("Failed to create network availability provider. slot index = "
                                 + slotIndex);
                     }
                     break;
 
-                case QNS_REMOVE_NETWORK_AVAILABILITY_UPDATER:
-                    if (updater != null) {
-                        updater.close();
-                        mUpdaters.remove(slotIndex);
+                case QNS_REMOVE_NETWORK_AVAILABILITY_PROVIDER:
+                    if (provider != null) {
+                        provider.close();
+                        mProviders.remove(slotIndex);
                     }
                     break;
 
-                case QNS_REMOVE_ALL_NETWORK_AVAILABILITY_UPDATERS:
-                    for (int i = 0; i < mUpdaters.size(); i++) {
-                        updater = mUpdaters.get(i);
-                        if (updater != null) {
-                            updater.close();
+                case QNS_REMOVE_ALL_NETWORK_AVAILABILITY_PROVIDERS:
+                    for (int i = 0; i < mProviders.size(); i++) {
+                        provider = mProviders.get(i);
+                        if (provider != null) {
+                            provider.close();
                         }
                     }
-                    mUpdaters.clear();
+                    mProviders.clear();
                     break;
 
                 case QNS_UPDATE_QUALIFIED_NETWORKS:
-                    if (updater == null) break;
-                    updater.onUpdateQualifiedNetworkTypes(message.arg2, (int[]) message.obj);
+                    if (provider == null) break;
+                    provider.onUpdateQualifiedNetworkTypes(message.arg2, (int[]) message.obj);
                     break;
             }
         }
@@ -227,8 +235,8 @@
     }
 
     /**
-     * Create the instance of {@link NetworkAvailabilityUpdater}. Vendor qualified network service
-     * must override this method to facilitate the creation of {@link NetworkAvailabilityUpdater}
+     * Create the instance of {@link NetworkAvailabilityProvider}. Vendor qualified network service
+     * must override this method to facilitate the creation of {@link NetworkAvailabilityProvider}
      * instances. The system will call this method after binding the qualified networks service for
      * each active SIM slot index.
      *
@@ -236,7 +244,7 @@
      * @return Qualified networks service instance
      */
     @NonNull
-    public abstract NetworkAvailabilityUpdater createNetworkAvailabilityUpdater(int slotIndex);
+    public abstract NetworkAvailabilityProvider onCreateNetworkAvailabilityProvider(int slotIndex);
 
     /** @hide */
     @Override
@@ -251,7 +259,7 @@
     /** @hide */
     @Override
     public boolean onUnbind(Intent intent) {
-        mHandler.obtainMessage(QNS_REMOVE_ALL_NETWORK_AVAILABILITY_UPDATERS).sendToTarget();
+        mHandler.obtainMessage(QNS_REMOVE_ALL_NETWORK_AVAILABILITY_PROVIDERS).sendToTarget();
         return false;
     }
 
@@ -267,15 +275,15 @@
      */
     private class IQualifiedNetworksServiceWrapper extends IQualifiedNetworksService.Stub {
         @Override
-        public void createNetworkAvailabilityUpdater(int slotIndex,
-                                                     IQualifiedNetworksServiceCallback callback) {
-            mHandler.obtainMessage(QNS_CREATE_NETWORK_AVAILABILITY_UPDATER, slotIndex, 0,
+        public void createNetworkAvailabilityProvider(int slotIndex,
+                                                      IQualifiedNetworksServiceCallback callback) {
+            mHandler.obtainMessage(QNS_CREATE_NETWORK_AVAILABILITY_PROVIDER, slotIndex, 0,
                     callback).sendToTarget();
         }
 
         @Override
-        public void removeNetworkAvailabilityUpdater(int slotIndex) {
-            mHandler.obtainMessage(QNS_REMOVE_NETWORK_AVAILABILITY_UPDATER, slotIndex, 0)
+        public void removeNetworkAvailabilityProvider(int slotIndex) {
+            mHandler.obtainMessage(QNS_REMOVE_NETWORK_AVAILABILITY_PROVIDER, slotIndex, 0)
                     .sendToTarget();
         }
     }
diff --git a/telephony/java/android/telephony/euicc/EuiccManager.java b/telephony/java/android/telephony/euicc/EuiccManager.java
index e651783..cde10ea 100644
--- a/telephony/java/android/telephony/euicc/EuiccManager.java
+++ b/telephony/java/android/telephony/euicc/EuiccManager.java
@@ -118,9 +118,9 @@
     /**
      * Intent action sent by system apps (such as the Settings app) to the Telephony framework to
      * enable or disable a subscription. Must be accompanied with {@link #EXTRA_SUBSCRIPTION_ID} and
-     * {@link #EXTRA_ENABLE_SUBSCRIPTION}.
+     * {@link #EXTRA_ENABLE_SUBSCRIPTION}, and optionally {@link #EXTRA_FROM_SUBSCRIPTION_ID}.
      *
-     * Requires the caller to be a privileged process with the
+     * <p>Requires the caller to be a privileged process with the
      * {@link android.permission#CALL_PRIVILEGED} permission for the intent to reach the Telephony
      * stack.
      *
@@ -143,7 +143,7 @@
      * Intent action sent by system apps (such as the Settings app) to the Telephony framework to
      * delete a subscription. Must be accompanied with {@link #EXTRA_SUBSCRIPTION_ID}.
      *
-     * Requires the caller to be a privileged process with the
+     * <p>Requires the caller to be a privileged process with the
      * {@link android.permission#CALL_PRIVILEGED} permission for the intent to reach the Telephony
      * stack.
      *
@@ -167,7 +167,7 @@
      * rename a subscription. Must be accompanied with {@link #EXTRA_SUBSCRIPTION_ID} and
      * {@link #EXTRA_SUBSCRIPTION_NICKNAME}.
      *
-     * Requires the caller to be a privileged process with the
+     * <p>Requires the caller to be a privileged process with the
      * {@link android.permission#CALL_PRIVILEGED} permission for the intent to reach the Telephony
      * stack.
      *
@@ -285,6 +285,8 @@
      * {@link #ACTION_DELETE_SUBSCRIPTION_PRIVILEGED}, and
      * {@link #ACTION_RENAME_SUBSCRIPTION_PRIVILEGED} providing the ID of the targeted subscription.
      *
+     * <p>Expected type of the extra data: int
+     *
      * @hide
      */
     @SystemApi
@@ -295,6 +297,8 @@
      * Key for an extra set on {@link #ACTION_TOGGLE_SUBSCRIPTION_PRIVILEGED} providing a boolean
      * value of whether to enable or disable the targeted subscription.
      *
+     * <p>Expected type of the extra data: boolean
+     *
      * @hide
      */
     @SystemApi
@@ -305,6 +309,8 @@
      * Key for an extra set on {@link #ACTION_RENAME_SUBSCRIPTION_PRIVILEGED} providing a new
      * nickname for the targeted subscription.
      *
+     * <p>Expected type of the extra data: String
+     *
      * @hide
      */
     @SystemApi
@@ -312,6 +318,22 @@
             "android.telephony.euicc.extra.SUBSCRIPTION_NICKNAME";
 
     /**
+     * Key for an extra set on {@link #ACTION_TOGGLE_SUBSCRIPTION_PRIVILEGED} providing the ID of
+     * the subscription we're toggling from. This extra is optional and is only used for UI
+     * purposes by the underlying eUICC service (i.e. the LPA app), such as displaying a dialog
+     * titled "Switch X with Y". If set, the provided subscription will be used as the "from"
+     * subscription in UI (the "X" in the dialog example). Otherwise, the currently active
+     * subscription that will be disabled is the "from" subscription.
+     *
+     * <p>Expected type of the extra data: int
+     *
+     * @hide
+     */
+    @SystemApi
+    public static final String EXTRA_FROM_SUBSCRIPTION_ID =
+            "android.telephony.euicc.extra.FROM_SUBSCRIPTION_ID";
+
+    /**
      * Optional meta-data attribute for a carrier app providing an icon to use to represent the
      * carrier. If not provided, the app's launcher icon will be used as a fallback.
      */
diff --git a/telephony/java/android/telephony/ims/ImsException.java b/telephony/java/android/telephony/ims/ImsException.java
index 02eddf6..8c686f7 100644
--- a/telephony/java/android/telephony/ims/ImsException.java
+++ b/telephony/java/android/telephony/ims/ImsException.java
@@ -31,7 +31,7 @@
  * @hide
  */
 @SystemApi
-public class ImsException extends Exception {
+public final class ImsException extends Exception {
 
     /**
      * The operation has failed due to an unknown or unspecified error.
diff --git a/telephony/java/android/telephony/ims/feature/ImsFeature.java b/telephony/java/android/telephony/ims/feature/ImsFeature.java
index b55866b..d2b4133 100644
--- a/telephony/java/android/telephony/ims/feature/ImsFeature.java
+++ b/telephony/java/android/telephony/ims/feature/ImsFeature.java
@@ -210,6 +210,7 @@
     /**
      * Contains the capabilities defined and supported by an ImsFeature in the form of a bit mask.
      * @hide
+     * @deprecated
      */
     @SystemApi  // SystemApi only because it was leaked through type usage in a previous release.
     public static class Capabilities {
diff --git a/telephony/java/com/android/internal/telephony/ISub.aidl b/telephony/java/com/android/internal/telephony/ISub.aidl
index 79e0aa1..3bbf7a4 100755
--- a/telephony/java/com/android/internal/telephony/ISub.aidl
+++ b/telephony/java/com/android/internal/telephony/ISub.aidl
@@ -205,15 +205,6 @@
     String setSubscriptionGroup(in int[] subIdList, String callingPackage);
 
     /**
-     * Set whether a subscription is metered
-     *
-     * @param isMetered whether it’s a metered subscription.
-     * @param subId the unique SubscriptionInfo index in database
-     * @return the number of records updated
-     */
-    int setMetered(boolean isMetered, int subId, String callingPackage);
-
-    /**
      * Set which subscription is preferred for cellular data. It's
      * designed to overwrite default data subscription temporarily.
      *
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index 62b92fd..10cc99e 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -1683,7 +1683,7 @@
      * (also any country or carrier overlays) to be loaded when using a test SIM with a call box.
      */
     void setCarrierTestOverride(int subId, String mccmnc, String imsi, String iccid, String gid1,
-            String gid2, String plmn, String spn);
+            String gid2, String plmn, String spn, String carrierPrivilegeRules, String apn);
 
     /**
      * A test API to return installed carrier id list version.
@@ -1919,15 +1919,18 @@
      * Indicate if the enablement of multi SIM functionality is restricted.
      * @hide
      */
-    void setMultisimCarrierRestriction(boolean isMultisimCarrierRestricted);
+    void setMultiSimCarrierRestriction(boolean isMultiSimCarrierRestricted);
 
     /**
      * Returns if the usage of multiple SIM cards at the same time is supported.
      *
      * @param callingPackage The package making the call.
-     * @return true if multisim is supported, false otherwise.
+     * @return {@link #MULTISIM_ALLOWED} if the device supports multiple SIMs.
+     * {@link #MULTISIM_NOT_SUPPORTED_BY_HARDWARE} if the device does not support multiple SIMs.
+     * {@link #MULTISIM_NOT_SUPPORTED_BY_CARRIER} in the device supports multiple SIMs, but the
+     * functionality is restricted by the carrier.
      */
-    boolean isMultisimSupported(String callingPackage);
+    int isMultiSimSupported(String callingPackage);
 
     /**
      * Switch configs to enable multi-sim or switch back to single-sim
diff --git a/telephony/java/com/android/internal/telephony/TelephonyPermissions.java b/telephony/java/com/android/internal/telephony/TelephonyPermissions.java
index 9d78bf4..4886a3f 100644
--- a/telephony/java/com/android/internal/telephony/TelephonyPermissions.java
+++ b/telephony/java/com/android/internal/telephony/TelephonyPermissions.java
@@ -317,7 +317,8 @@
                 Settings.Global.PRIVILEGED_DEVICE_IDENTIFIER_PRIV_CHECK_RELAXED, 0) == 1;
         ApplicationInfo callingPackageInfo = null;
         try {
-            callingPackageInfo = context.getPackageManager().getApplicationInfo(callingPackage, 0);
+            callingPackageInfo = context.getPackageManager().getApplicationInfoAsUser(
+                    callingPackage, 0, UserHandle.getUserId(uid));
             if (callingPackageInfo.isSystemApp()) {
                 isPreinstalled = true;
                 if (callingPackageInfo.isPrivilegedApp()) {
diff --git a/tests/FlickerTests/AndroidTest.xml b/tests/FlickerTests/AndroidTest.xml
index b31235b..41cb74a 100644
--- a/tests/FlickerTests/AndroidTest.xml
+++ b/tests/FlickerTests/AndroidTest.xml
@@ -4,7 +4,7 @@
  -->
 <configuration description="Runs WindowManager Flicker Tests">
     <option name="test-tag" value="FlickerTests" />
-    <target_preparer class="com.google.android.tradefed.targetprep.GoogleDeviceSetup">
+    <target_preparer class="com.android.tradefed.targetprep.DeviceSetup">
         <!-- keeps the screen on during tests -->
         <option name="screen-always-on" value="on" />
         <!-- prevents the phone from restarting -->
diff --git a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackBroadcastReceiver.java b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackBroadcastReceiver.java
index 8a925b9..ebe5418 100644
--- a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackBroadcastReceiver.java
+++ b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackBroadcastReceiver.java
@@ -63,6 +63,13 @@
     }
 
     /**
+     * Waits forever for the next rollback broadcast.
+     */
+    Intent take() throws InterruptedException {
+        return mRollbackBroadcasts.take();
+    }
+
+    /**
      * Unregisters this broadcast receiver.
      */
     void unregister() {
diff --git a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackTest.java b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackTest.java
index 7505230..834743d 100644
--- a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackTest.java
+++ b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackTest.java
@@ -27,7 +27,6 @@
 import static org.junit.Assert.fail;
 
 import android.Manifest;
-import android.app.ActivityManager;
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
@@ -40,14 +39,11 @@
 
 import androidx.test.InstrumentationRegistry;
 
-import org.junit.Ignore;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.JUnit4;
 
 import java.util.Collections;
-import java.util.concurrent.BlockingQueue;
-import java.util.concurrent.SynchronousQueue;
 import java.util.concurrent.TimeUnit;
 
 /**
@@ -87,6 +83,7 @@
             RollbackTestUtils.adoptShellPermissionIdentity(
                     Manifest.permission.INSTALL_PACKAGES,
                     Manifest.permission.DELETE_PACKAGES,
+                    Manifest.permission.TEST_MANAGE_ROLLBACKS,
                     Manifest.permission.MANAGE_ROLLBACKS);
 
             // Register a broadcast receiver for notification when the
@@ -175,7 +172,7 @@
             RollbackTestUtils.adoptShellPermissionIdentity(
                     Manifest.permission.INSTALL_PACKAGES,
                     Manifest.permission.DELETE_PACKAGES,
-                    Manifest.permission.MANAGE_ROLLBACKS);
+                    Manifest.permission.TEST_MANAGE_ROLLBACKS);
 
             RollbackManager rm = RollbackTestUtils.getRollbackManager();
 
@@ -233,7 +230,7 @@
             RollbackTestUtils.adoptShellPermissionIdentity(
                     Manifest.permission.INSTALL_PACKAGES,
                     Manifest.permission.DELETE_PACKAGES,
-                    Manifest.permission.MANAGE_ROLLBACKS);
+                    Manifest.permission.TEST_MANAGE_ROLLBACKS);
 
             RollbackManager rm = RollbackTestUtils.getRollbackManager();
 
@@ -290,7 +287,7 @@
             RollbackTestUtils.adoptShellPermissionIdentity(
                     Manifest.permission.INSTALL_PACKAGES,
                     Manifest.permission.DELETE_PACKAGES,
-                    Manifest.permission.MANAGE_ROLLBACKS);
+                    Manifest.permission.TEST_MANAGE_ROLLBACKS);
 
             RollbackManager rm = RollbackTestUtils.getRollbackManager();
 
@@ -343,11 +340,11 @@
             RollbackTestUtils.adoptShellPermissionIdentity(
                     Manifest.permission.INSTALL_PACKAGES,
                     Manifest.permission.DELETE_PACKAGES,
-                    Manifest.permission.MANAGE_ROLLBACKS,
+                    Manifest.permission.TEST_MANAGE_ROLLBACKS,
                     Manifest.permission.WRITE_DEVICE_CONFIG);
 
-            DeviceConfig.setProperty(DeviceConfig.Rollback.BOOT_NAMESPACE,
-                    DeviceConfig.Rollback.ROLLBACK_LIFETIME_IN_MILLIS,
+            DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ROLLBACK_BOOT,
+                    RollbackManager.PROPERTY_ROLLBACK_LIFETIME_MILLIS,
                     Long.toString(expirationTime), false /* makeDefault*/);
 
             // Pull the new expiration time from DeviceConfig
@@ -382,8 +379,8 @@
             assertNull(getUniqueRollbackInfoForPackage(rm.getAvailableRollbacks(), TEST_APP_A));
 
         } finally {
-            DeviceConfig.setProperty(DeviceConfig.Rollback.BOOT_NAMESPACE,
-                    DeviceConfig.Rollback.ROLLBACK_LIFETIME_IN_MILLIS,
+            DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ROLLBACK_BOOT,
+                    RollbackManager.PROPERTY_ROLLBACK_LIFETIME_MILLIS,
                     Long.toString(defaultExpirationTime), false /* makeDefault*/);
             RollbackTestUtils.dropShellPermissionIdentity();
         }
@@ -403,12 +400,12 @@
             RollbackTestUtils.adoptShellPermissionIdentity(
                     Manifest.permission.INSTALL_PACKAGES,
                     Manifest.permission.DELETE_PACKAGES,
-                    Manifest.permission.MANAGE_ROLLBACKS,
+                    Manifest.permission.TEST_MANAGE_ROLLBACKS,
                     Manifest.permission.WRITE_DEVICE_CONFIG,
                     Manifest.permission.SET_TIME);
 
-            DeviceConfig.setProperty(DeviceConfig.Rollback.BOOT_NAMESPACE,
-                    DeviceConfig.Rollback.ROLLBACK_LIFETIME_IN_MILLIS,
+            DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ROLLBACK_BOOT,
+                    RollbackManager.PROPERTY_ROLLBACK_LIFETIME_MILLIS,
                     Long.toString(expirationTime), false /* makeDefault*/);
 
             // Pull the new expiration time from DeviceConfig
@@ -458,8 +455,8 @@
                 RollbackTestUtils.forwardTimeBy(-expirationTime);
             }
         } finally {
-            DeviceConfig.setProperty(DeviceConfig.Rollback.BOOT_NAMESPACE,
-                    DeviceConfig.Rollback.ROLLBACK_LIFETIME_IN_MILLIS,
+            DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ROLLBACK_BOOT,
+                    RollbackManager.PROPERTY_ROLLBACK_LIFETIME_MILLIS,
                     Long.toString(defaultExpirationTime), false /* makeDefault*/);
             RollbackTestUtils.dropShellPermissionIdentity();
         }
@@ -475,7 +472,7 @@
             RollbackTestUtils.adoptShellPermissionIdentity(
                     Manifest.permission.INSTALL_PACKAGES,
                     Manifest.permission.DELETE_PACKAGES,
-                    Manifest.permission.MANAGE_ROLLBACKS);
+                    Manifest.permission.TEST_MANAGE_ROLLBACKS);
 
             RollbackManager rm = RollbackTestUtils.getRollbackManager();
             RollbackTestUtils.uninstall(TEST_APP_A);
@@ -512,7 +509,7 @@
             RollbackTestUtils.adoptShellPermissionIdentity(
                     Manifest.permission.INSTALL_PACKAGES,
                     Manifest.permission.DELETE_PACKAGES,
-                    Manifest.permission.MANAGE_ROLLBACKS);
+                    Manifest.permission.TEST_MANAGE_ROLLBACKS);
 
             RollbackTestUtils.uninstall(TEST_APP_A);
             RollbackTestUtils.install("RollbackTestAppAv1.apk", false);
@@ -533,14 +530,13 @@
     /**
      * Test rollback of apks involving splits.
      */
-    @Ignore("b/127520966 build issues with splits need to be sorted out")
     @Test
     public void testRollbackWithSplits() throws Exception {
         try {
             RollbackTestUtils.adoptShellPermissionIdentity(
                     Manifest.permission.INSTALL_PACKAGES,
                     Manifest.permission.DELETE_PACKAGES,
-                    Manifest.permission.MANAGE_ROLLBACKS);
+                    Manifest.permission.TEST_MANAGE_ROLLBACKS);
 
             RollbackTestUtils.uninstall(TEST_APP_A);
             RollbackTestUtils.installSplit(false,
@@ -598,7 +594,7 @@
             RollbackTestUtils.adoptShellPermissionIdentity(
                     Manifest.permission.INSTALL_PACKAGES,
                     Manifest.permission.DELETE_PACKAGES,
-                    Manifest.permission.MANAGE_ROLLBACKS);
+                    Manifest.permission.TEST_MANAGE_ROLLBACKS);
             RollbackManager rm = RollbackTestUtils.getRollbackManager();
 
             // Prep installation of the test apps.
@@ -693,6 +689,75 @@
     }
 
     /**
+     * Test that you cannot enable rollback for a package without the
+     * MANAGE_ROLLBACKS permission.
+     */
+    @Test
+    public void testEnableRollbackPermission() throws Exception {
+        try {
+            RollbackTestUtils.adoptShellPermissionIdentity(
+                    Manifest.permission.INSTALL_PACKAGES,
+                    Manifest.permission.DELETE_PACKAGES);
+
+            RollbackTestUtils.uninstall(TEST_APP_A);
+            RollbackTestUtils.install("RollbackTestAppAv1.apk", /* enableRollback */ false);
+            assertEquals(1, RollbackTestUtils.getInstalledVersion(TEST_APP_A));
+
+            RollbackTestUtils.install("RollbackTestAppAv2.apk", /* enableRollback */ true);
+
+            // We expect v2 of the app was installed, but rollback has not
+            // been enabled.
+            assertEquals(2, RollbackTestUtils.getInstalledVersion(TEST_APP_A));
+
+            // TODO: See if there is a way to remove this race condition
+            // between when the app is installed and when the rollback
+            // would be made available.
+            Thread.sleep(1000);
+
+            RollbackTestUtils.adoptShellPermissionIdentity(
+                    Manifest.permission.TEST_MANAGE_ROLLBACKS);
+            RollbackManager rm = RollbackTestUtils.getRollbackManager();
+            assertNull(getUniqueRollbackInfoForPackage(rm.getAvailableRollbacks(), TEST_APP_A));
+        } finally {
+            RollbackTestUtils.dropShellPermissionIdentity();
+        }
+    }
+
+    /**
+     * Test that you cannot enable rollback for a non-module package when
+     * holding the MANAGE_ROLLBACKS permission.
+     */
+    @Test
+    public void testNonModuleEnableRollback() throws Exception {
+        try {
+            RollbackTestUtils.adoptShellPermissionIdentity(
+                    Manifest.permission.INSTALL_PACKAGES,
+                    Manifest.permission.DELETE_PACKAGES,
+                    Manifest.permission.MANAGE_ROLLBACKS);
+
+            RollbackTestUtils.uninstall(TEST_APP_A);
+            RollbackTestUtils.install("RollbackTestAppAv1.apk", /* enableRollback */ false);
+            assertEquals(1, RollbackTestUtils.getInstalledVersion(TEST_APP_A));
+
+            RollbackTestUtils.install("RollbackTestAppAv2.apk", /* enableRollback */ true);
+
+            // We expect v2 of the app was installed, but rollback has not
+            // been enabled because the test app is not a module.
+            assertEquals(2, RollbackTestUtils.getInstalledVersion(TEST_APP_A));
+
+            // TODO: See if there is a way to remove this race condition
+            // between when the app is installed and when the rollback
+            // would be made available.
+            Thread.sleep(1000);
+
+            RollbackManager rm = RollbackTestUtils.getRollbackManager();
+            assertNull(getUniqueRollbackInfoForPackage(rm.getAvailableRollbacks(), TEST_APP_A));
+        } finally {
+            RollbackTestUtils.dropShellPermissionIdentity();
+        }
+    }
+
+    /**
      * Test rollback of multi-package installs is implemented.
      */
     @Test
@@ -701,7 +766,7 @@
             RollbackTestUtils.adoptShellPermissionIdentity(
                     Manifest.permission.INSTALL_PACKAGES,
                     Manifest.permission.DELETE_PACKAGES,
-                    Manifest.permission.MANAGE_ROLLBACKS);
+                    Manifest.permission.TEST_MANAGE_ROLLBACKS);
             RollbackManager rm = RollbackTestUtils.getRollbackManager();
 
             // Prep installation of the test apps.
@@ -761,6 +826,7 @@
                     Manifest.permission.INSTALL_PACKAGES,
                     Manifest.permission.DELETE_PACKAGES,
                     Manifest.permission.MANAGE_ROLLBACKS,
+                    Manifest.permission.TEST_MANAGE_ROLLBACKS,
                     Manifest.permission.KILL_BACKGROUND_PROCESSES,
                     Manifest.permission.RESTART_PACKAGES);
             RollbackManager rm = RollbackTestUtils.getRollbackManager();
@@ -790,34 +856,14 @@
                     rm.getAvailableRollbacks(), TEST_APP_B);
             assertRollbackInfoEquals(TEST_APP_B, 2, 1, rollbackB);
 
-            BlockingQueue<Integer> crashQueue = new SynchronousQueue<>();
+            // Register rollback committed receiver
+            RollbackBroadcastReceiver rollbackReceiver = new RollbackBroadcastReceiver();
 
-            IntentFilter crashCountFilter = new IntentFilter();
-            crashCountFilter.addAction("com.android.tests.rollback.CRASH");
-            crashCountFilter.addCategory(Intent.CATEGORY_DEFAULT);
+            // Crash TEST_APP_A PackageWatchdog#TRIGGER_FAILURE_COUNT times to trigger rollback
+            crashCountReceiver = RollbackTestUtils.sendCrashBroadcast(context, TEST_APP_A, 5);
 
-            crashCountReceiver = new BroadcastReceiver() {
-                    @Override
-                    public void onReceive(Context context, Intent intent) {
-                        try {
-                            // Sleep long enough for packagewatchdog to be notified of crash
-                            Thread.sleep(1000);
-                            // Kill app and close AppErrorDialog
-                            ActivityManager am = context.getSystemService(ActivityManager.class);
-                            am.killBackgroundProcesses(TEST_APP_A);
-                            // Allow another package launch
-                            crashQueue.put(intent.getIntExtra("count", 0));
-                        } catch (InterruptedException e) {
-                            fail("Failed to communicate with test app");
-                        }
-                    }
-                };
-            context.registerReceiver(crashCountReceiver, crashCountFilter);
-
-            // Start apps PackageWatchdog#TRIGGER_FAILURE_COUNT times so TEST_APP_A crashes
-            do {
-                RollbackTestUtils.launchPackage(TEST_APP_A);
-            } while(crashQueue.take() < 5);
+            // Verify we received a broadcast for the rollback.
+            rollbackReceiver.take();
 
             // TEST_APP_A is automatically rolled back by the RollbackPackageHealthObserver
             assertEquals(1, RollbackTestUtils.getInstalledVersion(TEST_APP_A));
diff --git a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackTestUtils.java b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackTestUtils.java
index 9aed074..81629aa 100644
--- a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackTestUtils.java
+++ b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackTestUtils.java
@@ -21,6 +21,7 @@
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.fail;
 
+import android.app.ActivityManager;
 import android.app.AlarmManager;
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
@@ -47,6 +48,7 @@
 import java.util.List;
 import java.util.concurrent.BlockingQueue;
 import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.SynchronousQueue;
 
 /**
  * Utilities to facilitate testing rollbacks.
@@ -187,7 +189,7 @@
     }
 
     /** Launches {@code packageName} with {@link Intent#ACTION_MAIN}. */
-    static void launchPackage(String packageName)
+    private static void launchPackage(String packageName)
             throws InterruptedException, IOException {
         Context context = InstrumentationRegistry.getContext();
         Intent intent = new Intent(Intent.ACTION_MAIN);
@@ -488,4 +490,39 @@
         }
         return null;
     }
+
+    /**
+     * Send broadcast to crash {@code packageName} {@code count} times. If {@code count} is at least
+     * {@link PackageWatchdog#TRIGGER_FAILURE_COUNT}, watchdog crash detection will be triggered.
+     */
+    static BroadcastReceiver sendCrashBroadcast(Context context, String packageName, int count)
+            throws InterruptedException, IOException {
+        BlockingQueue<Integer> crashQueue = new SynchronousQueue<>();
+        IntentFilter crashCountFilter = new IntentFilter();
+        crashCountFilter.addAction("com.android.tests.rollback.CRASH");
+        crashCountFilter.addCategory(Intent.CATEGORY_DEFAULT);
+
+        BroadcastReceiver crashCountReceiver = new BroadcastReceiver() {
+                @Override
+                public void onReceive(Context context, Intent intent) {
+                    try {
+                        // Sleep long enough for packagewatchdog to be notified of crash
+                        Thread.sleep(1000);
+                        // Kill app and close AppErrorDialog
+                        ActivityManager am = context.getSystemService(ActivityManager.class);
+                        am.killBackgroundProcesses(packageName);
+                        // Allow another package launch
+                        crashQueue.put(intent.getIntExtra("count", 0));
+                    } catch (InterruptedException e) {
+                        fail("Failed to communicate with test app");
+                    }
+                }
+            };
+        context.registerReceiver(crashCountReceiver, crashCountFilter);
+
+        do {
+            launchPackage(packageName);
+        } while(crashQueue.take() < count);
+        return crashCountReceiver;
+    }
 }
diff --git a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/StagedRollbackTest.java b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/StagedRollbackTest.java
index 047451b..7e711c2 100644
--- a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/StagedRollbackTest.java
+++ b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/StagedRollbackTest.java
@@ -63,7 +63,7 @@
         RollbackTestUtils.adoptShellPermissionIdentity(
                 Manifest.permission.INSTALL_PACKAGES,
                 Manifest.permission.DELETE_PACKAGES,
-                Manifest.permission.MANAGE_ROLLBACKS);
+                Manifest.permission.TEST_MANAGE_ROLLBACKS);
     }
 
     /**
diff --git a/tests/net/Android.bp b/tests/net/Android.bp
index 2539c0f..c62d85e 100644
--- a/tests/net/Android.bp
+++ b/tests/net/Android.bp
@@ -13,7 +13,6 @@
         "mockito-target-minus-junit4",
         "platform-test-annotations",
         "services.core",
-        "services.ipmemorystore",
         "services.net",
     ],
     libs: [
diff --git a/tests/net/java/android/net/DnsPacketTest.java b/tests/net/java/android/net/DnsPacketTest.java
index 9ede2b8..975abf4 100644
--- a/tests/net/java/android/net/DnsPacketTest.java
+++ b/tests/net/java/android/net/DnsPacketTest.java
@@ -69,7 +69,7 @@
         try {
             new TestDnsPacket(null);
             fail("Exception not thrown for null byte array");
-        } catch (DnsPacket.ParseException e) {
+        } catch (ParseException e) {
         }
     }
 
diff --git a/tests/net/java/android/net/IpMemoryStoreTest.java b/tests/net/java/android/net/IpMemoryStoreTest.java
index 57ecc8f..18c6768 100644
--- a/tests/net/java/android/net/IpMemoryStoreTest.java
+++ b/tests/net/java/android/net/IpMemoryStoreTest.java
@@ -16,6 +16,9 @@
 
 package android.net;
 
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.doAnswer;
+
 import android.content.Context;
 
 import androidx.test.filters.SmallTest;
@@ -33,13 +36,25 @@
     @Mock
     Context mMockContext;
     @Mock
+    NetworkStackClient mNetworkStackClient;
+    @Mock
     IIpMemoryStore mMockService;
     IpMemoryStore mStore;
 
     @Before
     public void setUp() {
         MockitoAnnotations.initMocks(this);
-        mStore = new IpMemoryStore(mMockContext, mMockService);
+        doAnswer(invocation -> {
+            ((IIpMemoryStoreCallbacks) invocation.getArgument(0))
+                    .onIpMemoryStoreFetched(mMockService);
+            return null;
+        }).when(mNetworkStackClient).fetchIpMemoryStore(any());
+        mStore = new IpMemoryStore(mMockContext) {
+            @Override
+            protected NetworkStackClient getNetworkStackClient() {
+                return mNetworkStackClient;
+            }
+        };
     }
 
     @Test
diff --git a/tests/net/java/android/net/LinkAddressTest.java b/tests/net/java/android/net/LinkAddressTest.java
index be7bd1b..d462441b 100644
--- a/tests/net/java/android/net/LinkAddressTest.java
+++ b/tests/net/java/android/net/LinkAddressTest.java
@@ -81,14 +81,14 @@
         assertEquals(25, address.getPrefixLength());
         assertEquals(0, address.getFlags());
         assertEquals(RT_SCOPE_UNIVERSE, address.getScope());
-        assertTrue(address.isIPv4());
+        assertTrue(address.isIpv4());
 
         address = new LinkAddress(V6_ADDRESS, 127);
         assertEquals(V6_ADDRESS, address.getAddress());
         assertEquals(127, address.getPrefixLength());
         assertEquals(0, address.getFlags());
         assertEquals(RT_SCOPE_UNIVERSE, address.getScope());
-        assertTrue(address.isIPv6());
+        assertTrue(address.isIpv6());
 
         // Nonsensical flags/scopes or combinations thereof are acceptable.
         address = new LinkAddress(V6 + "/64", IFA_F_DEPRECATED | IFA_F_PERMANENT, RT_SCOPE_LINK);
@@ -96,14 +96,14 @@
         assertEquals(64, address.getPrefixLength());
         assertEquals(IFA_F_DEPRECATED | IFA_F_PERMANENT, address.getFlags());
         assertEquals(RT_SCOPE_LINK, address.getScope());
-        assertTrue(address.isIPv6());
+        assertTrue(address.isIpv6());
 
         address = new LinkAddress(V4 + "/23", 123, 456);
         assertEquals(V4_ADDRESS, address.getAddress());
         assertEquals(23, address.getPrefixLength());
         assertEquals(123, address.getFlags());
         assertEquals(456, address.getScope());
-        assertTrue(address.isIPv4());
+        assertTrue(address.isIpv4());
 
         // InterfaceAddress doesn't have a constructor. Fetch some from an interface.
         List<InterfaceAddress> addrs = NetworkInterface.getByName("lo").getInterfaceAddresses();
diff --git a/tests/net/java/android/net/LinkPropertiesTest.java b/tests/net/java/android/net/LinkPropertiesTest.java
index 9a7d487..4177291 100644
--- a/tests/net/java/android/net/LinkPropertiesTest.java
+++ b/tests/net/java/android/net/LinkPropertiesTest.java
@@ -405,8 +405,8 @@
         LinkProperties lp = new LinkProperties();
 
         // No addresses.
-        assertFalse(lp.hasIPv4Address());
-        assertFalse(lp.hasGlobalIPv6Address());
+        assertFalse(lp.hasIpv4Address());
+        assertFalse(lp.hasGlobalIpv6Address());
 
         // Addresses on stacked links don't count.
         LinkProperties stacked = new LinkProperties();
@@ -414,53 +414,53 @@
         lp.addStackedLink(stacked);
         stacked.addLinkAddress(LINKADDRV4);
         stacked.addLinkAddress(LINKADDRV6);
-        assertTrue(stacked.hasIPv4Address());
-        assertTrue(stacked.hasGlobalIPv6Address());
-        assertFalse(lp.hasIPv4Address());
-        assertFalse(lp.hasGlobalIPv6Address());
+        assertTrue(stacked.hasIpv4Address());
+        assertTrue(stacked.hasGlobalIpv6Address());
+        assertFalse(lp.hasIpv4Address());
+        assertFalse(lp.hasGlobalIpv6Address());
         lp.removeStackedLink("stacked");
-        assertFalse(lp.hasIPv4Address());
-        assertFalse(lp.hasGlobalIPv6Address());
+        assertFalse(lp.hasIpv4Address());
+        assertFalse(lp.hasGlobalIpv6Address());
 
         // Addresses on the base link.
-        // Check the return values of hasIPvXAddress and ensure the add/remove methods return true
+        // Check the return values of hasIpvXAddress and ensure the add/remove methods return true
         // iff something changes.
         assertEquals(0, lp.getLinkAddresses().size());
         assertTrue(lp.addLinkAddress(LINKADDRV6));
         assertEquals(1, lp.getLinkAddresses().size());
-        assertFalse(lp.hasIPv4Address());
-        assertTrue(lp.hasGlobalIPv6Address());
+        assertFalse(lp.hasIpv4Address());
+        assertTrue(lp.hasGlobalIpv6Address());
 
         assertTrue(lp.removeLinkAddress(LINKADDRV6));
         assertEquals(0, lp.getLinkAddresses().size());
 
         assertTrue(lp.addLinkAddress(LINKADDRV6LINKLOCAL));
         assertEquals(1, lp.getLinkAddresses().size());
-        assertFalse(lp.hasGlobalIPv6Address());
+        assertFalse(lp.hasGlobalIpv6Address());
 
         assertTrue(lp.addLinkAddress(LINKADDRV4));
         assertEquals(2, lp.getLinkAddresses().size());
-        assertTrue(lp.hasIPv4Address());
-        assertFalse(lp.hasGlobalIPv6Address());
+        assertTrue(lp.hasIpv4Address());
+        assertFalse(lp.hasGlobalIpv6Address());
 
         assertTrue(lp.addLinkAddress(LINKADDRV6));
         assertEquals(3, lp.getLinkAddresses().size());
-        assertTrue(lp.hasIPv4Address());
-        assertTrue(lp.hasGlobalIPv6Address());
+        assertTrue(lp.hasIpv4Address());
+        assertTrue(lp.hasGlobalIpv6Address());
 
         assertTrue(lp.removeLinkAddress(LINKADDRV6LINKLOCAL));
         assertEquals(2, lp.getLinkAddresses().size());
-        assertTrue(lp.hasIPv4Address());
-        assertTrue(lp.hasGlobalIPv6Address());
+        assertTrue(lp.hasIpv4Address());
+        assertTrue(lp.hasGlobalIpv6Address());
 
         // Adding an address twice has no effect.
         // Removing an address that's not present has no effect.
         assertFalse(lp.addLinkAddress(LINKADDRV4));
         assertEquals(2, lp.getLinkAddresses().size());
-        assertTrue(lp.hasIPv4Address());
+        assertTrue(lp.hasIpv4Address());
         assertTrue(lp.removeLinkAddress(LINKADDRV4));
         assertEquals(1, lp.getLinkAddresses().size());
-        assertFalse(lp.hasIPv4Address());
+        assertFalse(lp.hasIpv4Address());
         assertFalse(lp.removeLinkAddress(LINKADDRV4));
         assertEquals(1, lp.getLinkAddresses().size());
 
@@ -546,8 +546,8 @@
         assertFalse("v4only:addr+dns", lp4.isProvisioned());
         lp4.addRoute(new RouteInfo(GATEWAY1));
         assertTrue("v4only:addr+dns+route", lp4.isProvisioned());
-        assertTrue("v4only:addr+dns+route", lp4.isIPv4Provisioned());
-        assertFalse("v4only:addr+dns+route", lp4.isIPv6Provisioned());
+        assertTrue("v4only:addr+dns+route", lp4.isIpv4Provisioned());
+        assertFalse("v4only:addr+dns+route", lp4.isIpv6Provisioned());
 
         LinkProperties lp6 = new LinkProperties();
         assertFalse("v6only:empty", lp6.isProvisioned());
@@ -558,11 +558,11 @@
         lp6.addRoute(new RouteInfo(GATEWAY61));
         assertFalse("v6only:fe80+dns+route", lp6.isProvisioned());
         lp6.addLinkAddress(LINKADDRV6);
-        assertTrue("v6only:fe80+global+dns+route", lp6.isIPv6Provisioned());
+        assertTrue("v6only:fe80+global+dns+route", lp6.isIpv6Provisioned());
         assertTrue("v6only:fe80+global+dns+route", lp6.isProvisioned());
         lp6.removeLinkAddress(LINKADDRV6LINKLOCAL);
-        assertFalse("v6only:global+dns+route", lp6.isIPv4Provisioned());
-        assertTrue("v6only:global+dns+route", lp6.isIPv6Provisioned());
+        assertFalse("v6only:global+dns+route", lp6.isIpv4Provisioned());
+        assertTrue("v6only:global+dns+route", lp6.isIpv6Provisioned());
         assertTrue("v6only:global+dns+route", lp6.isProvisioned());
 
         LinkProperties lp46 = new LinkProperties();
@@ -572,12 +572,12 @@
         lp46.addDnsServer(DNS6);
         assertFalse("dualstack:missing-routes", lp46.isProvisioned());
         lp46.addRoute(new RouteInfo(GATEWAY1));
-        assertTrue("dualstack:v4-provisioned", lp46.isIPv4Provisioned());
-        assertFalse("dualstack:v4-provisioned", lp46.isIPv6Provisioned());
+        assertTrue("dualstack:v4-provisioned", lp46.isIpv4Provisioned());
+        assertFalse("dualstack:v4-provisioned", lp46.isIpv6Provisioned());
         assertTrue("dualstack:v4-provisioned", lp46.isProvisioned());
         lp46.addRoute(new RouteInfo(GATEWAY61));
-        assertTrue("dualstack:both-provisioned", lp46.isIPv4Provisioned());
-        assertTrue("dualstack:both-provisioned", lp46.isIPv6Provisioned());
+        assertTrue("dualstack:both-provisioned", lp46.isIpv4Provisioned());
+        assertTrue("dualstack:both-provisioned", lp46.isIpv6Provisioned());
         assertTrue("dualstack:both-provisioned", lp46.isProvisioned());
 
         // A link with an IPv6 address and default route, but IPv4 DNS server.
@@ -585,8 +585,8 @@
         mixed.addLinkAddress(LINKADDRV6);
         mixed.addDnsServer(DNS1);
         mixed.addRoute(new RouteInfo(GATEWAY61));
-        assertFalse("mixed:addr6+route6+dns4", mixed.isIPv4Provisioned());
-        assertFalse("mixed:addr6+route6+dns4", mixed.isIPv6Provisioned());
+        assertFalse("mixed:addr6+route6+dns4", mixed.isIpv4Provisioned());
+        assertFalse("mixed:addr6+route6+dns4", mixed.isIpv6Provisioned());
         assertFalse("mixed:addr6+route6+dns4", mixed.isProvisioned());
     }
 
@@ -617,16 +617,16 @@
         v6lp.addLinkAddress(LINKADDRV6);
         v6lp.addRoute(new RouteInfo(GATEWAY61));
         v6lp.addDnsServer(DNS6);
-        assertFalse(v6lp.isIPv4Provisioned());
-        assertTrue(v6lp.isIPv6Provisioned());
+        assertFalse(v6lp.isIpv4Provisioned());
+        assertTrue(v6lp.isIpv6Provisioned());
         assertTrue(v6lp.isProvisioned());
 
         LinkProperties v46lp = new LinkProperties(v6lp);
         v46lp.addLinkAddress(LINKADDRV4);
         v46lp.addRoute(new RouteInfo(GATEWAY1));
         v46lp.addDnsServer(DNS1);
-        assertTrue(v46lp.isIPv4Provisioned());
-        assertTrue(v46lp.isIPv6Provisioned());
+        assertTrue(v46lp.isIpv4Provisioned());
+        assertTrue(v46lp.isIpv6Provisioned());
         assertTrue(v46lp.isProvisioned());
 
         assertEquals(ProvisioningChange.STILL_PROVISIONED,
diff --git a/tests/net/java/android/net/TcpKeepalivePacketDataTest.java b/tests/net/java/android/net/TcpKeepalivePacketDataTest.java
index 1f2dd27..372ffcd 100644
--- a/tests/net/java/android/net/TcpKeepalivePacketDataTest.java
+++ b/tests/net/java/android/net/TcpKeepalivePacketDataTest.java
@@ -21,12 +21,9 @@
 import static org.junit.Assert.fail;
 
 import android.net.SocketKeepalive.InvalidPacketException;
-import android.net.TcpKeepalivePacketData.TcpSocketInfo;
 
 import com.android.internal.util.TestUtils;
 
-import libcore.net.InetAddressUtils;
-
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -37,14 +34,14 @@
 
 @RunWith(JUnit4.class)
 public final class TcpKeepalivePacketDataTest {
+    private static final byte[] IPV4_KEEPALIVE_SRC_ADDR = {10, 0, 0, 1};
+    private static final byte[] IPV4_KEEPALIVE_DST_ADDR = {10, 0, 0, 5};
 
     @Before
     public void setUp() {}
 
     @Test
-    public void testV4TcpKeepalivePacket() {
-        final InetAddress srcAddr = InetAddressUtils.parseNumericAddress("192.168.0.1");
-        final InetAddress dstAddr = InetAddressUtils.parseNumericAddress("192.168.0.10");
+    public void testV4TcpKeepalivePacket() throws Exception {
         final int srcPort = 1234;
         final int dstPort = 4321;
         final int seq = 0x11111111;
@@ -52,20 +49,28 @@
         final int wnd = 8000;
         final int wndScale = 2;
         TcpKeepalivePacketData resultData = null;
-        TcpSocketInfo testInfo = new TcpSocketInfo(
-                srcAddr, srcPort, dstAddr, dstPort, seq, ack, wnd, wndScale);
+        final TcpKeepalivePacketDataParcelable testInfo = new TcpKeepalivePacketDataParcelable();
+        testInfo.srcAddress = IPV4_KEEPALIVE_SRC_ADDR;
+        testInfo.srcPort = srcPort;
+        testInfo.dstAddress = IPV4_KEEPALIVE_DST_ADDR;
+        testInfo.dstPort = dstPort;
+        testInfo.seq = seq;
+        testInfo.ack = ack;
+        testInfo.rcvWnd = wnd;
+        testInfo.rcvWndScale = wndScale;
         try {
             resultData = TcpKeepalivePacketData.tcpKeepalivePacket(testInfo);
         } catch (InvalidPacketException e) {
             fail("InvalidPacketException: " + e);
         }
 
-        assertEquals(testInfo.srcAddress, resultData.srcAddress);
-        assertEquals(testInfo.dstAddress, resultData.dstAddress);
+        assertEquals(InetAddress.getByAddress(testInfo.srcAddress), resultData.srcAddress);
+        assertEquals(InetAddress.getByAddress(testInfo.dstAddress), resultData.dstAddress);
         assertEquals(testInfo.srcPort, resultData.srcPort);
         assertEquals(testInfo.dstPort, resultData.dstPort);
         assertEquals(testInfo.seq, resultData.tcpSeq);
         assertEquals(testInfo.ack, resultData.tcpAck);
+        assertEquals(testInfo.rcvWnd, resultData.tcpWnd);
         assertEquals(testInfo.rcvWndScale, resultData.tcpWndScale);
 
         TestUtils.assertParcelingIsLossless(resultData, TcpKeepalivePacketData.CREATOR);
@@ -78,11 +83,11 @@
         byte[] ip = new byte[4];
         buf = ByteBuffer.wrap(packet, 12, 4);
         buf.get(ip);
-        assertArrayEquals(ip, srcAddr.getAddress());
+        assertArrayEquals(ip, IPV4_KEEPALIVE_SRC_ADDR);
         // Destination IP address.
         buf = ByteBuffer.wrap(packet, 16, 4);
         buf.get(ip);
-        assertArrayEquals(ip, dstAddr.getAddress());
+        assertArrayEquals(ip, IPV4_KEEPALIVE_DST_ADDR);
 
         buf = ByteBuffer.wrap(packet, 20, 12);
         // Source port.
@@ -102,25 +107,32 @@
 
     @Test
     public void testParcel() throws Exception {
-        final InetAddress srcAddr = InetAddresses.parseNumericAddress("192.168.0.1");
-        final InetAddress dstAddr = InetAddresses.parseNumericAddress("192.168.0.10");
         final int srcPort = 1234;
         final int dstPort = 4321;
         final int sequence = 0x11111111;
         final int ack = 0x22222222;
         final int wnd = 48_000;
         final int wndScale = 2;
+        final TcpKeepalivePacketDataParcelable testInfo = new TcpKeepalivePacketDataParcelable();
+        testInfo.srcAddress = IPV4_KEEPALIVE_SRC_ADDR;
+        testInfo.srcPort = srcPort;
+        testInfo.dstAddress = IPV4_KEEPALIVE_DST_ADDR;
+        testInfo.dstPort = dstPort;
+        testInfo.seq = sequence;
+        testInfo.ack = ack;
+        testInfo.rcvWnd = wnd;
+        testInfo.rcvWndScale = wndScale;
         TcpKeepalivePacketData testData = null;
         TcpKeepalivePacketDataParcelable resultData = null;
-        TcpSocketInfo testInfo = new TcpSocketInfo(
-                srcAddr, srcPort, dstAddr, dstPort, sequence, ack, wnd, wndScale);
         testData = TcpKeepalivePacketData.tcpKeepalivePacket(testInfo);
         resultData = testData.toStableParcelable();
-        assertArrayEquals(resultData.srcAddress, srcAddr.getAddress());
-        assertArrayEquals(resultData.dstAddress, dstAddr.getAddress());
+        assertArrayEquals(resultData.srcAddress, IPV4_KEEPALIVE_SRC_ADDR);
+        assertArrayEquals(resultData.dstAddress, IPV4_KEEPALIVE_DST_ADDR);
         assertEquals(resultData.srcPort, srcPort);
         assertEquals(resultData.dstPort, dstPort);
         assertEquals(resultData.seq, sequence);
         assertEquals(resultData.ack, ack);
+        assertEquals(resultData.rcvWnd, wnd);
+        assertEquals(resultData.rcvWndScale, wndScale);
     }
 }
diff --git a/tests/net/java/android/net/apf/ApfCapabilitiesTest.java b/tests/net/java/android/net/apf/ApfCapabilitiesTest.java
new file mode 100644
index 0000000..75752c3
--- /dev/null
+++ b/tests/net/java/android/net/apf/ApfCapabilitiesTest.java
@@ -0,0 +1,50 @@
+/*
+ * 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 android.net.apf;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
+
+import android.net.shared.ParcelableTestUtil;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.internal.util.TestUtils;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class ApfCapabilitiesTest {
+    @Test
+    public void testParcelUnparcel() {
+        final ApfCapabilities caps = new ApfCapabilities(123, 456, 789);
+        ParcelableTestUtil.assertFieldCountEquals(3, ApfCapabilities.class);
+
+        TestUtils.assertParcelingIsLossless(caps, ApfCapabilities.CREATOR);
+    }
+
+    @Test
+    public void testEquals() {
+        assertEquals(new ApfCapabilities(1, 2, 3), new ApfCapabilities(1, 2, 3));
+        assertNotEquals(new ApfCapabilities(2, 2, 3), new ApfCapabilities(1, 2, 3));
+        assertNotEquals(new ApfCapabilities(1, 3, 3), new ApfCapabilities(1, 2, 3));
+        assertNotEquals(new ApfCapabilities(1, 2, 4), new ApfCapabilities(1, 2, 3));
+    }
+}
diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java
index 3263ef9..9dfe436 100644
--- a/tests/net/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java
@@ -495,7 +495,7 @@
             try {
                 doAnswer(validateAnswer).when(mNetworkMonitor).notifyNetworkConnected();
                 doAnswer(validateAnswer).when(mNetworkMonitor).forceReevaluation(anyInt());
-                doAnswer(validateAnswer).when(mNetworkMonitor).notifyAcceptPartialConnectivity();
+                doAnswer(validateAnswer).when(mNetworkMonitor).setAcceptPartialConnectivity();
             } catch (RemoteException e) {
                 fail(e.getMessage());
             }
@@ -2550,7 +2550,7 @@
         verifyActiveNetwork(TRANSPORT_CELLULAR);
     }
 
-    // TODO: deflake and re-enable
+    // TODO(b/128426024): deflake and re-enable
     // @Test
     public void testPartialConnectivity() {
         // Register network callback.
@@ -2585,7 +2585,7 @@
         waitForIdle();
         try {
             verify(mWiFiNetworkAgent.mNetworkMonitor,
-                    timeout(TIMEOUT_MS).times(1)).notifyAcceptPartialConnectivity();
+                    timeout(TIMEOUT_MS).times(1)).setAcceptPartialConnectivity();
         } catch (RemoteException e) {
             fail(e.getMessage());
         }
@@ -2641,7 +2641,7 @@
         waitForIdle();
         try {
             verify(mWiFiNetworkAgent.mNetworkMonitor,
-                    timeout(TIMEOUT_MS).times(1)).notifyAcceptPartialConnectivity();
+                    timeout(TIMEOUT_MS).times(1)).setAcceptPartialConnectivity();
         } catch (RemoteException e) {
             fail(e.getMessage());
         }
diff --git a/tests/net/java/com/android/server/NetworkManagementServiceTest.java b/tests/net/java/com/android/server/NetworkManagementServiceTest.java
index 6fb3225..968b307 100644
--- a/tests/net/java/com/android/server/NetworkManagementServiceTest.java
+++ b/tests/net/java/com/android/server/NetworkManagementServiceTest.java
@@ -16,6 +16,7 @@
 
 package com.android.server;
 
+import static org.mockito.Mockito.doNothing;
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.reset;
@@ -23,11 +24,11 @@
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.verifyNoMoreInteractions;
 
+import android.annotation.NonNull;
 import android.content.Context;
 import android.net.INetd;
+import android.net.INetdUnsolicitedEventListener;
 import android.net.LinkAddress;
-import android.net.LocalServerSocket;
-import android.net.LocalSocket;
 import android.os.BatteryStats;
 import android.os.Binder;
 import android.os.IBinder;
@@ -43,12 +44,11 @@
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Captor;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 
-import java.io.IOException;
-import java.io.OutputStream;
-
 /**
  * Tests for {@link NetworkManagementService}.
  */
@@ -56,16 +56,16 @@
 @SmallTest
 public class NetworkManagementServiceTest {
 
-    private static final String SOCKET_NAME = "__test__NetworkManagementServiceTest";
     private NetworkManagementService mNMService;
-    private LocalServerSocket mServerSocket;
-    private LocalSocket mSocket;
-    private OutputStream mOutputStream;
 
     @Mock private Context mContext;
     @Mock private IBatteryStats.Stub mBatteryStatsService;
     @Mock private INetd.Stub mNetdService;
 
+    @NonNull
+    @Captor
+    private ArgumentCaptor<INetdUnsolicitedEventListener> mUnsolListenerCaptor;
+
     private final SystemServices mServices = new SystemServices() {
         @Override
         public IBinder getService(String name) {
@@ -88,32 +88,15 @@
     @Before
     public void setUp() throws Exception {
         MockitoAnnotations.initMocks(this);
-
-        // Set up a sheltered test environment.
-        mServerSocket = new LocalServerSocket(SOCKET_NAME);
-
+        doNothing().when(mNetdService)
+                .registerUnsolicitedEventListener(mUnsolListenerCaptor.capture());
         // Start the service and wait until it connects to our socket.
-        mNMService = NetworkManagementService.create(mContext, SOCKET_NAME, mServices);
-        mSocket = mServerSocket.accept();
-        mOutputStream = mSocket.getOutputStream();
+        mNMService = NetworkManagementService.create(mContext, mServices);
     }
 
     @After
     public void tearDown() throws Exception {
         mNMService.shutdown();
-        // Once NetworkManagementService#shutdown() actually does something and shutdowns
-        // the underlying NativeDaemonConnector, the block below should be uncommented.
-        // if (mOutputStream != null) mOutputStream.close();
-        // if (mSocket != null) mSocket.close();
-        // if (mServerSocket != null) mServerSocket.close();
-    }
-
-    /**
-     * Sends a message on the netd socket and gives the events some time to make it back.
-     */
-    private void sendMessage(String message) throws IOException {
-        // Strings are null-terminated, so add "\0" at the end.
-        mOutputStream.write((message + "\0").getBytes());
     }
 
     private static <T> T expectSoon(T mock) {
@@ -131,125 +114,78 @@
 
         // Forget everything that happened to the mock so far, so we can explicitly verify
         // everything that happens and does not happen to it from now on.
-        reset(observer);
 
-        // Now send NetworkManagementService messages and ensure that the observer methods are
-        // called. After every valid message we expect a callback soon after; to ensure that
+        INetdUnsolicitedEventListener unsolListener = mUnsolListenerCaptor.getValue();
+        reset(observer);
+        // Now call unsolListener methods and ensure that the observer methods are
+        // called. After every method we expect a callback soon after; to ensure that
         // invalid messages don't cause any callbacks, we call verifyNoMoreInteractions at the end.
 
         /**
          * Interface changes.
          */
-        sendMessage("600 Iface added rmnet12");
+        unsolListener.onInterfaceAdded("rmnet12");
         expectSoon(observer).interfaceAdded("rmnet12");
 
-        sendMessage("600 Iface removed eth1");
+        unsolListener.onInterfaceRemoved("eth1");
         expectSoon(observer).interfaceRemoved("eth1");
 
-        sendMessage("607 Iface removed eth1");
-        // Invalid code.
-
-        sendMessage("600 Iface borked lo down");
-        // Invalid event.
-
-        sendMessage("600 Iface changed clat4 up again");
-        // Extra tokens.
-
-        sendMessage("600 Iface changed clat4 up");
+        unsolListener.onInterfaceChanged("clat4", true);
         expectSoon(observer).interfaceStatusChanged("clat4", true);
 
-        sendMessage("600 Iface linkstate rmnet0 down");
+        unsolListener.onInterfaceLinkStateChanged("rmnet0", false);
         expectSoon(observer).interfaceLinkStateChanged("rmnet0", false);
 
-        sendMessage("600 IFACE linkstate clat4 up");
-        // Invalid group.
-
         /**
          * Bandwidth control events.
          */
-        sendMessage("601 limit alert data rmnet_usb0");
+        unsolListener.onQuotaLimitReached("data", "rmnet_usb0");
         expectSoon(observer).limitReached("data", "rmnet_usb0");
 
-        sendMessage("601 invalid alert data rmnet0");
-        // Invalid group.
-
-        sendMessage("601 limit increased data rmnet0");
-        // Invalid event.
-
-
         /**
          * Interface class activity.
          */
-
-        sendMessage("613 IfaceClass active 1 1234 10012");
+        unsolListener.onInterfaceClassActivityChanged(true, 1, 1234, 0);
         expectSoon(observer).interfaceClassDataActivityChanged("1", true, 1234);
 
-        sendMessage("613 IfaceClass idle 9 5678");
+        unsolListener.onInterfaceClassActivityChanged(false, 9, 5678, 0);
         expectSoon(observer).interfaceClassDataActivityChanged("9", false, 5678);
 
-        sendMessage("613 IfaceClass reallyactive 9 4321");
+        unsolListener.onInterfaceClassActivityChanged(false, 9, 4321, 0);
         expectSoon(observer).interfaceClassDataActivityChanged("9", false, 4321);
 
-        sendMessage("613 InterfaceClass reallyactive 1");
-        // Invalid group.
-
-
         /**
          * IP address changes.
          */
-        sendMessage("614 Address updated fe80::1/64 wlan0 128 253");
+        unsolListener.onInterfaceAddressUpdated("fe80::1/64", "wlan0", 128, 253);
         expectSoon(observer).addressUpdated("wlan0", new LinkAddress("fe80::1/64", 128, 253));
 
-        // There is no "added", so we take this as "removed".
-        sendMessage("614 Address added fe80::1/64 wlan0 128 253");
+        unsolListener.onInterfaceAddressRemoved("fe80::1/64", "wlan0", 128, 253);
         expectSoon(observer).addressRemoved("wlan0", new LinkAddress("fe80::1/64", 128, 253));
 
-        sendMessage("614 Address removed 2001:db8::1/64 wlan0 1 0");
+        unsolListener.onInterfaceAddressRemoved("2001:db8::1/64", "wlan0", 1, 0);
         expectSoon(observer).addressRemoved("wlan0", new LinkAddress("2001:db8::1/64", 1, 0));
 
-        sendMessage("614 Address removed 2001:db8::1/64 wlan0 1");
-        // Not enough arguments.
-
-        sendMessage("666 Address removed 2001:db8::1/64 wlan0 1 0");
-        // Invalid code.
-
-
         /**
          * DNS information broadcasts.
          */
-        sendMessage("615 DnsInfo servers rmnet_usb0 3600 2001:db8::1");
+        unsolListener.onInterfaceDnsServerInfo("rmnet_usb0", 3600, new String[]{"2001:db8::1"});
         expectSoon(observer).interfaceDnsServerInfo("rmnet_usb0", 3600,
                 new String[]{"2001:db8::1"});
 
-        sendMessage("615 DnsInfo servers wlan0 14400 2001:db8::1,2001:db8::2");
+        unsolListener.onInterfaceDnsServerInfo("wlan0", 14400,
+                new String[]{"2001:db8::1", "2001:db8::2"});
         expectSoon(observer).interfaceDnsServerInfo("wlan0", 14400,
                 new String[]{"2001:db8::1", "2001:db8::2"});
 
         // We don't check for negative lifetimes, only for parse errors.
-        sendMessage("615 DnsInfo servers wlan0 -3600 ::1");
+        unsolListener.onInterfaceDnsServerInfo("wlan0", -3600, new String[]{"::1"});
         expectSoon(observer).interfaceDnsServerInfo("wlan0", -3600,
                 new String[]{"::1"});
 
-        sendMessage("615 DnsInfo servers wlan0 SIXHUNDRED ::1");
-        // Non-numeric lifetime.
-
-        sendMessage("615 DnsInfo servers wlan0 2001:db8::1");
-        // Missing lifetime.
-
-        sendMessage("615 DnsInfo servers wlan0 3600");
-        // No servers.
-
-        sendMessage("615 DnsInfo servers 3600 wlan0 2001:db8::1,2001:db8::2");
-        // Non-numeric lifetime.
-
-        sendMessage("615 DnsInfo wlan0 7200 2001:db8::1,2001:db8::2");
-        // Invalid tokens.
-
-        sendMessage("666 DnsInfo servers wlan0 5400 2001:db8::1");
-        // Invalid code.
-
         // No syntax checking on the addresses.
-        sendMessage("615 DnsInfo servers wlan0 600 ,::,,foo,::1,");
+        unsolListener.onInterfaceDnsServerInfo("wlan0", 600,
+                new String[]{"", "::", "", "foo", "::1"});
         expectSoon(observer).interfaceDnsServerInfo("wlan0", 600,
                 new String[]{"", "::", "", "foo", "::1"});
 
diff --git a/tests/net/java/com/android/server/connectivity/TetheringTest.java b/tests/net/java/com/android/server/connectivity/TetheringTest.java
index fdba723..6c42ac3 100644
--- a/tests/net/java/com/android/server/connectivity/TetheringTest.java
+++ b/tests/net/java/com/android/server/connectivity/TetheringTest.java
@@ -550,7 +550,7 @@
                 mTetheringDependencies.ipv6CoordinatorNotifyList) {
             NetworkState ipv6OnlyState = buildMobileUpstreamState(false, true, false);
             ipSrv.sendMessage(IpServer.CMD_IPV6_TETHER_UPDATE, 0, 0,
-                    upstreamState.linkProperties.isIPv6Provisioned()
+                    upstreamState.linkProperties.isIpv6Provisioned()
                             ? ipv6OnlyState.linkProperties
                             : null);
         }
diff --git a/tests/net/java/com/android/server/net/NetworkStatsCollectionTest.java b/tests/net/java/com/android/server/net/NetworkStatsCollectionTest.java
index 830c928..9b4f49c 100644
--- a/tests/net/java/com/android/server/net/NetworkStatsCollectionTest.java
+++ b/tests/net/java/com/android/server/net/NetworkStatsCollectionTest.java
@@ -101,6 +101,7 @@
     @After
     public void tearDown() throws Exception {
         RecurrenceRule.sClock = sOriginalClock;
+        NetworkTemplate.resetForceAllNetworkTypes();
     }
 
     private void setClock(Instant instant) {
diff --git a/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java b/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java
index 598448b..bce526d 100644
--- a/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java
+++ b/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java
@@ -19,6 +19,7 @@
 import static android.content.Intent.ACTION_UID_REMOVED;
 import static android.content.Intent.EXTRA_UID;
 import static android.net.ConnectivityManager.TYPE_MOBILE;
+import static android.net.ConnectivityManager.TYPE_VPN;
 import static android.net.ConnectivityManager.TYPE_WIFI;
 import static android.net.ConnectivityManager.TYPE_WIMAX;
 import static android.net.NetworkStats.DEFAULT_NETWORK_ALL;
@@ -41,6 +42,7 @@
 import static android.net.NetworkStats.UID_ALL;
 import static android.net.NetworkStatsHistory.FIELD_ALL;
 import static android.net.NetworkTemplate.buildTemplateMobileAll;
+import static android.net.NetworkTemplate.buildTemplateMobileWildcard;
 import static android.net.NetworkTemplate.buildTemplateWifiWildcard;
 import static android.net.TrafficStats.MB_IN_BYTES;
 import static android.net.TrafficStats.UID_REMOVED;
@@ -132,6 +134,8 @@
 
     private static final String TEST_IFACE = "test0";
     private static final String TEST_IFACE2 = "test1";
+    private static final String TUN_IFACE = "test_nss_tun0";
+
     private static final long TEST_START = 1194220800000L;
 
     private static final String IMSI_1 = "310004";
@@ -145,10 +149,12 @@
     private static final int UID_RED = 1001;
     private static final int UID_BLUE = 1002;
     private static final int UID_GREEN = 1003;
-
+    private static final int UID_VPN = 1004;
 
     private static final Network WIFI_NETWORK =  new Network(100);
     private static final Network MOBILE_NETWORK =  new Network(101);
+    private static final Network VPN_NETWORK = new Network(102);
+
     private static final Network[] NETWORKS_WIFI = new Network[]{ WIFI_NETWORK };
     private static final Network[] NETWORKS_MOBILE = new Network[]{ MOBILE_NETWORK };
 
@@ -914,7 +920,113 @@
         assertNetworkTotal(sTemplateImsi1, 2048L, 16L, 512L, 4L, 0);
         assertUidTotal(sTemplateImsi1, UID_RED, 128L, 2L, 128L, 2L, 0);
         assertUidTotal(sTemplateImsi1, UID_TETHERING, 1920L, 14L, 384L, 2L, 0);
+    }
 
+    @Test
+    public void vpnWithOneUnderlyingIface() throws Exception {
+        // WiFi network is connected and VPN is using WiFi (which has TEST_IFACE).
+        expectDefaultSettings();
+        NetworkState[] networkStates = new NetworkState[] {buildWifiState(), buildVpnState()};
+        VpnInfo[] vpnInfos = new VpnInfo[] {createVpnInfo(TEST_IFACE)};
+        expectNetworkStatsUidDetail(buildEmptyStats());
+        expectBandwidthControlCheck();
+
+        mService.forceUpdateIfaces(
+                new Network[] {WIFI_NETWORK, VPN_NETWORK},
+                vpnInfos,
+                networkStates,
+                getActiveIface(networkStates));
+        // create some traffic (assume 10 bytes of MTU for VPN interface and 1 byte encryption
+        // overhead per packet):
+        // 1000 bytes (100 packets) were sent/received by UID_RED over VPN.
+        // 500 bytes (50 packets) were sent/received by UID_BLUE over VPN.
+        // VPN sent/received 1650 bytes (150 packets) over WiFi.
+        // Of 1650 bytes over WiFi, expect 1000 bytes attributed to UID_RED, 500 bytes attributed to
+        // UID_BLUE, and 150 bytes attributed to UID_VPN for both rx/tx traffic.
+        incrementCurrentTime(HOUR_IN_MILLIS);
+        expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 3)
+                .addValues(TUN_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 1000L, 100L, 1000L, 100L, 1L)
+                .addValues(TUN_IFACE, UID_BLUE, SET_DEFAULT, TAG_NONE, 500L, 50L, 500L, 50L, 1L)
+                .addValues(
+                    TEST_IFACE, UID_VPN, SET_DEFAULT, TAG_NONE, 1650L, 150L, 1650L, 150L, 2L));
+
+        forcePollAndWaitForIdle();
+
+        assertUidTotal(sTemplateWifi, UID_RED, 1000L, 100L, 1000L, 100L, 1);
+        assertUidTotal(sTemplateWifi, UID_BLUE, 500L, 50L, 500L, 50L, 1);
+        assertUidTotal(sTemplateWifi, UID_VPN, 150L, 0L, 150L, 0L, 2);
+    }
+
+    @Test
+    public void vpnWithOneUnderlyingIface_withCompression() throws Exception {
+        // WiFi network is connected and VPN is using WiFi (which has TEST_IFACE).
+        expectDefaultSettings();
+        NetworkState[] networkStates = new NetworkState[] {buildWifiState(), buildVpnState()};
+        VpnInfo[] vpnInfos = new VpnInfo[] {createVpnInfo(TEST_IFACE)};
+        expectNetworkStatsUidDetail(buildEmptyStats());
+        expectBandwidthControlCheck();
+
+        mService.forceUpdateIfaces(
+                new Network[] {WIFI_NETWORK, VPN_NETWORK},
+                vpnInfos,
+                networkStates,
+                getActiveIface(networkStates));
+        // create some traffic (assume 10 bytes of MTU for VPN interface and 1 byte encryption
+        // overhead per packet):
+        // 1000 bytes (100 packets) were sent/received by UID_RED over VPN.
+        // 3000 bytes (300 packets) were sent/received by UID_BLUE over VPN.
+        // VPN sent/received 1000 bytes (100 packets) over WiFi.
+        // Of 1000 bytes over WiFi, expect 250 bytes attributed UID_RED and 750 bytes to UID_BLUE,
+        // with nothing attributed to UID_VPN for both rx/tx traffic.
+        incrementCurrentTime(HOUR_IN_MILLIS);
+        expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 3)
+                .addValues(TUN_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 1000L, 100L, 1000L, 100L, 1L)
+                .addValues(TUN_IFACE, UID_BLUE, SET_DEFAULT, TAG_NONE, 3000L, 300L, 3000L, 300L, 1L)
+                .addValues(
+                    TEST_IFACE, UID_VPN, SET_DEFAULT, TAG_NONE, 1000L, 100L, 1000L, 100L, 0L));
+
+        forcePollAndWaitForIdle();
+
+        assertUidTotal(sTemplateWifi, UID_RED, 250L, 25L, 250L, 25L, 0);
+        assertUidTotal(sTemplateWifi, UID_BLUE, 750L, 75L, 750L, 75L, 0);
+        assertUidTotal(sTemplateWifi, UID_VPN, 0L, 0L, 0L, 0L, 0);
+    }
+
+    @Test
+    public void vpnWithIncorrectUnderlyingIface() throws Exception {
+        // WiFi and Cell networks are connected and VPN is using Cell (which has TEST_IFACE2),
+        // but has declared only WiFi (TEST_IFACE) in its underlying network set.
+        expectDefaultSettings();
+        NetworkState[] networkStates =
+                new NetworkState[] {
+                    buildWifiState(), buildMobile4gState(TEST_IFACE2), buildVpnState()
+                };
+        VpnInfo[] vpnInfos = new VpnInfo[] {createVpnInfo(TEST_IFACE)};
+        expectNetworkStatsUidDetail(buildEmptyStats());
+        expectBandwidthControlCheck();
+
+        mService.forceUpdateIfaces(
+                new Network[] {WIFI_NETWORK, VPN_NETWORK},
+                vpnInfos,
+                networkStates,
+                getActiveIface(networkStates));
+        // create some traffic (assume 10 bytes of MTU for VPN interface and 1 byte encryption
+        // overhead per packet):
+        // 1000 bytes (100 packets) were sent/received by UID_RED over VPN.
+        // VPN sent/received 1100 bytes (100 packets) over Cell.
+        // Of 1100 bytes over Cell, expect all of it attributed to UID_VPN for both rx/tx traffic.
+        incrementCurrentTime(HOUR_IN_MILLIS);
+        expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 2)
+                .addValues(TUN_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 1000L, 100L, 1000L, 100L, 1L)
+                .addValues(
+                    TEST_IFACE2, UID_VPN, SET_DEFAULT, TAG_NONE, 1100L, 100L, 1100L, 100L, 1L));
+
+        forcePollAndWaitForIdle();
+
+        assertUidTotal(sTemplateWifi, UID_RED, 0L, 0L, 0L, 0L, 0);
+        assertUidTotal(sTemplateWifi, UID_VPN, 0L, 0L, 0L, 0L, 0);
+        assertUidTotal(buildTemplateMobileWildcard(), UID_RED, 0L, 0L, 0L, 0L, 0);
+        assertUidTotal(buildTemplateMobileWildcard(), UID_VPN, 1100L, 100L, 1100L, 100L, 1);
     }
 
     @Test
@@ -1262,6 +1374,22 @@
         return new NetworkStats(getElapsedRealtime(), 0);
     }
 
+    private static NetworkState buildVpnState() {
+        final NetworkInfo info = new NetworkInfo(TYPE_VPN, 0, null, null);
+        info.setDetailedState(DetailedState.CONNECTED, null, null);
+        final LinkProperties prop = new LinkProperties();
+        prop.setInterfaceName(TUN_IFACE);
+        return new NetworkState(info, prop, new NetworkCapabilities(), VPN_NETWORK, null, null);
+    }
+
+    private static VpnInfo createVpnInfo(String underlyingIface) {
+        VpnInfo info = new VpnInfo();
+        info.ownerUid = UID_VPN;
+        info.vpnIface = TUN_IFACE;
+        info.primaryUnderlyingIface = underlyingIface;
+        return info;
+    }
+
     private long getElapsedRealtime() {
         return mElapsedRealtime;
     }
diff --git a/tools/aapt2/Android.bp b/tools/aapt2/Android.bp
index 8bef221..aca2be1 100644
--- a/tools/aapt2/Android.bp
+++ b/tools/aapt2/Android.bp
@@ -198,3 +198,22 @@
     static_libs: ["libaapt2"],
     defaults: ["aapt2_defaults"],
 }
+
+// ==========================================================
+// Dist the protos
+// ==========================================================
+genrule {
+    name: "aapt2-protos",
+    tools: [":soong_zip"],
+    srcs: [
+        "Configuration.proto",
+        "Resources.proto",
+    ],
+    out: ["aapt2-protos.zip"],
+    cmd: "mkdir $(genDir)/protos && " +
+        "cp $(in) $(genDir)/protos && " +
+        "$(location :soong_zip) -o $(out) -C $(genDir)/protos -D $(genDir)/protos",
+    dist: {
+        targets: ["sdk_repo"],
+    },
+}
diff --git a/tools/aapt2/cmd/Dump.h b/tools/aapt2/cmd/Dump.h
index 5cf056e..7ded9bc 100644
--- a/tools/aapt2/cmd/Dump.h
+++ b/tools/aapt2/cmd/Dump.h
@@ -32,6 +32,7 @@
  public:
   explicit DumpApkCommand(const std::string&& name, text::Printer* printer, IDiagnostics* diag)
       : Command(name), printer_(printer), diag_(diag) {
+        SetDescription("Dump information about an APK or APC.");
   }
 
   text::Printer* GetPrinter() {
diff --git a/tools/aapt2/link/TableMerger.cpp b/tools/aapt2/link/TableMerger.cpp
index e937517..a24e0d2f 100644
--- a/tools/aapt2/link/TableMerger.cpp
+++ b/tools/aapt2/link/TableMerger.cpp
@@ -58,7 +58,7 @@
       // valid. This is because un-mangled references are mangled, then looked up at resolution
       // time. Also, when linking, we convert references with no package name to use the compilation
       // package name.
-      error |= !DoMerge(src, table, package.get(), false /*mangle*/, overlay, allow_new);
+      error |= !DoMerge(src, package.get(), false /*mangle*/, overlay, allow_new);
     }
   }
   return !error;
@@ -78,7 +78,7 @@
 
     bool mangle = package_name != context_->GetCompilationPackage();
     merged_packages_.insert(package->name);
-    error |= !DoMerge(src, table, package.get(), mangle, false /*overlay*/, true /*allow_new*/);
+    error |= !DoMerge(src, package.get(), mangle, false /*overlay*/, true /*allow_new*/);
   }
   return !error;
 }
@@ -213,9 +213,8 @@
   return collision_result;
 }
 
-bool TableMerger::DoMerge(const Source& src, ResourceTable* src_table,
-                          ResourceTablePackage* src_package, bool mangle_package, bool overlay,
-                          bool allow_new_resources) {
+bool TableMerger::DoMerge(const Source& src, ResourceTablePackage* src_package, bool mangle_package,
+                          bool overlay, bool allow_new_resources) {
   bool error = false;
 
   for (auto& src_type : src_package->types) {
@@ -337,8 +336,7 @@
       ->FindOrCreateValue(file_desc.config, {})
       ->value = std::move(file_ref);
 
-  return DoMerge(file->GetSource(), &table, pkg, false /*mangle*/, overlay /*overlay*/,
-                 true /*allow_new*/);
+  return DoMerge(file->GetSource(), pkg, false /*mangle*/, overlay /*overlay*/, true /*allow_new*/);
 }
 
 }  // namespace aapt
diff --git a/tools/aapt2/link/TableMerger.h b/tools/aapt2/link/TableMerger.h
index 24c5e13..51305cf 100644
--- a/tools/aapt2/link/TableMerger.h
+++ b/tools/aapt2/link/TableMerger.h
@@ -85,8 +85,8 @@
 
   bool MergeImpl(const Source& src, ResourceTable* src_table, bool overlay, bool allow_new);
 
-  bool DoMerge(const Source& src, ResourceTable* src_table, ResourceTablePackage* src_package,
-               bool mangle_package, bool overlay, bool allow_new_resources);
+  bool DoMerge(const Source& src, ResourceTablePackage* src_package, bool mangle_package,
+               bool overlay, bool allow_new_resources);
 
   std::unique_ptr<FileReference> CloneAndMangleFile(const std::string& package,
                                                     const FileReference& value);
diff --git a/tools/processors/view_inspector/src/java/android/processor/view/inspector/InspectableClassModel.java b/tools/processors/view_inspector/src/java/android/processor/view/inspector/InspectableClassModel.java
index 147f054..04710e4 100644
--- a/tools/processors/view_inspector/src/java/android/processor/view/inspector/InspectableClassModel.java
+++ b/tools/processors/view_inspector/src/java/android/processor/view/inspector/InspectableClassModel.java
@@ -39,7 +39,6 @@
 public final class InspectableClassModel {
     private final @NonNull ClassName mClassName;
     private final @NonNull Map<String, Property> mPropertyMap;
-    private @NonNull Optional<String> mNodeName = Optional.empty();
 
     /**
      * @param className The name of the modeled class
@@ -54,15 +53,6 @@
         return mClassName;
     }
 
-    @NonNull
-    public Optional<String> getNodeName() {
-        return mNodeName;
-    }
-
-    public void setNodeName(@NonNull Optional<String> nodeName) {
-        mNodeName = nodeName;
-    }
-
     /**
      * Add a property to the model, replacing an existing property of the same name.
      *
diff --git a/tools/processors/view_inspector/src/java/android/processor/view/inspector/InspectableNodeNameProcessor.java b/tools/processors/view_inspector/src/java/android/processor/view/inspector/InspectableNodeNameProcessor.java
deleted file mode 100644
index 64a60fb..0000000
--- a/tools/processors/view_inspector/src/java/android/processor/view/inspector/InspectableNodeNameProcessor.java
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * Copyright 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 android.processor.view.inspector;
-
-import androidx.annotation.NonNull;
-
-import java.util.Optional;
-
-import javax.annotation.processing.ProcessingEnvironment;
-import javax.lang.model.element.AnnotationMirror;
-import javax.lang.model.element.Element;
-
-/**
- * Process {@code @InspectableNodeName} annotations.
- *
- * @see android.view.inspector.InspectableNodeName
- */
-public final class InspectableNodeNameProcessor implements ModelProcessor {
-    private final @NonNull String mQualifiedName;
-    private final @NonNull ProcessingEnvironment mProcessingEnv;
-    private final @NonNull AnnotationUtils mAnnotationUtils;
-
-    /**
-     * @param annotationQualifiedName The qualified name of the annotation to process
-     * @param processingEnv The processing environment from the parent processor
-     */
-    public InspectableNodeNameProcessor(
-            @NonNull String annotationQualifiedName,
-            @NonNull ProcessingEnvironment processingEnv) {
-        mQualifiedName = annotationQualifiedName;
-        mProcessingEnv = processingEnv;
-        mAnnotationUtils = new AnnotationUtils(processingEnv);
-    }
-
-    /**
-     * Set the node name on the model if one is supplied.
-     *
-     * If the model already has a different node name, the node name will not be updated, and
-     * the processor will print an error the the messager.
-     *
-     * @param element The annotated element to operate on
-     * @param model The model this element should be merged into
-     */
-    @Override
-    public void process(@NonNull Element element, @NonNull InspectableClassModel model) {
-        try {
-            final AnnotationMirror mirror =
-                    mAnnotationUtils.exactlyOneMirror(mQualifiedName, element);
-            final Optional<String> nodeName = mAnnotationUtils
-                    .typedValueByName("value", String.class, element, mirror);
-
-            if (!model.getNodeName().isPresent() || model.getNodeName().equals(nodeName)) {
-                model.setNodeName(nodeName);
-            } else {
-                final String message = String.format(
-                        "Node name was already set to \"%s\", refusing to change it to \"%s\".",
-                        model.getNodeName().get(),
-                        nodeName);
-                throw new ProcessingException(message, element, mirror);
-            }
-        } catch (ProcessingException processingException) {
-            processingException.print(mProcessingEnv.getMessager());
-        }
-    }
-}
diff --git a/tools/processors/view_inspector/src/java/android/processor/view/inspector/InspectablePropertyProcessor.java b/tools/processors/view_inspector/src/java/android/processor/view/inspector/InspectablePropertyProcessor.java
index 2042a68..2bd867c 100644
--- a/tools/processors/view_inspector/src/java/android/processor/view/inspector/InspectablePropertyProcessor.java
+++ b/tools/processors/view_inspector/src/java/android/processor/view/inspector/InspectablePropertyProcessor.java
@@ -46,7 +46,7 @@
  *
  * @see android.view.inspector.InspectableProperty
  */
-public final class InspectablePropertyProcessor implements ModelProcessor {
+public final class InspectablePropertyProcessor {
     private final @NonNull String mQualifiedName;
     private final @NonNull ProcessingEnvironment mProcessingEnv;
     private final @NonNull AnnotationUtils mAnnotationUtils;
@@ -139,7 +139,6 @@
         mAnnotationUtils = new AnnotationUtils(processingEnv);
     }
 
-    @Override
     public void process(@NonNull Element element, @NonNull InspectableClassModel model) {
         try {
             final AnnotationMirror annotation =
@@ -608,7 +607,7 @@
      * Build a model of an {@code int} enumeration mapping from annotation values.
      *
      * This method only handles the one-to-one mapping of mirrors of
-     * {@link android.view.inspector.InspectableProperty.EnumMap} annotations into
+     * {@link android.view.inspector.InspectableProperty.EnumEntry} annotations into
      * {@link IntEnumEntry} objects. Further validation should be handled elsewhere
      *
      * @see android.view.inspector.InspectableProperty#enumMapping()
@@ -635,14 +634,14 @@
             final String name = mAnnotationUtils.typedValueByName(
                     "name", String.class, accessor, enumAnnotation)
                     .orElseThrow(() -> new ProcessingException(
-                            "Name is required for @EnumMap",
+                            "Name is required for @EnumEntry",
                             accessor,
                             enumAnnotation));
 
             final int value = mAnnotationUtils.typedValueByName(
                     "value", Integer.class, accessor, enumAnnotation)
                     .orElseThrow(() -> new ProcessingException(
-                            "Value is required for @EnumMap",
+                            "Value is required for @EnumEntry",
                             accessor,
                             enumAnnotation));
 
@@ -656,7 +655,7 @@
      * Build a model of an {@code int} flag mapping from annotation values.
      *
      * This method only handles the one-to-one mapping of mirrors of
-     * {@link android.view.inspector.InspectableProperty.FlagMap} annotations into
+     * {@link android.view.inspector.InspectableProperty.FlagEntry} annotations into
      * {@link IntFlagEntry} objects. Further validation should be handled elsewhere
      *
      * @see android.view.inspector.IntFlagMapping
@@ -684,14 +683,14 @@
             final String name = mAnnotationUtils.typedValueByName(
                     "name", String.class, accessor, flagAnnotation)
                     .orElseThrow(() -> new ProcessingException(
-                            "Name is required for @FlagMap",
+                            "Name is required for @FlagEntry",
                             accessor,
                             flagAnnotation));
 
             final int target = mAnnotationUtils.typedValueByName(
                     "target", Integer.class, accessor, flagAnnotation)
                     .orElseThrow(() -> new ProcessingException(
-                            "Target is required for @FlagMap",
+                            "Target is required for @FlagEntry",
                             accessor,
                             flagAnnotation));
 
diff --git a/tools/processors/view_inspector/src/java/android/processor/view/inspector/InspectionCompanionGenerator.java b/tools/processors/view_inspector/src/java/android/processor/view/inspector/InspectionCompanionGenerator.java
index c428a46..6e38c24 100644
--- a/tools/processors/view_inspector/src/java/android/processor/view/inspector/InspectionCompanionGenerator.java
+++ b/tools/processors/view_inspector/src/java/android/processor/view/inspector/InspectionCompanionGenerator.java
@@ -163,8 +163,6 @@
                 .addMethod(generateMapProperties(properties, fields))
                 .addMethod(generateReadProperties(properties, fields, model.getClassName()));
 
-        model.getNodeName().ifPresent(name -> builder.addMethod(generateGetNodeName(name)));
-
         return builder.build();
     }
 
@@ -451,31 +449,6 @@
     }
 
     /**
-     * Generate an implementation of
-     * {@link android.view.inspector.InspectionCompanion#getNodeName()}.
-     *
-     * Example:
-     * <pre>
-     *     @Override
-     *     public String getNodeName() {
-     *         return "nodeName";
-     *     }
-     * </pre>
-     *
-     * @param nodeName The name of this node
-     * @return A method definition that returns the node name
-     */
-    @NonNull
-    private MethodSpec generateGetNodeName(@NonNull String nodeName) {
-        return MethodSpec.methodBuilder("getNodeName")
-                .addAnnotation(Override.class)
-                .addModifiers(Modifier.PUBLIC)
-                .returns(String.class)
-                .addStatement("return $S", nodeName)
-                .build();
-    }
-
-    /**
      * Generate the final class name for the inspection companion from the model's class name.
      *
      * The generated class is added to the same package as the source class. If the class in the
diff --git a/tools/processors/view_inspector/src/java/android/processor/view/inspector/ModelProcessor.java b/tools/processors/view_inspector/src/java/android/processor/view/inspector/ModelProcessor.java
deleted file mode 100644
index ab38f4c..0000000
--- a/tools/processors/view_inspector/src/java/android/processor/view/inspector/ModelProcessor.java
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * Copyright 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 android.processor.view.inspector;
-
-import androidx.annotation.NonNull;
-
-import javax.lang.model.element.Element;
-
-/**
- * An interface for annotation processors that operate on a single element and a class model.
- */
-public interface ModelProcessor {
-    /**
-     * Process the supplied element, mutating the model as needed.
-     *
-     * @param element The annotated element to operate on
-     * @param model The model this element should be merged into
-     */
-    void process(@NonNull Element element, @NonNull InspectableClassModel model);
-}
diff --git a/tools/processors/view_inspector/src/java/android/processor/view/inspector/PlatformInspectableProcessor.java b/tools/processors/view_inspector/src/java/android/processor/view/inspector/PlatformInspectableProcessor.java
index d9ed1fb..80d3727 100644
--- a/tools/processors/view_inspector/src/java/android/processor/view/inspector/PlatformInspectableProcessor.java
+++ b/tools/processors/view_inspector/src/java/android/processor/view/inspector/PlatformInspectableProcessor.java
@@ -38,25 +38,18 @@
 import javax.lang.model.element.TypeElement;
 import javax.lang.model.util.ElementFilter;
 
-
 /**
  * An annotation processor for the platform inspectable annotations.
  *
- * It mostly delegates to {@link ModelProcessor} and {@link InspectionCompanionGenerator}. This
- * modular architecture allows the core generation code to be reused for comparable annotations
- * outside the platform, such as in AndroidX.
+ * It mostly delegates to {@link InspectablePropertyProcessor} and
+ * {@link InspectionCompanionGenerator}. This modular architecture allows the core generation code
+ * to be reused for comparable annotations outside the platform.
  *
- * @see android.view.inspector.InspectableNodeName
  * @see android.view.inspector.InspectableProperty
  */
-@SupportedAnnotationTypes({
-        PlatformInspectableProcessor.NODE_NAME_QUALIFIED_NAME,
-        PlatformInspectableProcessor.PROPERTY_QUALIFIED_NAME
-})
+@SupportedAnnotationTypes({PlatformInspectableProcessor.ANNOTATION_QUALIFIED_NAME})
 public final class PlatformInspectableProcessor extends AbstractProcessor {
-    static final String NODE_NAME_QUALIFIED_NAME =
-            "android.view.inspector.InspectableNodeName";
-    static final String PROPERTY_QUALIFIED_NAME =
+    static final String ANNOTATION_QUALIFIED_NAME =
             "android.view.inspector.InspectableProperty";
 
     @Override
@@ -71,18 +64,8 @@
         final Map<String, InspectableClassModel> modelMap = new HashMap<>();
 
         for (TypeElement annotation : annotations) {
-            if (annotation.getQualifiedName().contentEquals(NODE_NAME_QUALIFIED_NAME)) {
-                runModelProcessor(
-                        roundEnv.getElementsAnnotatedWith(annotation),
-                        new InspectableNodeNameProcessor(NODE_NAME_QUALIFIED_NAME, processingEnv),
-                        modelMap);
-
-            } else if (annotation.getQualifiedName().contentEquals(PROPERTY_QUALIFIED_NAME)) {
-                runModelProcessor(
-                        roundEnv.getElementsAnnotatedWith(annotation),
-                        new InspectablePropertyProcessor(PROPERTY_QUALIFIED_NAME, processingEnv),
-                        modelMap);
-
+            if (annotation.getQualifiedName().contentEquals(ANNOTATION_QUALIFIED_NAME)) {
+                processProperties(roundEnv.getElementsAnnotatedWith(annotation), modelMap);
             } else {
                 fail("Unexpected annotation type", annotation);
             }
@@ -106,16 +89,17 @@
     }
 
     /**
-     * Run a {@link ModelProcessor} for a set of elements
+     * Runs {@link PlatformInspectableProcessor} on a set of annotated elements.
      *
-     * @param elements Elements to process, should be annotated correctly
-     * @param processor The processor to use
-     * @param modelMap A map of qualified class names to models
+     * @param elements A set of annotated elements to process
+     * @param modelMap A map of qualified class names to class models to update
      */
-    private void runModelProcessor(
+    private void processProperties(
             @NonNull Set<? extends Element> elements,
-            @NonNull ModelProcessor processor,
             @NonNull Map<String, InspectableClassModel> modelMap) {
+        final InspectablePropertyProcessor processor =
+                new InspectablePropertyProcessor(ANNOTATION_QUALIFIED_NAME, processingEnv);
+
         for (Element element : elements) {
             final Optional<TypeElement> classElement = enclosingClassElement(element);
 
diff --git a/tools/processors/view_inspector/test/java/android/processor/view/inspector/InspectionCompanionGeneratorTest.java b/tools/processors/view_inspector/test/java/android/processor/view/inspector/InspectionCompanionGeneratorTest.java
index 3ec620a..c6e6018 100644
--- a/tools/processors/view_inspector/test/java/android/processor/view/inspector/InspectionCompanionGeneratorTest.java
+++ b/tools/processors/view_inspector/test/java/android/processor/view/inspector/InspectionCompanionGeneratorTest.java
@@ -36,7 +36,6 @@
 import java.io.IOException;
 import java.net.URL;
 import java.util.Arrays;
-import java.util.Optional;
 
 /**
  * Tests for {@link InspectionCompanionGenerator}
@@ -56,12 +55,6 @@
     }
 
     @Test
-    public void testNodeName() {
-        mModel.setNodeName(Optional.of("NodeName"));
-        assertGeneratedFileEquals("NodeName");
-    }
-
-    @Test
     public void testNestedClass() {
         mModel = new InspectableClassModel(
                 ClassName.get("com.android.node", "Outer", "Inner"));
diff --git a/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/NodeName.java.txt b/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/NodeName.java.txt
deleted file mode 100644
index ffa1f0b..0000000
--- a/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/NodeName.java.txt
+++ /dev/null
@@ -1,37 +0,0 @@
-package com.android.node;
-
-import android.view.inspector.InspectionCompanion;
-import android.view.inspector.PropertyMapper;
-import android.view.inspector.PropertyReader;
-import java.lang.Override;
-import java.lang.String;
-
-/**
- * Inspection companion for {@link TestNode}.
- *
- * Generated by {@link android.processor.view.inspector.InspectionCompanionGenerator}
- * on behalf of {@link android.processor.view.inspector.InspectionCompanionGeneratorTest}.
- */
-public final class TestNode$InspectionCompanion implements InspectionCompanion<TestNode> {
-    /**
-     * Guards against reading properties before mapping them.
-     */
-    private boolean mPropertiesMapped = false;
-
-    @Override
-    public void mapProperties(PropertyMapper propertyMapper) {
-        mPropertiesMapped = true;
-    }
-
-    @Override
-    public void readProperties(TestNode node, PropertyReader propertyReader) {
-        if (!mPropertiesMapped) {
-            throw new InspectionCompanion.UninitializedPropertyMapException();
-        }
-    }
-
-    @Override
-    public String getNodeName() {
-        return "NodeName";
-    }
-}
diff --git a/wifi/java/android/net/wifi/WifiEnterpriseConfig.java b/wifi/java/android/net/wifi/WifiEnterpriseConfig.java
index 7a505a2..950c6f8 100644
--- a/wifi/java/android/net/wifi/WifiEnterpriseConfig.java
+++ b/wifi/java/android/net/wifi/WifiEnterpriseConfig.java
@@ -139,6 +139,8 @@
     private X509Certificate[] mClientCertificateChain;
     private int mEapMethod = Eap.NONE;
     private int mPhase2Method = Phase2.NONE;
+    private boolean mIsAppInstalledDeviceKeyAndCert = false;
+    private boolean mIsAppInstalledCaCert = false;
 
     private static final String TAG = "WifiEnterpriseConfig";
 
@@ -181,6 +183,8 @@
         }
         mEapMethod = source.mEapMethod;
         mPhase2Method = source.mPhase2Method;
+        mIsAppInstalledDeviceKeyAndCert = source.mIsAppInstalledDeviceKeyAndCert;
+        mIsAppInstalledCaCert = source.mIsAppInstalledCaCert;
     }
 
     /**
@@ -224,6 +228,8 @@
         ParcelUtil.writeCertificates(dest, mCaCerts);
         ParcelUtil.writePrivateKey(dest, mClientPrivateKey);
         ParcelUtil.writeCertificates(dest, mClientCertificateChain);
+        dest.writeBoolean(mIsAppInstalledDeviceKeyAndCert);
+        dest.writeBoolean(mIsAppInstalledCaCert);
     }
 
     public static final @android.annotation.NonNull Creator<WifiEnterpriseConfig> CREATOR =
@@ -243,6 +249,8 @@
                     enterpriseConfig.mCaCerts = ParcelUtil.readCertificates(in);
                     enterpriseConfig.mClientPrivateKey = ParcelUtil.readPrivateKey(in);
                     enterpriseConfig.mClientCertificateChain = ParcelUtil.readCertificates(in);
+                    enterpriseConfig.mIsAppInstalledDeviceKeyAndCert = in.readBoolean();
+                    enterpriseConfig.mIsAppInstalledCaCert = in.readBoolean();
                     return enterpriseConfig;
                 }
 
@@ -652,8 +660,10 @@
     public void setCaCertificate(@Nullable X509Certificate cert) {
         if (cert != null) {
             if (cert.getBasicConstraints() >= 0) {
+                mIsAppInstalledCaCert = true;
                 mCaCerts = new X509Certificate[] {cert};
             } else {
+                mCaCerts = null;
                 throw new IllegalArgumentException("Not a CA certificate");
             }
         } else {
@@ -694,10 +704,12 @@
                 if (certs[i].getBasicConstraints() >= 0) {
                     newCerts[i] = certs[i];
                 } else {
+                    mCaCerts = null;
                     throw new IllegalArgumentException("Not a CA certificate");
                 }
             }
             mCaCerts = newCerts;
+            mIsAppInstalledCaCert = true;
         } else {
             mCaCerts = null;
         }
@@ -853,6 +865,7 @@
 
         mClientPrivateKey = privateKey;
         mClientCertificateChain = newCerts;
+        mIsAppInstalledDeviceKeyAndCert = true;
     }
 
     /**
@@ -1147,4 +1160,30 @@
         }
         return true;
     }
+
+    /**
+     * Check if certificate was installed by an app, or manually (not by an app). If true,
+     * certificate and keys will be removed from key storage when this network is removed. If not,
+     * then certificates and keys remain persistent until the user manually removes them.
+     *
+     * @return true if certificate was installed by an app, false if certificate was installed
+     * manually by the user.
+     * @hide
+     */
+    public boolean isAppInstalledDeviceKeyAndCert() {
+        return mIsAppInstalledDeviceKeyAndCert;
+    }
+
+    /**
+     * Check if CA certificate was installed by an app, or manually (not by an app). If true,
+     * CA certificate will be removed from key storage when this network is removed. If not,
+     * then certificates and keys remain persistent until the user manually removes them.
+     *
+     * @return true if CA certificate was installed by an app, false if CA certificate was installed
+     * manually by the user.
+     * @hide
+     */
+    public boolean isAppInstalledCaCert() {
+        return mIsAppInstalledCaCert;
+    }
 }
diff --git a/wifi/java/android/net/wifi/WifiNetworkSuggestion.java b/wifi/java/android/net/wifi/WifiNetworkSuggestion.java
index 32a7a47..a9c9939 100644
--- a/wifi/java/android/net/wifi/WifiNetworkSuggestion.java
+++ b/wifi/java/android/net/wifi/WifiNetworkSuggestion.java
@@ -403,7 +403,7 @@
          *      .setWpa3Passphrase("test6789")
          *      .build()
          * final List<WifiNetworkSuggestion> suggestionsList =
-         *      new ArrayList<WifiNetworkSuggestion> {{
+         *      new ArrayList<WifiNetworkSuggestion> &#123;{
          *          add(suggestion1);
          *          add(suggestion2);
          *          add(suggestion3);
diff --git a/wifi/java/android/net/wifi/WifiUsabilityStatsEntry.java b/wifi/java/android/net/wifi/WifiUsabilityStatsEntry.java
index 51aa93a..01176f2 100644
--- a/wifi/java/android/net/wifi/WifiUsabilityStatsEntry.java
+++ b/wifi/java/android/net/wifi/WifiUsabilityStatsEntry.java
@@ -20,6 +20,7 @@
 import android.annotation.SystemApi;
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.telephony.TelephonyManager.NetworkType;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
@@ -98,6 +99,10 @@
     private final int mProbeMcsRateSinceLastUpdate;
     /** Rx link speed at the sample time in Mbps */
     private final int mRxLinkSpeedMbps;
+    private final @NetworkType int mCellularDataNetworkType;
+    private final int mCellularSignalStrengthDbm;
+    private final int mCellularSignalStrengthDb;
+    private final boolean mIsSameRegisteredCell;
 
     /** Constructor function {@hide} */
     public WifiUsabilityStatsEntry(long timeStampMillis, int rssi, int linkSpeedMbps,
@@ -109,7 +114,10 @@
             long totalHotspot2ScanTimeMillis,
             long totalCcaBusyFreqTimeMillis, long totalRadioOnFreqTimeMillis, long totalBeaconRx,
             @ProbeStatus int probeStatusSinceLastUpdate, int probeElapsedTimeSinceLastUpdateMillis,
-            int probeMcsRateSinceLastUpdate, int rxLinkSpeedMbps) {
+            int probeMcsRateSinceLastUpdate, int rxLinkSpeedMbps,
+            @NetworkType int cellularDataNetworkType,
+            int cellularSignalStrengthDbm, int cellularSignalStrengthDb,
+            boolean isSameRegisteredCell) {
         mTimeStampMillis = timeStampMillis;
         mRssi = rssi;
         mLinkSpeedMbps = linkSpeedMbps;
@@ -133,6 +141,10 @@
         mProbeElapsedTimeSinceLastUpdateMillis = probeElapsedTimeSinceLastUpdateMillis;
         mProbeMcsRateSinceLastUpdate = probeMcsRateSinceLastUpdate;
         mRxLinkSpeedMbps = rxLinkSpeedMbps;
+        mCellularDataNetworkType = cellularDataNetworkType;
+        mCellularSignalStrengthDbm = cellularSignalStrengthDbm;
+        mCellularSignalStrengthDb = cellularSignalStrengthDb;
+        mIsSameRegisteredCell = isSameRegisteredCell;
     }
 
     /** Implement the Parcelable interface */
@@ -165,6 +177,10 @@
         dest.writeInt(mProbeElapsedTimeSinceLastUpdateMillis);
         dest.writeInt(mProbeMcsRateSinceLastUpdate);
         dest.writeInt(mRxLinkSpeedMbps);
+        dest.writeInt(mCellularDataNetworkType);
+        dest.writeInt(mCellularSignalStrengthDbm);
+        dest.writeInt(mCellularSignalStrengthDb);
+        dest.writeBoolean(mIsSameRegisteredCell);
     }
 
     /** Implement the Parcelable interface */
@@ -179,7 +195,9 @@
                     in.readLong(), in.readLong(), in.readLong(),
                     in.readLong(), in.readLong(), in.readLong(),
                     in.readLong(), in.readLong(), in.readInt(),
-                    in.readInt(), in.readInt(), in.readInt()
+                    in.readInt(), in.readInt(), in.readInt(),
+                    in.readInt(), in.readInt(), in.readInt(),
+                    in.readBoolean()
             );
         }
 
@@ -304,4 +322,30 @@
     public int getRxLinkSpeedMbps() {
         return mRxLinkSpeedMbps;
     }
+
+    /** Cellular data network type currently in use on the device for data transmission */
+    @NetworkType public int getCellularDataNetworkType() {
+        return mCellularDataNetworkType;
+    }
+
+    /**
+     * Cellular signal strength in dBm, NR: CsiRsrp, LTE: Rsrp, WCDMA/TDSCDMA: Rscp,
+     * CDMA: Rssi, EVDO: Rssi, GSM: Rssi
+     */
+    public int getCellularSignalStrengthDbm() {
+        return mCellularSignalStrengthDbm;
+    }
+
+    /**
+     * Cellular signal strength in dB, NR: CsiSinr, LTE: Rsrq, WCDMA: EcNo, TDSCDMA: invalid,
+     * CDMA: Ecio, EVDO: SNR, GSM: invalid
+     */
+    public int getCellularSignalStrengthDb() {
+        return mCellularSignalStrengthDb;
+    }
+
+    /** Whether the primary registered cell of current entry is same as that of previous entry */
+    public boolean getIsSameRegisteredCell() {
+        return mIsSameRegisteredCell;
+    }
 }
diff --git a/wifi/java/android/net/wifi/aware/WifiAwareNetworkSpecifier.java b/wifi/java/android/net/wifi/aware/WifiAwareNetworkSpecifier.java
index b225116..daea601 100644
--- a/wifi/java/android/net/wifi/aware/WifiAwareNetworkSpecifier.java
+++ b/wifi/java/android/net/wifi/aware/WifiAwareNetworkSpecifier.java
@@ -18,6 +18,7 @@
 
 import static android.net.wifi.aware.WifiAwareManager.WIFI_AWARE_DATA_PATH_ROLE_INITIATOR;
 
+import android.annotation.IntRange;
 import android.annotation.NonNull;
 import android.annotation.SystemApi;
 import android.net.NetworkSpecifier;
@@ -302,12 +303,6 @@
     /**
      * A builder class for a Wi-Fi Aware network specifier to set up an Aware connection with a
      * peer.
-     * <p>
-     * Note that all Wi-Fi Aware connection specifier objects must call the
-     * {@link Builder#setDiscoverySession(DiscoverySession)} to specify the context
-     * within which the connection is created, and
-     * {@link Builder#setPeerHandle(PeerHandle)} to specify the peer to which the
-     * connection is created.
      */
     public static final class Builder {
         private DiscoverySession mDiscoverySession;
@@ -318,42 +313,27 @@
         private int mTransportProtocol = -1; // invalid value
 
         /**
-         * Configure the {@link PublishDiscoverySession} or {@link SubscribeDiscoverySession}
-         * discovery session in whose context the connection is created.
-         * <p>
-         * Note: this method must be called for any connection request!
+         * Create a builder for {@link WifiAwareNetworkSpecifier} used in requests to set up a
+         * Wi-Fi Aware connection with a peer.
          *
-         * @param discoverySession A Wi-Fi Aware discovery session.
-         * @return the current {@link Builder} builder, enabling chaining of builder
-         *         methods.
-         */
-        public @NonNull Builder setDiscoverySession(@NonNull DiscoverySession discoverySession) {
-            if (discoverySession == null) {
-                throw new IllegalArgumentException("Non-null discoverySession required");
-            }
-            mDiscoverySession = discoverySession;
-            return this;
-        }
-
-        /**
-         * Configure the {@link PeerHandle} of the peer to which the Wi-Fi Aware connection is
-         * requested. The peer is discovered through Wi-Fi Aware discovery,
-         * <p>
-         * Note: this method must be called for any connection request!
-         *
-         * @param peerHandle The peer's handle obtained through
+         * @param discoverySession A Wi-Fi Aware discovery session in whose context the connection
+         *                         is created.
+         * @param peerHandle The handle of the peer to which the Wi-Fi Aware connection is
+         *                   requested. The peer is discovered through Wi-Fi Aware discovery. The
+         *                   handle can be obtained through
          * {@link DiscoverySessionCallback#onServiceDiscovered(PeerHandle, byte[], java.util.List)}
          *                   or
          *                   {@link DiscoverySessionCallback#onMessageReceived(PeerHandle, byte[])}.
-         * @return the current {@link Builder} builder, enabling chaining of builder
-         *         methods.
          */
-        public @NonNull Builder setPeerHandle(@NonNull PeerHandle peerHandle) {
+        public Builder(@NonNull DiscoverySession discoverySession, @NonNull PeerHandle peerHandle) {
+            if (discoverySession == null) {
+                throw new IllegalArgumentException("Non-null discoverySession required");
+            }
             if (peerHandle == null) {
                 throw new IllegalArgumentException("Non-null peerHandle required");
             }
+            mDiscoverySession = discoverySession;
             mPeerHandle = peerHandle;
-            return this;
         }
 
         /**
@@ -407,7 +387,7 @@
          * @return the current {@link Builder} builder, enabling chaining of builder
          *         methods.
          */
-        public @NonNull Builder setPort(int port) {
+        public @NonNull Builder setPort(@IntRange(from = 0, to = 65535) int port) {
             if (port <= 0 || port > 65535) {
                 throw new IllegalArgumentException("The port must be a positive value (0, 65535]");
             }
@@ -432,7 +412,8 @@
          * @return the current {@link Builder} builder, enabling chaining of builder
          *         methods.
          */
-        public @NonNull Builder setTransportProtocol(int transportProtocol) {
+        public @NonNull
+                Builder setTransportProtocol(@IntRange(from = 0, to = 255) int transportProtocol) {
             if (transportProtocol < 0 || transportProtocol > 255) {
                 throw new IllegalArgumentException(
                         "The transport protocol must be in range [0, 255]");
@@ -460,6 +441,9 @@
             if (mDiscoverySession == null) {
                 throw new IllegalStateException("Null discovery session!?");
             }
+            if (mPeerHandle == null) {
+                throw new IllegalStateException("Null peerHandle!?");
+            }
             if (mPskPassphrase != null & mPmk != null) {
                 throw new IllegalStateException(
                         "Can only specify a Passphrase or a PMK - not both!");
@@ -481,10 +465,6 @@
                 }
             }
 
-            if (role == WIFI_AWARE_DATA_PATH_ROLE_INITIATOR && mPeerHandle == null) {
-                throw new IllegalStateException("Null peerHandle!?");
-            }
-
             return new WifiAwareNetworkSpecifier(
                     WifiAwareNetworkSpecifier.NETWORK_SPECIFIER_TYPE_IB, role,
                     mDiscoverySession.mClientId, mDiscoverySession.mSessionId, mPeerHandle.peerId,
diff --git a/wifi/tests/src/android/net/wifi/WifiEnterpriseConfigTest.java b/wifi/tests/src/android/net/wifi/WifiEnterpriseConfigTest.java
index 6ec64ff..beed666 100644
--- a/wifi/tests/src/android/net/wifi/WifiEnterpriseConfigTest.java
+++ b/wifi/tests/src/android/net/wifi/WifiEnterpriseConfigTest.java
@@ -423,4 +423,68 @@
         mEnterpriseConfig.setPassword(password);
         assertFalse(mEnterpriseConfig.toString().contains(password));
     }
+
+    /** Verifies that certificate ownership flag is set correctly */
+    @Test
+    public void testIsAppInstalledDeviceKeyAndCert() {
+        // First make sure that app didn't install anything
+        assertFalse(mEnterpriseConfig.isAppInstalledDeviceKeyAndCert());
+        assertFalse(mEnterpriseConfig.isAppInstalledCaCert());
+
+        // Then app loads keys via the enterprise config API
+        PrivateKey clientKey = FakeKeys.RSA_KEY1;
+        X509Certificate cert0 = FakeKeys.CLIENT_CERT;
+        X509Certificate cert1 = FakeKeys.CA_CERT1;
+        X509Certificate[] clientChain = new X509Certificate[] {cert0, cert1};
+        mEnterpriseConfig.setClientKeyEntryWithCertificateChain(clientKey, clientChain);
+        X509Certificate[] result = mEnterpriseConfig.getClientCertificateChain();
+        assertEquals(result.length, 2);
+        assertTrue(result[0] == cert0 && result[1] == cert1);
+        assertTrue(mEnterpriseConfig.getClientCertificate() == cert0);
+
+        // Make sure it is the owner now
+        assertTrue(mEnterpriseConfig.isAppInstalledDeviceKeyAndCert());
+        assertFalse(mEnterpriseConfig.isAppInstalledCaCert());
+    }
+
+    /** Verifies that certificate ownership flag is set correctly */
+    @Test
+    public void testIsAppInstalledCaCert() {
+        // First make sure that app didn't install anything
+        assertFalse(mEnterpriseConfig.isAppInstalledDeviceKeyAndCert());
+        assertFalse(mEnterpriseConfig.isAppInstalledCaCert());
+
+        // Then app loads CA cert via the enterprise config API
+        X509Certificate cert = FakeKeys.CA_CERT1;
+        mEnterpriseConfig.setCaCertificate(cert);
+        X509Certificate result = mEnterpriseConfig.getCaCertificate();
+        assertTrue(result == cert);
+
+        // Make sure it is the owner now
+        assertFalse(mEnterpriseConfig.isAppInstalledDeviceKeyAndCert());
+        assertTrue(mEnterpriseConfig.isAppInstalledCaCert());
+    }
+
+    /** Verifies that certificate ownership flag is set correctly */
+    @Test
+    public void testIsAppInstalledCaCerts() {
+        // First make sure that app didn't install anything
+        assertFalse(mEnterpriseConfig.isAppInstalledDeviceKeyAndCert());
+        assertFalse(mEnterpriseConfig.isAppInstalledCaCert());
+
+        // Then app loads CA cert via the enterprise config API
+        X509Certificate cert0 = FakeKeys.CA_CERT0;
+        X509Certificate cert1 = FakeKeys.CA_CERT1;
+        X509Certificate[] cert = new X509Certificate[] {cert0, cert1};
+
+        mEnterpriseConfig.setCaCertificates(cert);
+        X509Certificate[] result = mEnterpriseConfig.getCaCertificates();
+        assertEquals(result.length, 2);
+        assertTrue(result[0] == cert0 && result[1] == cert1);
+//        assertTrue(mEnterpriseConfig.getClientCertificate() == cert0);
+
+        // Make sure it is the owner now
+        assertFalse(mEnterpriseConfig.isAppInstalledDeviceKeyAndCert());
+        assertTrue(mEnterpriseConfig.isAppInstalledCaCert());
+    }
 }
diff --git a/wifi/tests/src/android/net/wifi/WifiUsabilityStatsEntryTest.java b/wifi/tests/src/android/net/wifi/WifiUsabilityStatsEntryTest.java
index 8e37113..cd60f02 100644
--- a/wifi/tests/src/android/net/wifi/WifiUsabilityStatsEntryTest.java
+++ b/wifi/tests/src/android/net/wifi/WifiUsabilityStatsEntryTest.java
@@ -74,7 +74,8 @@
 
     private static WifiUsabilityStatsEntry createResult() {
         return new WifiUsabilityStatsEntry(
-                0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22
+                0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
+                14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, true
         );
     }
 
@@ -111,5 +112,10 @@
         assertEquals(expected.getProbeMcsRateSinceLastUpdate(),
                 actual.getProbeMcsRateSinceLastUpdate());
         assertEquals(expected.getRxLinkSpeedMbps(), actual.getRxLinkSpeedMbps());
+        assertEquals(expected.getCellularDataNetworkType(), actual.getCellularDataNetworkType());
+        assertEquals(expected.getCellularSignalStrengthDbm(),
+                actual.getCellularSignalStrengthDbm());
+        assertEquals(expected.getCellularSignalStrengthDb(), actual.getCellularSignalStrengthDb());
+        assertEquals(expected.getIsSameRegisteredCell(), actual.getIsSameRegisteredCell());
     }
 }
diff --git a/wifi/tests/src/android/net/wifi/aware/WifiAwareManagerTest.java b/wifi/tests/src/android/net/wifi/aware/WifiAwareManagerTest.java
index 657a338..905540e 100644
--- a/wifi/tests/src/android/net/wifi/aware/WifiAwareManagerTest.java
+++ b/wifi/tests/src/android/net/wifi/aware/WifiAwareManagerTest.java
@@ -958,8 +958,8 @@
         WifiAwareNetworkSpecifier ns =
                 (WifiAwareNetworkSpecifier) publishSession.getValue().createNetworkSpecifierOpen(
                         peerHandle);
-        WifiAwareNetworkSpecifier nsb = new WifiAwareNetworkSpecifier.Builder().setDiscoverySession(
-                publishSession.getValue()).setPeerHandle(peerHandle).build();
+        WifiAwareNetworkSpecifier nsb = new WifiAwareNetworkSpecifier.Builder(
+                publishSession.getValue(), peerHandle).build();
 
         // validate format
         collector.checkThat("role", WifiAwareManager.WIFI_AWARE_DATA_PATH_ROLE_RESPONDER,
@@ -979,9 +979,8 @@
         // (4) request an encrypted (PMK) network specifier from the session
         ns = (WifiAwareNetworkSpecifier) publishSession.getValue().createNetworkSpecifierPmk(
                 peerHandle, pmk);
-        nsb = new WifiAwareNetworkSpecifier.Builder().setDiscoverySession(
-                publishSession.getValue()).setPeerHandle(peerHandle).setPmk(pmk).setPort(
-                port).setTransportProtocol(transportProtocol).build();
+        nsb = new WifiAwareNetworkSpecifier.Builder(publishSession.getValue(), peerHandle).setPmk(
+                pmk).setPort(port).setTransportProtocol(transportProtocol).build();
 
         // validate format
         collector.checkThat("role", WifiAwareManager.WIFI_AWARE_DATA_PATH_ROLE_RESPONDER,
@@ -1005,9 +1004,9 @@
                 (WifiAwareNetworkSpecifier) publishSession.getValue()
                         .createNetworkSpecifierPassphrase(
                         peerHandle, passphrase);
-        nsb = new WifiAwareNetworkSpecifier.Builder().setDiscoverySession(
-                publishSession.getValue()).setPeerHandle(peerHandle).setPskPassphrase(
-                passphrase).setPort(port).setTransportProtocol(transportProtocol).build();
+        nsb = new WifiAwareNetworkSpecifier.Builder(publishSession.getValue(),
+                peerHandle).setPskPassphrase(passphrase).setPort(port).setTransportProtocol(
+                transportProtocol).build();
 
         // validate format
         collector.checkThat("role", WifiAwareManager.WIFI_AWARE_DATA_PATH_ROLE_RESPONDER,
@@ -1255,16 +1254,15 @@
         // (3) create network specifier
         if (doPmk) {
             if (useBuilder) {
-                new WifiAwareNetworkSpecifier.Builder().setDiscoverySession(
-                        publishSession.getValue()).setPeerHandle(peerHandle).setPmk(pmk).build();
+                new WifiAwareNetworkSpecifier.Builder(publishSession.getValue(), peerHandle).setPmk(
+                        pmk).build();
             } else {
                 publishSession.getValue().createNetworkSpecifierPmk(peerHandle, pmk);
             }
         } else {
             if (useBuilder) {
-                new WifiAwareNetworkSpecifier.Builder().setDiscoverySession(
-                        publishSession.getValue()).setPeerHandle(peerHandle).setPskPassphrase(
-                        passphrase).build();
+                new WifiAwareNetworkSpecifier.Builder(publishSession.getValue(),
+                        peerHandle).setPskPassphrase(passphrase).build();
             } else {
                 publishSession.getValue().createNetworkSpecifierPassphrase(peerHandle, passphrase);
             }
@@ -1353,8 +1351,8 @@
 
         DiscoverySession publishSession = executeSessionStartup(true);
 
-        WifiAwareNetworkSpecifier nsb = new WifiAwareNetworkSpecifier.Builder().setDiscoverySession(
-                publishSession).setPeerHandle(peerHandle).setPmk(pmk).setPort(port).build();
+        WifiAwareNetworkSpecifier nsb = new WifiAwareNetworkSpecifier.Builder(publishSession,
+                peerHandle).setPmk(pmk).setPort(port).build();
     }
 
     /**
@@ -1368,8 +1366,8 @@
 
         DiscoverySession publishSession = executeSessionStartup(true);
 
-        WifiAwareNetworkSpecifier nsb = new WifiAwareNetworkSpecifier.Builder().setDiscoverySession(
-                publishSession).setPeerHandle(peerHandle).setPort(port).build();
+        WifiAwareNetworkSpecifier nsb = new WifiAwareNetworkSpecifier.Builder(publishSession,
+                peerHandle).setPort(port).build();
     }
 
     /**
@@ -1383,8 +1381,8 @@
 
         DiscoverySession subscribeSession = executeSessionStartup(false);
 
-        WifiAwareNetworkSpecifier nsb = new WifiAwareNetworkSpecifier.Builder().setDiscoverySession(
-                subscribeSession).setPeerHandle(peerHandle).setPort(port).build();
+        WifiAwareNetworkSpecifier nsb = new WifiAwareNetworkSpecifier.Builder(subscribeSession,
+                peerHandle).setPort(port).build();
     }
 
     /**
@@ -1403,27 +1401,23 @@
         DiscoverySession publishSession = executeSessionStartup(true);
 
         try {
-            WifiAwareNetworkSpecifier nsb = new WifiAwareNetworkSpecifier.Builder()
-                            .setDiscoverySession(publishSession).setPeerHandle(peerHandle)
-                            .setPmk(pmk).setTransportProtocol(tpNegative).build();
+            WifiAwareNetworkSpecifier nsb = new WifiAwareNetworkSpecifier.Builder(publishSession,
+                    peerHandle).setPmk(pmk).setTransportProtocol(tpNegative).build();
             assertTrue("No exception on negative transport protocol!", false);
         } catch (IllegalArgumentException e) {
             // nop - exception is correct!
         }
         try {
-            WifiAwareNetworkSpecifier nsb = new WifiAwareNetworkSpecifier.Builder()
-                            .setDiscoverySession(publishSession).setPeerHandle(peerHandle)
-                            .setPmk(pmk).setTransportProtocol(tpTooLarge).build();
+            WifiAwareNetworkSpecifier nsb = new WifiAwareNetworkSpecifier.Builder(publishSession,
+                    peerHandle).setPmk(pmk).setTransportProtocol(tpTooLarge).build();
             assertTrue("No exception on >255 transport protocol!", false);
         } catch (IllegalArgumentException e) {
             // nop - exception is correct!
         }
-        WifiAwareNetworkSpecifier nsb = new WifiAwareNetworkSpecifier.Builder()
-                        .setDiscoverySession(publishSession).setPeerHandle(peerHandle)
-                        .setPmk(pmk).setTransportProtocol(tpSmallest).build();
-        nsb = new WifiAwareNetworkSpecifier.Builder().setDiscoverySession(
-                publishSession).setPeerHandle(peerHandle).setPmk(pmk).setTransportProtocol(
-                tpLargest).build();
+        WifiAwareNetworkSpecifier nsb = new WifiAwareNetworkSpecifier.Builder(publishSession,
+                peerHandle).setPmk(pmk).setTransportProtocol(tpSmallest).build();
+        nsb = new WifiAwareNetworkSpecifier.Builder(publishSession, peerHandle).setPmk(
+                pmk).setTransportProtocol(tpLargest).build();
     }
 
     /**
@@ -1437,9 +1431,8 @@
 
         DiscoverySession publishSession = executeSessionStartup(true);
 
-        WifiAwareNetworkSpecifier nsb = new WifiAwareNetworkSpecifier.Builder()
-                        .setDiscoverySession(publishSession).setPeerHandle(peerHandle)
-                        .setTransportProtocol(transportProtocol).build();
+        WifiAwareNetworkSpecifier nsb = new WifiAwareNetworkSpecifier.Builder(publishSession,
+                peerHandle).setTransportProtocol(transportProtocol).build();
     }
 
     /**
@@ -1453,9 +1446,8 @@
 
         DiscoverySession subscribeSession = executeSessionStartup(false);
 
-        WifiAwareNetworkSpecifier nsb = new WifiAwareNetworkSpecifier.Builder()
-                        .setDiscoverySession(subscribeSession).setPeerHandle(peerHandle)
-                        .setTransportProtocol(transportProtocol).build();
+        WifiAwareNetworkSpecifier nsb = new WifiAwareNetworkSpecifier.Builder(subscribeSession,
+                peerHandle).setTransportProtocol(transportProtocol).build();
     }
 
     /*