Merge "Foldables: Implement emulation for folded screen"
diff --git a/Android.bp b/Android.bp
index 9584767..d89b501 100644
--- a/Android.bp
+++ b/Android.bp
@@ -49,9 +49,8 @@
         "rs/java/**/*.java",
 
         ":framework-javastream-protos",
-        // TODO: Resolve circular library dependency and remove media1-srcs and mediasession2-srcs
+        // TODO: Resolve circular library dependency and remove media1-srcs
         ":media1-srcs",
-        ":mediasession2-srcs",
 
         "core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl",
         "core/java/android/accessibilityservice/IAccessibilityServiceClient.aidl",
@@ -562,6 +561,7 @@
         "telephony/java/android/telephony/mbms/vendor/IMbmsStreamingService.aidl",
         "telephony/java/android/telephony/mbms/vendor/IMbmsGroupCallService.aidl",
         "telephony/java/android/telephony/ICellInfoCallback.aidl",
+        "telephony/java/android/telephony/IFinancialSmsCallback.aidl",
         "telephony/java/android/telephony/INetworkService.aidl",
         "telephony/java/android/telephony/INetworkServiceCallback.aidl",
         "telephony/java/com/android/ims/internal/IImsCallSession.aidl",
@@ -827,19 +827,6 @@
 }
 
 // A temporary build target that is conditionally included on the bootclasspath if
-// org.apache.http.legacy library has been removed and which provides support for
-// maintaining backwards compatibility for APKs that target pre-P and depend on
-// org.apache.http.legacy classes. This is used iff REMOVE_OAHL_FROM_BCP=true is
-// specified on the build command line.
-java_library {
-    name: "framework-oahl-backward-compatibility",
-    installable: true,
-    srcs: [
-        "core/java/android/content/pm/OrgApacheHttpLegacyUpdater.java",
-    ],
-}
-
-// A temporary build target that is conditionally included on the bootclasspath if
 // android.test.base library has been removed and which provides support for
 // maintaining backwards compatibility for APKs that target pre-P and depend on
 // android.test.base classes. This is used iff REMOVE_ATB_FROM_BCP=true is
@@ -920,6 +907,31 @@
     api_dir: "aidl/networkstack",
 }
 
+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",
+        "core/java/android/net/DhcpResults.java",
+        "core/java/android/util/LocalLog.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",
+        "core/java/com/android/internal/util/MessageUtils.java",
+        "core/java/com/android/internal/util/Preconditions.java",
+        "core/java/com/android/internal/util/RingBufferIndices.java",
+        "core/java/com/android/internal/util/State.java",
+        "core/java/com/android/internal/util/StateMachine.java",
+        "core/java/com/android/internal/util/WakeupMessage.java",
+        "core/java/android/net/shared/*.java",
+    ]
+}
+
 // Build ext.jar
 // ============================================================
 java_library {
diff --git a/api/current.txt b/api/current.txt
index 8ad59ff..d431e39 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -3802,6 +3802,7 @@
     method @Deprecated public void onStateNotSaved();
     method @CallSuper protected void onStop();
     method protected void onTitleChanged(CharSequence, int);
+    method public void onTopResumedActivityChanged(boolean);
     method public boolean onTouchEvent(android.view.MotionEvent);
     method public boolean onTrackballEvent(android.view.MotionEvent);
     method public void onTrimMemory(int);
@@ -5776,6 +5777,7 @@
     method public String addAutomaticZenRule(android.app.AutomaticZenRule);
     method public boolean areBubblesAllowed();
     method public boolean areNotificationsEnabled();
+    method public boolean areNotificationsPaused();
     method public boolean canNotifyAsPackage(String);
     method public void cancel(int);
     method public void cancel(String, int);
@@ -14167,6 +14169,7 @@
     ctor public ImageFormat();
     method public static int getBitsPerPixel(int);
     field public static final int DEPTH16 = 1144402265; // 0x44363159
+    field public static final int DEPTH_JPEG = 1768253795; // 0x69656963
     field public static final int DEPTH_POINT_CLOUD = 257; // 0x101
     field public static final int FLEX_RGBA_8888 = 42; // 0x2a
     field public static final int FLEX_RGB_888 = 41; // 0x29
@@ -16171,6 +16174,7 @@
     method public long getUsage();
     method public int getWidth();
     method public boolean isClosed();
+    method public static boolean isSupported(int, int, int, int, long);
     method public void writeToParcel(android.os.Parcel, int);
     field public static final int BLOB = 33; // 0x21
     field public static final android.os.Parcelable.Creator<android.hardware.HardwareBuffer> CREATOR;
@@ -23523,6 +23527,8 @@
     method public int setBufferSizeInFrames(int);
     method public int setLoopPoints(int, int, int);
     method public int setNotificationMarkerPosition(int);
+    method public void setOffloadDelayPadding(int, int);
+    method public void setOffloadEndOfStream();
     method public int setPlaybackHeadPosition(int);
     method public void setPlaybackParams(@NonNull android.media.PlaybackParams);
     method public void setPlaybackPositionUpdateListener(android.media.AudioTrack.OnPlaybackPositionUpdateListener);
@@ -25151,6 +25157,8 @@
     field public static final int METADATA_KEY_DATE = 5; // 0x5
     field public static final int METADATA_KEY_DISC_NUMBER = 14; // 0xe
     field public static final int METADATA_KEY_DURATION = 9; // 0x9
+    field public static final int METADATA_KEY_EXIF_LENGTH = 34; // 0x22
+    field public static final int METADATA_KEY_EXIF_OFFSET = 33; // 0x21
     field public static final int METADATA_KEY_GENRE = 6; // 0x6
     field public static final int METADATA_KEY_HAS_AUDIO = 16; // 0x10
     field public static final int METADATA_KEY_HAS_IMAGE = 26; // 0x1a
@@ -25954,6 +25962,7 @@
     method @NonNull public abstract android.media.MediaSession2 onGetPrimarySession();
     method @Nullable public abstract android.media.MediaSession2Service.MediaNotification onUpdateNotification(@NonNull android.media.MediaSession2);
     method public final void removeSession(@NonNull android.media.MediaSession2);
+    field public static final String SERVICE_INTERFACE = "android.media.MediaSession2Service";
   }
 
   public static class MediaSession2Service.MediaNotification {
@@ -27346,6 +27355,7 @@
     method public int getRatingType();
     method @Nullable public android.app.PendingIntent getSessionActivity();
     method @NonNull public android.media.session.MediaSession.Token getSessionToken();
+    method public String getTag();
     method @NonNull public android.media.session.MediaController.TransportControls getTransportControls();
     method public void registerCallback(@NonNull android.media.session.MediaController.Callback);
     method public void registerCallback(@NonNull android.media.session.MediaController.Callback, @Nullable android.os.Handler);
@@ -27679,6 +27689,7 @@
     field public static final String TYPE_DVB_T2 = "TYPE_DVB_T2";
     field public static final String TYPE_ISDB_C = "TYPE_ISDB_C";
     field public static final String TYPE_ISDB_S = "TYPE_ISDB_S";
+    field public static final String TYPE_ISDB_S3 = "TYPE_ISDB_S3";
     field public static final String TYPE_ISDB_T = "TYPE_ISDB_T";
     field public static final String TYPE_ISDB_TB = "TYPE_ISDB_TB";
     field public static final String TYPE_NTSC = "TYPE_NTSC";
@@ -30585,6 +30596,7 @@
   }
 
   public final class NfcAdapter {
+    method public boolean deviceSupportsNfcSecure();
     method public void disableForegroundDispatch(android.app.Activity);
     method @Deprecated public void disableForegroundNdefPush(android.app.Activity);
     method public void disableReaderMode(android.app.Activity);
@@ -30597,6 +30609,7 @@
     method @Deprecated public boolean invokeBeam(android.app.Activity);
     method public boolean isEnabled();
     method @Deprecated public boolean isNdefPushEnabled();
+    method public boolean isNfcSecureEnabled();
     method @Deprecated public void setBeamPushUris(android.net.Uri[], android.app.Activity);
     method @Deprecated public void setBeamPushUrisCallback(android.nfc.NfcAdapter.CreateBeamUrisCallback, android.app.Activity);
     method @Deprecated public void setNdefPushMessage(android.nfc.NdefMessage, android.app.Activity, android.app.Activity...);
@@ -34406,8 +34419,12 @@
   }
 
   public abstract class FileObserver {
-    ctor public FileObserver(String);
-    ctor public FileObserver(String, int);
+    ctor @Deprecated public FileObserver(String);
+    ctor public FileObserver(@NonNull java.io.File);
+    ctor public FileObserver(@NonNull java.util.List<java.io.File>);
+    ctor @Deprecated public FileObserver(String, int);
+    ctor public FileObserver(@NonNull java.io.File, int);
+    ctor public FileObserver(@NonNull java.util.List<java.io.File>, int);
     method protected void finalize();
     method public abstract void onEvent(int, @Nullable String);
     method public void startWatching();
@@ -38643,6 +38660,7 @@
     field public static final String ACTION_NOTIFICATION_POLICY_ACCESS_SETTINGS = "android.settings.NOTIFICATION_POLICY_ACCESS_SETTINGS";
     field public static final String ACTION_PRINT_SETTINGS = "android.settings.ACTION_PRINT_SETTINGS";
     field public static final String ACTION_PRIVACY_SETTINGS = "android.settings.PRIVACY_SETTINGS";
+    field public static final String ACTION_PROCESS_WIFI_EASY_CONNECT_QR_CODE = "android.settings.PROCESS_WIFI_EASY_CONNECT_QR_CODE";
     field public static final String ACTION_QUICK_LAUNCH_SETTINGS = "android.settings.QUICK_LAUNCH_SETTINGS";
     field public static final String ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS = "android.settings.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS";
     field public static final String ACTION_REQUEST_SET_AUTOFILL_SERVICE = "android.settings.REQUEST_SET_AUTOFILL_SERVICE";
@@ -38676,6 +38694,7 @@
     field public static final String EXTRA_DO_NOT_DISTURB_MODE_ENABLED = "android.settings.extra.do_not_disturb_mode_enabled";
     field public static final String EXTRA_DO_NOT_DISTURB_MODE_MINUTES = "android.settings.extra.do_not_disturb_mode_minutes";
     field public static final String EXTRA_INPUT_METHOD_ID = "input_method_id";
+    field public static final String EXTRA_QR_CODE = "android.provider.extra.QR_CODE";
     field public static final String EXTRA_SUB_ID = "android.provider.extra.SUB_ID";
     field public static final String INTENT_CATEGORY_USAGE_ACCESS_CONFIG = "android.intent.category.USAGE_ACCESS_CONFIG";
     field public static final String METADATA_USAGE_ACCESS_REASON = "android.settings.metadata.USAGE_ACCESS_REASON";
@@ -41406,9 +41425,9 @@
     method public int getUser();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.service.notification.Adjustment> CREATOR;
+    field public static final String KEY_CONTEXTUAL_ACTIONS = "key_contextual_actions";
     field public static final String KEY_IMPORTANCE = "key_importance";
-    field public static final String KEY_SMART_ACTIONS = "key_smart_actions";
-    field public static final String KEY_SMART_REPLIES = "key_smart_replies";
+    field public static final String KEY_TEXT_REPLIES = "key_text_replies";
     field public static final String KEY_USER_SENTIMENT = "key_user_sentiment";
   }
 
@@ -44670,6 +44689,7 @@
     method public static android.telephony.SmsManager getDefault();
     method public static int getDefaultSmsSubscriptionId();
     method public static android.telephony.SmsManager getSmsManagerForSubscriptionId(int);
+    method @RequiresPermission(android.Manifest.permission.SMS_FINANCIAL_TRANSACTIONS) public void getSmsMessagesForFinancialApp(android.os.Bundle, @NonNull java.util.concurrent.Executor, @NonNull android.telephony.SmsManager.FinancialSmsCallback);
     method public int getSubscriptionId();
     method public void injectSmsPdu(byte[], String, android.app.PendingIntent);
     method public void sendDataMessage(String, String, short, byte[], android.app.PendingIntent, android.app.PendingIntent);
@@ -44732,6 +44752,11 @@
     field public static final int STATUS_ON_ICC_UNSENT = 7; // 0x7
   }
 
+  public abstract static class SmsManager.FinancialSmsCallback {
+    ctor public SmsManager.FinancialSmsCallback();
+    method public abstract void onFinancialSmsMessages(android.database.CursorWindow);
+  }
+
   public class SmsMessage {
     method public static int[] calculateLength(CharSequence, boolean);
     method public static int[] calculateLength(String, boolean);
@@ -45001,6 +45026,7 @@
     method @Deprecated public void setVoicemailVibrationEnabled(android.telecom.PhoneAccountHandle, boolean);
     method public boolean updateAvailableNetworks(java.util.List<android.telephony.AvailableNetworkInfo>);
     field public static final String ACTION_CONFIGURE_VOICEMAIL = "android.telephony.action.CONFIGURE_VOICEMAIL";
+    field public static final String ACTION_NETWORK_COUNTRY_CHANGED = "android.telephony.action.NETWORK_COUNTRY_CHANGED";
     field @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public static final String ACTION_PHONE_STATE_CHANGED = "android.intent.action.PHONE_STATE";
     field public static final String ACTION_RESPOND_VIA_MESSAGE = "android.intent.action.RESPOND_VIA_MESSAGE";
     field public static final String ACTION_SECRET_CODE = "android.telephony.action.SECRET_CODE";
@@ -45039,6 +45065,7 @@
     field 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";
     field public static final String EXTRA_NOTIFICATION_COUNT = "android.telephony.extra.NOTIFICATION_COUNT";
     field public static final String EXTRA_PHONE_ACCOUNT_HANDLE = "android.telephony.extra.PHONE_ACCOUNT_HANDLE";
     field public static final String EXTRA_PRECISE_CARRIER_ID = "android.telephony.extra.PRECISE_CARRIER_ID";
@@ -55934,10 +55961,10 @@
     method @NonNull public android.widget.Magnifier.Builder setCornerRadius(@Px @FloatRange(from=0) float);
     method @NonNull public android.widget.Magnifier.Builder setDefaultSourceToMagnifierOffset(@Px int, @Px int);
     method @NonNull public android.widget.Magnifier.Builder setElevation(@Px @FloatRange(from=0) float);
+    method @NonNull public android.widget.Magnifier.Builder setInitialZoom(@FloatRange(from=0.0f) float);
     method @NonNull public android.widget.Magnifier.Builder setOverlay(@Nullable android.graphics.drawable.Drawable);
     method @NonNull public android.widget.Magnifier.Builder setSize(@Px @IntRange(from=0) int, @Px @IntRange(from=0) int);
     method @NonNull public android.widget.Magnifier.Builder setSourceBounds(int, int, int, int);
-    method @NonNull public android.widget.Magnifier.Builder setZoom(@FloatRange(from=0.0f) float);
   }
 
   public class MediaController extends android.widget.FrameLayout {
diff --git a/api/system-current.txt b/api/system-current.txt
index e5ae9a7..f405eaf 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -1267,6 +1267,7 @@
     field public static final String CONTEXTHUB_SERVICE = "contexthub";
     field public static final String EUICC_CARD_SERVICE = "euicc_card";
     field public static final String HDMI_CONTROL_SERVICE = "hdmi_control";
+    field public static final String NETD_SERVICE = "netd";
     field public static final String NETWORK_SCORE_SERVICE = "network_score";
     field public static final String OEM_LOCK_SERVICE = "oem_lock";
     field public static final String PERMISSION_SERVICE = "permission";
@@ -1699,12 +1700,14 @@
     method public int describeContents();
     method public java.util.List<android.content.rollback.PackageRollbackInfo> getPackages();
     method public int getRollbackId();
+    method public int getSessionId();
+    method public boolean isStaged();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.content.rollback.RollbackInfo> CREATOR;
   }
 
   public final class RollbackManager {
-    method @RequiresPermission(android.Manifest.permission.MANAGE_ROLLBACKS) public void commitRollback(@NonNull android.content.rollback.RollbackInfo, @NonNull android.content.IntentSender);
+    method @RequiresPermission(android.Manifest.permission.MANAGE_ROLLBACKS) public void commitRollback(int, @NonNull android.content.IntentSender);
     method @RequiresPermission(android.Manifest.permission.MANAGE_ROLLBACKS) public void expireRollbackForPackage(@NonNull String);
     method @RequiresPermission(android.Manifest.permission.MANAGE_ROLLBACKS) 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();
@@ -3618,6 +3621,10 @@
     method public void unregisterCallback(@NonNull android.media.session.ControllerCallbackLink);
   }
 
+  public static final class MediaController.PlaybackInfo implements android.os.Parcelable {
+    ctor public MediaController.PlaybackInfo(int, int, int, int, android.media.AudioAttributes);
+  }
+
   public abstract static class MediaSession.Callback {
     method public void onSetMediaButtonEventDelegate(@NonNull android.media.session.MediaSessionEngine.MediaButtonEventDelegate);
   }
@@ -4102,25 +4109,10 @@
     method @RequiresPermission(android.Manifest.permission.MANAGE_IPSEC_TUNNELS) public void removeAddress(@NonNull java.net.InetAddress, int) throws java.io.IOException;
   }
 
-  public final class IpSecTransform implements java.lang.AutoCloseable {
-    method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_IPSEC_TUNNELS, "android.permission.PACKET_KEEPALIVE_OFFLOAD"}) public void startNattKeepalive(@NonNull android.net.IpSecTransform.NattKeepaliveCallback, int, @NonNull android.os.Handler) throws java.io.IOException;
-    method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_IPSEC_TUNNELS, "android.permission.PACKET_KEEPALIVE_OFFLOAD"}) public void stopNattKeepalive();
-  }
-
   public static class IpSecTransform.Builder {
     method @NonNull @RequiresPermission(android.Manifest.permission.MANAGE_IPSEC_TUNNELS) public android.net.IpSecTransform buildTunnelModeTransform(@NonNull java.net.InetAddress, @NonNull android.net.IpSecManager.SecurityParameterIndex) throws java.io.IOException, android.net.IpSecManager.ResourceUnavailableException, android.net.IpSecManager.SpiUnavailableException;
   }
 
-  public static class IpSecTransform.NattKeepaliveCallback {
-    ctor public IpSecTransform.NattKeepaliveCallback();
-    method public void onError(int);
-    method public void onStarted();
-    method public void onStopped();
-    field public static final int ERROR_HARDWARE_ERROR = 3; // 0x3
-    field public static final int ERROR_HARDWARE_UNSUPPORTED = 2; // 0x2
-    field public static final int ERROR_INVALID_NETWORK = 1; // 0x1
-  }
-
   public class LinkAddress implements android.os.Parcelable {
     ctor public LinkAddress(java.net.InetAddress, int, int, int);
     ctor public LinkAddress(java.net.InetAddress, int);
@@ -4250,10 +4242,31 @@
     field public final android.net.RssiCurve rssiCurve;
   }
 
+  public final class StaticIpConfiguration implements android.os.Parcelable {
+    ctor public StaticIpConfiguration();
+    ctor public StaticIpConfiguration(android.net.StaticIpConfiguration);
+    method public void addDnsServer(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 public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.net.StaticIpConfiguration> CREATOR;
+  }
+
   public class TrafficStats {
     method public static void setThreadStatsTagApp();
     method public static void setThreadStatsTagBackup();
     method public static void setThreadStatsTagRestore();
+    field public static final int TAG_SYSTEM_DHCP = -192; // 0xffffff40
+    field public static final int TAG_SYSTEM_DHCP_SERVER = -186; // 0xffffff46
+    field public static final int TAG_SYSTEM_PROBE = -190; // 0xffffff42
   }
 
   public class VpnService extends android.app.Service {
@@ -4275,6 +4288,49 @@
 
 }
 
+package android.net.apf {
+
+  public class ApfCapabilities {
+    ctor public ApfCapabilities(int, int, int);
+    method public boolean getApfDrop8023Frames(android.content.Context);
+    method public int[] getApfEthTypeBlackList(android.content.Context);
+    method public boolean hasDataAccess();
+    field public final int apfPacketFormat;
+    field public final int apfVersionSupported;
+    field public final int maximumApfProgramSize;
+  }
+
+}
+
+package android.net.captiveportal {
+
+  public final class CaptivePortalProbeResult {
+    ctor public CaptivePortalProbeResult(int);
+    ctor public CaptivePortalProbeResult(int, String, String);
+    ctor public CaptivePortalProbeResult(int, String, String, android.net.captiveportal.CaptivePortalProbeSpec);
+    method public boolean isFailed();
+    method public boolean isPortal();
+    method public boolean isSuccessful();
+    field public static final android.net.captiveportal.CaptivePortalProbeResult FAILED;
+    field public static final int FAILED_CODE = 599; // 0x257
+    field public static final int PORTAL_CODE = 302; // 0x12e
+    field 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 android.net.captiveportal.CaptivePortalProbeSpec probeSpec;
+    field 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 @Nullable public static android.net.captiveportal.CaptivePortalProbeSpec parseSpecOrNull(@Nullable String);
+  }
+
+}
+
 package android.net.metrics {
 
   public final class ApfProgramEvent implements android.net.metrics.IpConnectivityLog.Event {
@@ -4435,6 +4491,7 @@
 
   public class SocketUtils {
     method public static void bindSocketToInterface(java.io.FileDescriptor, String) throws android.system.ErrnoException;
+    method public static void closeSocket(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, byte[]);
@@ -5031,6 +5088,7 @@
     method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean enableNdefPush();
     method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean removeNfcUnlockHandler(android.nfc.NfcAdapter.NfcUnlockHandler);
     method public void setNdefPushMessage(android.nfc.NdefMessage, android.app.Activity, int);
+    method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean setNfcSecure(boolean);
     field public static final int FLAG_NDEF_PUSH_NO_CONFIRM = 1; // 0x1
   }
 
@@ -5061,6 +5119,36 @@
     method public Object onTransactStarted(android.os.IBinder, int);
   }
 
+  public class BugreportManager {
+    method @RequiresPermission(android.Manifest.permission.DUMP) public void cancelBugreport();
+    method @RequiresPermission(android.Manifest.permission.DUMP) public void startBugreport(@NonNull android.os.ParcelFileDescriptor, @Nullable android.os.ParcelFileDescriptor, @NonNull android.os.BugreportParams, @NonNull java.util.concurrent.Executor, @NonNull android.os.BugreportManager.BugreportCallback);
+  }
+
+  public abstract static class BugreportManager.BugreportCallback {
+    ctor public BugreportManager.BugreportCallback();
+    method public void onError(int);
+    method public void onFinished();
+    method public void onProgress(float);
+    field public static final int BUGREPORT_ERROR_INVALID_INPUT = 1; // 0x1
+    field public static final int BUGREPORT_ERROR_RUNTIME = 2; // 0x2
+    field public static final int BUGREPORT_ERROR_USER_CONSENT_TIMED_OUT = 4; // 0x4
+    field public static final int BUGREPORT_ERROR_USER_DENIED_CONSENT = 3; // 0x3
+  }
+
+  public final class BugreportParams {
+    ctor public BugreportParams(@android.os.BugreportParams.BugreportMode int);
+    method public int getMode();
+    field public static final int BUGREPORT_MODE_FULL = 0; // 0x0
+    field public static final int BUGREPORT_MODE_INTERACTIVE = 1; // 0x1
+    field public static final int BUGREPORT_MODE_REMOTE = 2; // 0x2
+    field public static final int BUGREPORT_MODE_TELEPHONY = 4; // 0x4
+    field public static final int BUGREPORT_MODE_WEAR = 3; // 0x3
+    field public static final int BUGREPORT_MODE_WIFI = 5; // 0x5
+  }
+
+  @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) @IntDef(prefix={"BUGREPORT_MODE_"}, value={android.os.BugreportParams.BUGREPORT_MODE_FULL, android.os.BugreportParams.BUGREPORT_MODE_INTERACTIVE, android.os.BugreportParams.BUGREPORT_MODE_REMOTE, android.os.BugreportParams.BUGREPORT_MODE_WEAR, android.os.BugreportParams.BUGREPORT_MODE_TELEPHONY, android.os.BugreportParams.BUGREPORT_MODE_WIFI}) public static @interface BugreportParams.BugreportMode {
+  }
+
   public static class Build.VERSION {
     field public static final String PREVIEW_SDK_FINGERPRINT;
   }
@@ -5666,6 +5754,12 @@
     field public static final String NAMESPACE = "activity_manager";
   }
 
+  public static interface DeviceConfig.AttentionManagerService {
+    field public static final String NAMESPACE = "attention_manager_service";
+    field public static final String PROPERTY_COMPONENT_NAME = "component_name";
+    field public static final String PROPERTY_SERVICE_ENABLED = "service_enabled";
+  }
+
   public static interface DeviceConfig.FsiBoot {
     field public static final String NAMESPACE = "fsi_boot";
     field public static final String OOB_ENABLED = "oob_enabled";
@@ -5674,8 +5768,8 @@
 
   public static interface DeviceConfig.IntelligenceAttention {
     field public static final String NAMESPACE = "intelligence_attention";
-    field public static final String PROPERTY_ATTENTION_CHECK_ENABLED = "attention_check_enabled";
-    field public static final String PROPERTY_ATTENTION_CHECK_SETTINGS = "attention_check_settings";
+    field public static final String PROPERTY_ATTENTION_ENABLED = "attention_enabled";
+    field public static final String PROPERTY_ATTENTION_SETTINGS = "attention_settings";
   }
 
   public static interface DeviceConfig.OnPropertyChangedListener {
@@ -7444,7 +7538,7 @@
   }
 
   public class PhoneStateListener {
-    method public void onCallAttributesChanged(android.telephony.CallAttributes);
+    method public void onCallAttributesChanged(@NonNull android.telephony.CallAttributes);
     method public void onCallDisconnectCauseChanged(int, int);
     method public void onPreciseCallStateChanged(android.telephony.PreciseCallState);
     method public void onPreciseDataConnectionStateChanged(android.telephony.PreciseDataConnectionState);
@@ -7850,7 +7944,7 @@
 package android.telephony.data {
 
   public final class DataCallResponse implements android.os.Parcelable {
-    ctor public DataCallResponse(int, int, int, int, @Nullable String, @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);
+    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);
     ctor public DataCallResponse(android.os.Parcel);
     method public int describeContents();
     method public int getActive();
@@ -7861,9 +7955,9 @@
     method @NonNull public String getIfname();
     method public int getMtu();
     method @NonNull public java.util.List<java.lang.String> getPcscfs();
+    method public int getProtocolType();
     method public int getStatus();
     method public int getSuggestedRetryTime();
-    method @NonNull public String getType();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.telephony.data.DataCallResponse> CREATOR;
   }
@@ -7877,8 +7971,8 @@
     method public int getMtu();
     method public String getPassword();
     method public int getProfileId();
-    method public String getProtocol();
-    method public String getRoamingProtocol();
+    method public int getProtocol();
+    method public int getRoamingProtocol();
     method public int getSupportedApnTypesBitmap();
     method public int getType();
     method public String getUserName();
diff --git a/api/test-current.txt b/api/test-current.txt
index ae29e49..2295a21 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -516,6 +516,7 @@
 
   public final class Bitmap implements android.os.Parcelable {
     method public void eraseColor(@ColorLong long);
+    method public void setColorSpace(@NonNull android.graphics.ColorSpace);
   }
 
   public final class ImageDecoder implements java.lang.AutoCloseable {
@@ -867,11 +868,75 @@
     field public static final int RTN_UNREACHABLE = 7; // 0x7
   }
 
+  public final class StaticIpConfiguration implements android.os.Parcelable {
+    ctor public StaticIpConfiguration();
+    ctor public StaticIpConfiguration(android.net.StaticIpConfiguration);
+    method public void addDnsServer(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 public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.net.StaticIpConfiguration> CREATOR;
+  }
+
   public class TrafficStats {
     method public static long getLoopbackRxBytes();
     method public static long getLoopbackRxPackets();
     method public static long getLoopbackTxBytes();
     method public static long getLoopbackTxPackets();
+    field public static final int TAG_SYSTEM_DHCP = -192; // 0xffffff40
+    field public static final int TAG_SYSTEM_DHCP_SERVER = -186; // 0xffffff46
+    field public static final int TAG_SYSTEM_PROBE = -190; // 0xffffff42
+  }
+
+}
+
+package android.net.apf {
+
+  public class ApfCapabilities {
+    ctor public ApfCapabilities(int, int, int);
+    method public boolean getApfDrop8023Frames(android.content.Context);
+    method public int[] getApfEthTypeBlackList(android.content.Context);
+    method public boolean hasDataAccess();
+    field public final int apfPacketFormat;
+    field public final int apfVersionSupported;
+    field public final int maximumApfProgramSize;
+  }
+
+}
+
+package android.net.captiveportal {
+
+  public final class CaptivePortalProbeResult {
+    ctor public CaptivePortalProbeResult(int);
+    ctor public CaptivePortalProbeResult(int, String, String);
+    ctor public CaptivePortalProbeResult(int, String, String, android.net.captiveportal.CaptivePortalProbeSpec);
+    method public boolean isFailed();
+    method public boolean isPortal();
+    method public boolean isSuccessful();
+    field public static final android.net.captiveportal.CaptivePortalProbeResult FAILED;
+    field public static final int FAILED_CODE = 599; // 0x257
+    field public static final int PORTAL_CODE = 302; // 0x12e
+    field 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 android.net.captiveportal.CaptivePortalProbeSpec probeSpec;
+    field 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 @Nullable public static android.net.captiveportal.CaptivePortalProbeSpec parseSpecOrNull(@Nullable String);
   }
 
 }
@@ -1032,6 +1097,18 @@
 
 }
 
+package android.net.util {
+
+  public class SocketUtils {
+    method public static void bindSocketToInterface(java.io.FileDescriptor, String) throws android.system.ErrnoException;
+    method public static void closeSocket(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, byte[]);
+  }
+
+}
+
 package android.os {
 
   public class Build {
diff --git a/cmds/statsd/OWNERS b/cmds/statsd/OWNERS
index 1315750..deebd4e 100644
--- a/cmds/statsd/OWNERS
+++ b/cmds/statsd/OWNERS
@@ -1,6 +1,7 @@
 bookatz@google.com
 cjyu@google.com
 dwchen@google.com
+gaillard@google.com
 jinyithu@google.com
 joeo@google.com
 kwekua@google.com
diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto
index c1e319f..812a2f2 100644
--- a/cmds/statsd/src/atoms.proto
+++ b/cmds/statsd/src/atoms.proto
@@ -24,15 +24,18 @@
 import "frameworks/base/core/proto/android/app/enums.proto";
 import "frameworks/base/core/proto/android/app/settings_enums.proto";
 import "frameworks/base/core/proto/android/app/job/enums.proto";
+import "frameworks/base/core/proto/android/bluetooth/a2dp/enums.proto";
 import "frameworks/base/core/proto/android/bluetooth/enums.proto";
 import "frameworks/base/core/proto/android/bluetooth/hci/enums.proto";
 import "frameworks/base/core/proto/android/bluetooth/hfp/enums.proto";
+import "frameworks/base/core/proto/android/bluetooth/smp/enums.proto";
 import "frameworks/base/core/proto/android/debug/enums.proto";
 import "frameworks/base/core/proto/android/hardware/biometrics/enums.proto";
 import "frameworks/base/core/proto/android/net/networkcapabilities.proto";
 import "frameworks/base/core/proto/android/os/enums.proto";
 import "frameworks/base/core/proto/android/server/connectivity/data_stall_event.proto";
 import "frameworks/base/core/proto/android/server/enums.proto";
+import "frameworks/base/core/proto/android/server/job/enums.proto";
 import "frameworks/base/core/proto/android/server/location/enums.proto";
 import "frameworks/base/core/proto/android/service/procstats_enum.proto";
 import "frameworks/base/core/proto/android/service/usb.proto";
@@ -213,6 +216,24 @@
         WatchdogRollbackOccurred watchdog_rollback_occurred = 147;
         BiometricHalDeathReported biometric_hal_death_reported = 148;
         BubbleUIChanged bubble_ui_changed = 149;
+        ScheduledJobConstraintChanged scheduled_job_constraint_changed = 150;
+        BluetoothActiveDeviceChanged bluetooth_active_device_changed = 151;
+        BluetoothA2dpPlaybackStateChanged bluetooth_a2dp_playback_state_changed = 152;
+        BluetoothA2dpCodecConfigChanged bluetooth_a2dp_codec_config_changed = 153;
+        BluetoothA2dpCodecCapabilityChanged bluetooth_a2dp_codec_capability_changed = 154;
+        BluetoothA2dpAudioUnderrunReported bluetooth_a2dp_audio_underrun_reported = 155;
+        BluetoothA2dpAudioOverrunReported bluetooth_a2dp_audio_overrun_reported = 156;
+        BluetoothDeviceRssiReported bluetooth_device_rssi_reported = 157;
+        BluetoothDeviceFailedContactCounterReported bluetooth_device_failed_contact_counter_reported = 158;
+        BluetoothDeviceTxPowerLevelReported bluetooth_device_tx_power_level_reported = 159;
+        BluetoothHciTimeoutReported bluetooth_hci_timeout_reported = 160;
+        BluetoothQualityReportReported bluetooth_quality_report_reported = 161;
+        BluetoothManufacturerInfoReported bluetooth_device_info_reported = 162;
+        BluetoothRemoteVersionInfoReported bluetooth_remote_version_info_reported = 163;
+        BluetoothSdpAttributeReported bluetooth_sdp_attribute_reported = 164;
+        BluetoothBondStateChanged bluetooth_bond_state_changed = 165;
+        BluetoothClassicPairingEventReported bluetooth_classic_pairing_event_reported = 166;
+        BluetoothSmpPairingEventReported bluetooth_smp_pairing_event_reported = 167;
     }
 
     // Pulled events will start at field 10000.
@@ -1407,6 +1428,27 @@
     optional android.bluetooth.hfp.ScoCodec codec = 3;
 }
 
+/**
+ * Logged when active device of a profile changes
+ *
+ * Logged from:
+ *     packages/apps/Bluetooth/src/com/android/bluetooth/a2dp/A2dpService.java
+ *     packages/apps/Bluetooth/src/com/android/bluetooth/hfp/HeadsetService.java
+ *     packages/apps/Bluetooth/src/com/android/bluetooth/hearingaid/HearingAidService.java
+ */
+message BluetoothActiveDeviceChanged {
+    // The profile whose active device has changed. Eg. A2DP, HEADSET, HEARING_AID
+    // From android.bluetooth.BluetoothProfile
+    optional int32 bt_profile = 1;
+    // An identifier that can be used to match events for this new active device.
+    // Currently, this is a salted hash of the MAC address of this Bluetooth device.
+    // Salt: Randomly generated 256 bit value
+    // Hash algorithm: HMAC-SHA256
+    // Size: 32 byte
+    // Default: null or empty if there is no active device for this profile
+    optional bytes obfuscated_id = 2 [(android.os.statsd.log_mode) = MODE_BYTES];
+}
+
 // Logs when there is an event affecting Bluetooth device's link layer connection.
 // - This event is triggered when there is a related HCI command or event
 // - Users of this metrics can deduce Bluetooth device's connection state from these events
@@ -1509,6 +1551,516 @@
     optional int32 package_version_code = 3;
 }
 
+/**
+ * Logs when there is a change in Bluetooth A2DP playback state
+ *
+ * Logged from:
+ *     packages/apps/Bluetooth/src/com/android/bluetooth/a2dp/A2dpService.java
+ */
+message BluetoothA2dpPlaybackStateChanged {
+    // An identifier that can be used to match events for this device.
+    // Currently, this is a salted hash of the MAC address of this Bluetooth device.
+    // Salt: Randomly generated 256 bit value
+    // Hash algorithm: HMAC-SHA256
+    // Size: 32 byte
+    // Default: null or empty if the device identifier is not known
+    optional bytes obfuscated_id = 1 [(android.os.statsd.log_mode) = MODE_BYTES];
+    // Current playback state
+    // Default: PLAYBACK_STATE_UNKNOWN
+    optional android.bluetooth.a2dp.PlaybackStateEnum playback_state = 2;
+    // Current audio coding mode
+    // Default: AUDIO_CODING_MODE_UNKNOWN
+    optional android.bluetooth.a2dp.AudioCodingModeEnum audio_coding_mode = 3;
+}
+
+/**
+ * Logs when there is a change in A2DP codec config for a particular remote device
+ *
+ * Logged from:
+ *     frameworks/base/core/java/android/bluetooth/BluetoothCodecConfig.java
+ *     packages/apps/Bluetooth/src/com/android/bluetooth/a2dp/A2dpService.java
+ */
+message BluetoothA2dpCodecConfigChanged {
+    // An identifier that can be used to match events for this device.
+    // Currently, this is a salted hash of the MAC address of this Bluetooth device.
+    // Salt: Randomly generated 256 bit value
+    // Hash algorithm: HMAC-SHA256
+    // Size: 32 byte
+    // Default: null or empty if the device identifier is not known
+    optional bytes obfuscated_id = 1 [(android.os.statsd.log_mode) = MODE_BYTES];
+    // Type of codec as defined by various SOURCE_CODEC_TYPE_* constants in BluetoothCodecConfig
+    // Default SOURCE_CODEC_TYPE_INVALID
+    optional int32 codec_type = 2;
+    // Codec priroity, the higher the more preferred, -1 for disabled
+    // Default: CODEC_PRIORITY_DEFAULT
+    optional int32 codec_priority = 3;
+    // Sample rate in Hz as defined by various SAMPLE_RATE_* constants in BluetoothCodecConfig
+    // Default: SAMPLE_RATE_NONE
+    optional int32 sample_rate = 4;
+    // Bits per sample as defined by various BITS_PER_SAMPLE_* constants in BluetoothCodecConfig
+    // Default: BITS_PER_SAMPLE_NONE
+    optional int32 bits_per_sample = 5;
+    // Channel mode as defined by various CHANNEL_MODE_* constants in BluetoothCodecConfig
+    // Default: CHANNEL_MODE_NONE
+    optional int32 channel_mode = 6;
+    // Codec specific values
+    // Default 0
+    optional int64 codec_specific_1 = 7;
+    optional int64 codec_specific_2 = 8;
+    optional int64 codec_specific_3 = 9;
+    optional int64 codec_specific_4 = 10;
+}
+
+/**
+ * Logs when there is a change in selectable A2DP codec capability for a paricular remote device
+ * Each codec's capability is logged separately due to statsd restriction
+ *
+ * Logged from:
+ *     frameworks/base/core/java/android/bluetooth/BluetoothCodecConfig.java
+ *     packages/apps/Bluetooth/src/com/android/bluetooth/a2dp/A2dpService.java
+ */
+message BluetoothA2dpCodecCapabilityChanged {
+    // An identifier that can be used to match events for this device.
+    // Currently, this is a salted hash of the MAC address of this Bluetooth device.
+    // Salt: Randomly generated 256 bit value
+    // Hash algorithm: HMAC-SHA256
+    // Size: 32 byte
+    // Default: null or empty if the device identifier is not known
+    optional bytes obfuscated_id = 1 [(android.os.statsd.log_mode) = MODE_BYTES];
+    // Type of codec as defined by various SOURCE_CODEC_TYPE_* constants in BluetoothCodecConfig
+    // Default SOURCE_CODEC_TYPE_INVALID
+    optional int32 codec_type = 2;
+    // Codec priroity, the higher the more preferred, -1 for disabled
+    // Default: CODEC_PRIORITY_DEFAULT
+    optional int32 codec_priority = 3;
+    // A bit field of supported sample rates as defined by various SAMPLE_RATE_* constants
+    // in BluetoothCodecConfig
+    // Default: empty and SAMPLE_RATE_NONE for individual item
+    optional int32 sample_rate = 4;
+    // A bit field of supported bits per sample as defined by various BITS_PER_SAMPLE_* constants
+    // in BluetoothCodecConfig
+    // Default: empty and BITS_PER_SAMPLE_NONE for individual item
+    optional int32 bits_per_sample = 5;
+    // A bit field of supported channel mode as defined by various CHANNEL_MODE_* constants in
+    // BluetoothCodecConfig
+    // Default: empty and CHANNEL_MODE_NONE for individual item
+    optional int32 channel_mode = 6;
+    // Codec specific values
+    // Default 0
+    optional int64 codec_specific_1 = 7;
+    optional int64 codec_specific_2 = 8;
+    optional int64 codec_specific_3 = 9;
+    optional int64 codec_specific_4 = 10;
+}
+
+/**
+ * Logs when A2DP failed to read from PCM source.
+ * This typically happens when audio HAL cannot supply A2DP with data fast enough for encoding.
+ *
+ * Logged from:
+ *     system/bt
+ */
+message BluetoothA2dpAudioUnderrunReported {
+    // An identifier that can be used to match events for this device.
+    // Currently, this is a salted hash of the MAC address of this Bluetooth device.
+    // Salt: Randomly generated 256 bit value
+    // Hash algorithm: HMAC-SHA256
+    // Size: 32 byte
+    // Default: null or empty if the device identifier is not known
+    optional bytes obfuscated_id = 1 [(android.os.statsd.log_mode) = MODE_BYTES];
+    // Encoding interval in nanoseconds
+    // Default: 0
+    optional int64 encoding_interval_nanos = 2;
+    // Number of bytes of PCM data that could not be read from the source
+    // Default: 0
+    optional int32 num_missing_pcm_bytes = 3;
+}
+
+/**
+ * Logs when A2DP failed send encoded data to the remote device fast enough such that the transmit
+ * buffer queue is full and we have to drop data
+ *
+ * Logged from:
+ *     system/bt
+ */
+message BluetoothA2dpAudioOverrunReported {
+    // An identifier that can be used to match events for this device.
+    // Currently, this is a salted hash of the MAC address of this Bluetooth device.
+    // Salt: Randomly generated 256 bit value
+    // Hash algorithm: HMAC-SHA256
+    // Size: 32 byte
+    // Default: null or empty if the device identifier is not known
+    optional bytes obfuscated_id = 1 [(android.os.statsd.log_mode) = MODE_BYTES];
+    // Encoding interval in nanoseconds
+    // Default: 0
+    optional int64 encoding_interval_nanos = 2;
+    // Number of buffers dropped in this event
+    // Each buffer is encoded in one encoding interval and consists of multiple encoded frames
+    // Default: 0
+    optional int32 num_dropped_buffers = 3;
+    // Number of encoded buffers dropped in this event
+    // Default 0
+    optional int32 num_dropped_encoded_frames = 4;
+    // Number of encoded bytes dropped in this event
+    // Default: 0
+    optional int32 num_dropped_encoded_bytes = 5;
+}
+
+/**
+ * Logs when we receive reports regarding a device's RSSI value
+ *
+ * Logged from:
+ *     system/bt
+ */
+message BluetoothDeviceRssiReported {
+    // An identifier that can be used to match events for this device.
+    // Currently, this is a salted hash of the MAC address of this Bluetooth device.
+    // Salt: Randomly generated 256 bit value
+    // Hash algorithm: HMAC-SHA256
+    // Size: 32 byte
+    // Default: null or empty if the device identifier is not known
+    optional bytes obfuscated_id = 1 [(android.os.statsd.log_mode) = MODE_BYTES];
+    // Connection handle of this connection if available
+    // Range: 0x0000 - 0x0EFF (12 bits)
+    // Default: 0xFFFF if the handle is unknown
+    optional int32 connection_handle = 2;
+    // HCI command status code if this is triggerred by hci_cmd
+    // Default: STATUS_UNKNOWN
+    optional android.bluetooth.hci.StatusEnum hci_status = 3;
+    // BR/EDR
+    //   Range: -128 ≤ N ≤ 127 (signed integer)
+    //   Units: dB
+    // LE:
+    //   Range: -127 to 20, 127 (signed integer)
+    //   Units: dBm
+    // Invalid when an out of range value is reported
+    optional int32 rssi = 4;
+}
+
+/**
+ * Logs when we receive reports regarding how many consecutive failed contacts for a connection
+ *
+ * Logged from:
+ *     system/bt
+ */
+message BluetoothDeviceFailedContactCounterReported {
+    // An identifier that can be used to match events for this device.
+    // Currently, this is a salted hash of the MAC address of this Bluetooth device.
+    // Salt: Randomly generated 256 bit value
+    // Hash algorithm: HMAC-SHA256
+    // Size: 32 byte
+    // Default: null or empty if the device identifier is not known
+    optional bytes obfuscated_id = 1 [(android.os.statsd.log_mode) = MODE_BYTES];
+    // Connection handle of this connection if available
+    // Range: 0x0000 - 0x0EFF (12 bits)
+    // Default: 0xFFFF if the handle is unknown
+    optional int32 connection_handle = 2;
+    // HCI command status code if this is triggerred by hci_cmd
+    // Default: STATUS_UNKNOWN
+    optional android.bluetooth.hci.StatusEnum cmd_status = 3;
+    // Number of consecutive failed contacts for a connection corresponding to the Handle
+    // Range: uint16_t, 0-0xFFFF
+    // Default: 0xFFFFF
+    optional int32 failed_contact_counter = 4;
+}
+
+/**
+ * Logs when we receive reports regarding the tranmit power level used for a specific connection
+ *
+ * Logged from:
+ *     system/bt
+ */
+message BluetoothDeviceTxPowerLevelReported {
+    // An identifier that can be used to match events for this device.
+    // Currently, this is a salted hash of the MAC address of this Bluetooth device.
+    // Salt: Randomly generated 256 bit value
+    // Hash algorithm: HMAC-SHA256
+    // Size: 32 byte
+    // Default: null or empty if the device identifier is not known
+    optional bytes obfuscated_id = 1 [(android.os.statsd.log_mode) = MODE_BYTES];
+    // Connection handle of this connection if available
+    // Range: 0x0000 - 0x0EFF (12 bits)
+    // Default: 0xFFFF if the handle is unknown
+    optional int32 connection_handle = 2;
+    // HCI command status code if this is triggered by hci_cmd
+    // Default: STATUS_UNKNOWN
+    optional android.bluetooth.hci.StatusEnum hci_status = 3;
+    // Range: -30 ≤ N ≤ 20
+    // Units: dBm
+    // Invalid when an out of range value is reported
+    optional int32 transmit_power_level = 4;
+}
+
+/**
+ * Logs when Bluetooth controller failed to reply with command status within a timeout period after
+ * receiving an HCI command from the host
+ *
+ * Logged from: system/bt
+ */
+message BluetoothHciTimeoutReported {
+    // HCI command associated with this event
+    // Default: CMD_UNKNOWN
+    optional android.bluetooth.hci.CommandEnum hci_command = 1;
+}
+
+/**
+ * Logs when we receive Bluetooth Link Quality Report event from the controller
+ * See Android Bluetooth HCI specification for more details
+ *
+ * Note: all count and bytes field are counted since last event
+ *
+ * Logged from: system/bt
+ */
+message BluetoothQualityReportReported {
+    // Quality report ID
+    // Original type: uint8_t
+    // Default: BQR_ID_UNKNOWN
+    optional android.bluetooth.hci.BqrIdEnum quality_report_id = 1;
+    // Packet type of the connection
+    // Original type: uint8_t
+    // Default: BQR_PACKET_TYPE_UNKNOWN
+    optional android.bluetooth.hci.BqrPacketTypeEnum packet_types = 2;
+    // Connection handle of the connection
+    // Original type: uint16_t
+    optional int32 connection_handle = 3;
+    // Performing Role for the connection
+    // Original type: uint8_t
+    optional int32 connection_role = 4;
+    // Current Transmit Power Level for the connection. This value is the same as the controller's
+    // response to the HCI_Read_Transmit_Power_Level HCI command
+    // Original type: uint8_t
+    optional int32 tx_power_level = 5;
+    // Received Signal Strength Indication (RSSI) value for the connection. This value is an
+    // absolute receiver signal strength value
+    // Original type: int8_t
+    optional int32 rssi = 6;
+    // Signal-to-Noise Ratio (SNR) value for the connection. It is the average SNR of all the
+    // channels used by the link currently
+    // Original type: uint8_t
+    optional int32 snr = 7;
+    // Indicates the number of unused channels in AFH_channel_map
+    // Original type: uint8_t
+    optional int32 unused_afh_channel_count = 8;
+    // Indicates the number of the channels which are interfered and quality is bad but are still
+    // selected for AFH
+    // Original type: uint8_t
+    optional int32 afh_select_unideal_channel_count = 9;
+    // Current Link Supervision Timeout Setting
+    // Unit: N * 0.3125 ms (1 Bluetooth Clock)
+    // Original type: uint16_t
+    optional int32 lsto = 10;
+    // Piconet Clock for the specified Connection_Handle. This value is the same as the controller's
+    // response to HCI_Read_Clock HCI command with the parameter "Which_Clock" of
+    // 0x01 (Piconet Clock)
+    // Unit: N * 0.3125 ms (1 Bluetooth Clock)
+    // Original type: uint32_t
+    optional int64 connection_piconet_clock = 11;
+    // The count of retransmission
+    // Original type: uint32_t
+    optional int64 retransmission_count = 12;
+    // The count of no RX
+    // Original type: uint32_t
+    optional int64 no_rx_count = 13;
+    // The count of NAK (Negative Acknowledge)
+    // Original type: uint32_t
+    optional int64 nak_count = 14;
+    // Controller timestamp of last TX ACK
+    // Unit: N * 0.3125 ms (1 Bluetooth Clock)
+    // Original type: uint32_t
+    optional int64 last_tx_ack_timestamp = 15;
+    // The count of Flow-off (STOP)
+    // Original type: uint32_t
+    optional int64 flow_off_count = 16;
+    // Controller timestamp of last Flow-on (GO)
+    // Unit: N * 0.3125 ms (1 Bluetooth Clock)
+    // Original type: uint32_t
+    optional int64 last_flow_on_timestamp = 17;
+    // Buffer overflow count (how many bytes of TX data are dropped) since the last event
+    // Original type: uint32_t
+    optional int64 buffer_overflow_bytes = 18;
+    // Buffer underflow count (in byte) since last event
+    // Original type: uint32_t
+    optional int64 buffer_underflow_bytes = 19;
+}
+
+/**
+ * Logs when a Bluetooth device's manufacturer information is learnt by the Bluetooth stack
+ *
+ * Notes:
+ * - Each event can be partially filled as we might learn different pieces of device
+ *   information at different time
+ * - Multiple device info events can be combined to give more complete picture
+ * - When multiple device info events tries to describe the same information, the
+ *   later one wins
+ *
+ * Logged from:
+ *     packages/apps/Bluetooth
+ */
+message BluetoothManufacturerInfoReported {
+    // An identifier that can be used to match events for this device.
+    // Currently, this is a salted hash of the MAC address of this Bluetooth device.
+    // Salt: Randomly generated 256 bit value
+    // Hash algorithm: HMAC-SHA256
+    // Size: 32 byte
+    // Default: null or empty if the device identifier is not known
+    optional bytes obfuscated_id = 1 [(android.os.statsd.log_mode) = MODE_BYTES];
+    // Where is this device info obtained from
+    optional android.bluetooth.DeviceInfoSrcEnum source_type = 2;
+    // Name of the data source
+    // For EXTERNAL: package name of the data source
+    // For INTERNAL: null for general case, component name otherwise
+    optional string source_name = 3;
+    // Name of the manufacturer of this device
+    optional string manufacturer = 4;
+    // Model of this device
+    optional string model = 5;
+    // Hardware version of this device
+    optional string hardware_version = 6;
+    // Software version of this device
+    optional string software_version = 7;
+}
+
+/**
+ * Logs when we receive Bluetooth Read Remote Version Information Complete Event from the remote
+ * device, as documented by the Bluetooth Core HCI specification
+ * Reference: https://www.bluetooth.com/specifications/bluetooth-core-specification
+ * Vol 2, Part E, Page 1118
+ *
+ * Logged from:
+ *     system/bt
+ */
+message BluetoothRemoteVersionInfoReported {
+    // Connection handle of the connection
+    // Original type: uint16_t
+    optional int32 connection_handle = 1;
+    // HCI command status code
+    // Default: STATUS_UNKNOWN
+    optional android.bluetooth.hci.StatusEnum hci_status = 2;
+    // 1 byte Version of current LMP in the remote controller
+    optional int32 lmp_version = 3;
+    // 2 bytes LMP manufacturer code of the remote controller
+    // https://www.bluetooth.com/specifications/assigned-numbers/company-identifiers
+    optional int32 lmp_manufacturer_code = 4;
+    // 4 bytes subversion of the LMP in the remote controller
+    optional int32 lmp_subversion = 5;
+}
+
+/**
+ * Logs when certain Bluetooth SDP attributes are discovered
+ * Constant definitions are from:
+ *     https://www.bluetooth.com/specifications/assigned-numbers/service-discovery
+ *
+ * Current logged attributes:
+ * - BluetoothProfileDescriptorList
+ * - Supported Features Bitmask
+ *
+ * Logged from:
+ *     system/bt
+ */
+message BluetoothSdpAttributeReported {
+    // An identifier that can be used to match events for this device.
+    // Currently, this is a salted hash of the MAC address of this Bluetooth device.
+    // Salt: Randomly generated 256 bit value
+    // Hash algorithm: HMAC-SHA256
+    optional bytes obfuscated_id = 1 [(android.os.statsd.log_mode) = MODE_BYTES];
+    // Short form UUIDs used to identify Bluetooth protocols, profiles, and service classes
+    // Original type: uint16_t
+    optional int32 protocol_uuid = 2;
+    // Short form UUIDs used to identify Bluetooth SDP attribute types
+    // Original type: uint16_t
+    optional int32 attribute_id = 3;
+    // Attribute value for the particular attribute
+    optional bytes attribute_value = 4 [(android.os.statsd.log_mode) = MODE_BYTES];
+}
+
+/**
+ * Logs when bond state of a Bluetooth device changes
+ *
+ * Logged from:
+ *     frameworks/base/core/java/android/bluetooth/BluetoothDevice.java
+ *     packages/apps/Bluetooth/src/com/android/bluetooth/btservice/BondStateMachine.java
+ */
+message BluetoothBondStateChanged {
+    // An identifier that can be used to match events for this device.
+    // Currently, this is a salted hash of the MAC address of this Bluetooth device.
+    // Salt: Randomly generated 256 bit value
+    // Hash algorithm: HMAC-SHA256
+    // Size: 32 byte
+    // Default: null or empty if the device identifier is not known
+    optional bytes obfuscated_id = 1 [(android.os.statsd.log_mode) = MODE_BYTES];
+    // Preferred transport type to remote dual mode device
+    // Default: TRANSPORT_AUTO means no preference
+    optional android.bluetooth.TransportTypeEnum transport = 2;
+    // The type of this Bluetooth device (Classic, LE, or Dual mode)
+    // Default: UNKNOWN
+    optional android.bluetooth.DeviceTypeEnum type = 3;
+    // Current bond state (NONE, BONDING, BONDED)
+    // Default: BOND_STATE_UNKNOWN
+    optional android.bluetooth.BondStateEnum bond_state = 4;
+    // Bonding sub state
+    // Default: BOND_SUB_STATE_UNKNOWN
+    optional android.bluetooth.BondSubStateEnum bonding_sub_state = 5;
+    // Unbond Reason
+    // Default: UNBOND_REASON_UNKNOWN
+    optional android.bluetooth.UnbondReasonEnum unbond_reason = 6;
+}
+
+/**
+ * Logs there is an event related Bluetooth classic pairing
+ *
+ * Logged from:
+ *     system/bt
+ */
+message BluetoothClassicPairingEventReported {
+    // An identifier that can be used to match events for this device.
+    // Currently, this is a salted hash of the MAC address of this Bluetooth device.
+    // Salt: Randomly generated 256 bit value
+    // Hash algorithm: HMAC-SHA256
+    // Size: 32 byte
+    // Default: null or empty if the device identifier is not known
+    optional bytes obfuscated_id = 1 [(android.os.statsd.log_mode) = MODE_BYTES];
+    // Connection handle of this connection if available
+    // Range: 0x0000 - 0x0EFF (12 bits)
+    // Default: 0xFFFF if the handle is unknown
+    optional int32 connection_handle = 2;
+    // HCI command associated with this event
+    // Default: CMD_UNKNOWN
+    optional android.bluetooth.hci.CommandEnum hci_cmd = 3;
+    // HCI event associated with this event
+    // Default: EVT_UNKNOWN
+    optional android.bluetooth.hci.EventEnum hci_event = 4;
+    // HCI command status code if this is triggerred by hci_cmd
+    // Default: STATUS_UNKNOWN
+    optional android.bluetooth.hci.StatusEnum cmd_status = 5;
+    // HCI reason code associated with this event
+    // Default: STATUS_UNKNOWN
+    optional android.bluetooth.hci.StatusEnum reason_code = 6;
+}
+
+/**
+ * Logs when there is an event related to Bluetooth Security Manager Protocol (SMP)
+ *
+ * Logged from:
+ *     system/bt
+ */
+message BluetoothSmpPairingEventReported {
+    // An identifier that can be used to match events for this device.
+    // Currently, this is a salted hash of the MAC address of this Bluetooth device.
+    // Salt: Randomly generated 256 bit value
+    // Hash algorithm: HMAC-SHA256
+    // Size: 32 byte
+    // Default: null or empty if the device identifier is not known
+    optional bytes obfuscated_id = 1 [(android.os.statsd.log_mode) = MODE_BYTES];
+    // SMP command sent or received over L2CAP
+    // Default: CMD_UNKNOWN
+    optional android.bluetooth.smp.CommandEnum smp_command = 2;
+    // Whether this command is sent or received
+    // Default: DIRECTION_UNKNOWN
+    optional android.bluetooth.DirectionEnum direction = 3;
+    // SMP failure reason code
+    // Default: PAIRING_FAIL_REASON_DEFAULT
+    optional android.bluetooth.smp.PairingFailReasonEnum smp_fail_reason = 4;
+}
 
 /**
  * Logs when something is plugged into or removed from the USB-C connector.
@@ -2430,7 +2982,7 @@
     // specified and supported by the biometric modality, this is from the first ACQUIRED_GOOD to
     // AUTHENTICATED. for setRequireConfirmation(true), this is from PENDING_CONFIRMATION to
     // CONFIRMED.
-    optional int32 latency = 6;
+    optional int64 latency_millis = 6;
 }
 
 /**
@@ -4699,3 +5251,24 @@
     optional float normalized_x_position = 7;
     optional float normalized_y_position = 8;
 }
+
+/**
+ * Logs that a constraint for a scheduled job has changed.
+ *
+ * Logged from:
+ *     frameworks/base/services/core/java/com/android/server/job/controllers/JobStatus.java
+ */
+message ScheduledJobConstraintChanged {
+    repeated AttributionNode attribution_node = 1;
+
+    // Name of the job.
+    optional string job_name = 2;
+
+    optional com.android.server.job.ConstraintEnum constraint = 3;
+
+    enum State {
+        UNSATISFIED = 0;
+        SATISFIED = 1;
+    }
+    optional State state = 4;
+}
diff --git a/cmds/statsd/src/metrics/ValueMetricProducer.cpp b/cmds/statsd/src/metrics/ValueMetricProducer.cpp
index 4122d84..5645461 100644
--- a/cmds/statsd/src/metrics/ValueMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/ValueMetricProducer.cpp
@@ -524,6 +524,14 @@
         multiIntervals.resize(mFieldMatchers.size());
     }
 
+    // We only use anomaly detection under certain cases.
+    // N.B.: The anomaly detection cases were modified in order to fix an issue with value metrics
+    // containing multiple values. We tried to retain all previous behaviour, but we are unsure the
+    // previous behaviour was correct. At the time of the fix, anomaly detection had no owner.
+    // Whoever next works on it should look into the cases where it is triggered in this function.
+    // Discussion here: http://ag/6124370.
+    bool useAnomalyDetection = true;
+
     for (int i = 0; i < (int)mFieldMatchers.size(); i++) {
         const Matcher& matcher = mFieldMatchers[i];
         Interval& interval = multiIntervals[i];
@@ -546,7 +554,11 @@
                     // no base. just update base and return.
                     interval.base = value;
                     interval.hasBase = true;
-                    return;
+                    // If we're missing a base, do not use anomaly detection on incomplete data
+                    useAnomalyDetection = false;
+                    // Continue (instead of return) here in order to set interval.base and
+                    // interval.hasBase for other intervals
+                    continue;
                 }
             }
             Value diff;
@@ -560,7 +572,9 @@
                         VLOG("Unexpected decreasing value");
                         StatsdStats::getInstance().notePullDataError(mPullTagId);
                         interval.base = value;
-                        return;
+                        // If we've got bad data, do not use anomaly detection
+                        useAnomalyDetection = false;
+                        continue;
                     }
                     break;
                 case ValueMetric::DECREASING:
@@ -572,7 +586,9 @@
                         VLOG("Unexpected increasing value");
                         StatsdStats::getInstance().notePullDataError(mPullTagId);
                         interval.base = value;
-                        return;
+                        // If we've got bad data, do not use anomaly detection
+                        useAnomalyDetection = false;
+                        continue;
                     }
                     break;
                 case ValueMetric::ANY:
@@ -608,14 +624,18 @@
         interval.sampleSize += 1;
     }
 
-    // TODO: propgate proper values down stream when anomaly support doubles
-    long wholeBucketVal = multiIntervals[0].value.long_value;
-    auto prev = mCurrentFullBucket.find(eventKey);
-    if (prev != mCurrentFullBucket.end()) {
-        wholeBucketVal += prev->second;
-    }
-    for (auto& tracker : mAnomalyTrackers) {
-        tracker->detectAndDeclareAnomaly(eventTimeNs, mCurrentBucketNum, eventKey, wholeBucketVal);
+    // Only trigger the tracker if all intervals are correct
+    if (useAnomalyDetection) {
+        // TODO: propgate proper values down stream when anomaly support doubles
+        long wholeBucketVal = multiIntervals[0].value.long_value;
+        auto prev = mCurrentFullBucket.find(eventKey);
+        if (prev != mCurrentFullBucket.end()) {
+            wholeBucketVal += prev->second;
+        }
+        for (auto& tracker : mAnomalyTrackers) {
+            tracker->detectAndDeclareAnomaly(
+                eventTimeNs, mCurrentBucketNum, eventKey, wholeBucketVal);
+        }
     }
 }
 
diff --git a/cmds/statsd/src/metrics/ValueMetricProducer.h b/cmds/statsd/src/metrics/ValueMetricProducer.h
index 69eb0af..a8dfc5b 100644
--- a/cmds/statsd/src/metrics/ValueMetricProducer.h
+++ b/cmds/statsd/src/metrics/ValueMetricProducer.h
@@ -212,6 +212,7 @@
     FRIEND_TEST(ValueMetricProducerTest, TestFirstBucket);
     FRIEND_TEST(ValueMetricProducerTest, TestCalcPreviousBucketEndTime);
     FRIEND_TEST(ValueMetricProducerTest, TestSkipZeroDiffOutput);
+    FRIEND_TEST(ValueMetricProducerTest, TestSkipZeroDiffOutputMultiValue);
     FRIEND_TEST(ValueMetricProducerTest, TestUseZeroDefaultBase);
     FRIEND_TEST(ValueMetricProducerTest, TestUseZeroDefaultBaseWithPullFailures);
     FRIEND_TEST(ValueMetricProducerTest, TestTrimUnusedDimensionKey);
diff --git a/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp b/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp
index 9cfe343..c0648ee 100644
--- a/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp
+++ b/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp
@@ -1508,6 +1508,113 @@
     EXPECT_EQ(5, valueProducer.mPastBuckets.begin()->second.back().values[0].long_value);
 }
 
+TEST(ValueMetricProducerTest, TestSkipZeroDiffOutputMultiValue) {
+    ValueMetric metric;
+    metric.set_id(metricId);
+    metric.set_bucket(ONE_MINUTE);
+    metric.mutable_value_field()->set_field(tagId);
+    metric.mutable_value_field()->add_child()->set_field(2);
+    metric.mutable_value_field()->add_child()->set_field(3);
+    metric.set_aggregation_type(ValueMetric::MIN);
+    metric.set_use_diff(true);
+
+    UidMap uidMap;
+    SimpleAtomMatcher atomMatcher;
+    atomMatcher.set_atom_id(tagId);
+    sp<EventMatcherWizard> eventMatcherWizard =
+            new EventMatcherWizard({new SimpleLogMatchingTracker(
+                    atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
+    sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
+    sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
+
+    ValueMetricProducer valueProducer(kConfigKey, metric, -1, wizard, logEventMatcherIndex,
+                                      eventMatcherWizard, -1, bucketStartTimeNs, bucketStartTimeNs,
+                                      pullerManager);
+
+    shared_ptr<LogEvent> event1 = make_shared<LogEvent>(tagId, bucketStartTimeNs + 10);
+    event1->write(1);
+    event1->write(10);
+    event1->write(20);
+    event1->init();
+    shared_ptr<LogEvent> event2 = make_shared<LogEvent>(tagId, bucketStartTimeNs + 15);
+    event2->write(1);
+    event2->write(15);
+    event2->write(22);
+    event2->init();
+    valueProducer.onMatchedLogEvent(1 /*log matcher index*/, *event1);
+    // has one slice
+    EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
+    ValueMetricProducer::Interval curInterval0 =
+        valueProducer.mCurrentSlicedBucket.begin()->second[0];
+    ValueMetricProducer::Interval curInterval1 =
+        valueProducer.mCurrentSlicedBucket.begin()->second[1];
+    EXPECT_EQ(true, curInterval0.hasBase);
+    EXPECT_EQ(10, curInterval0.base.long_value);
+    EXPECT_EQ(false, curInterval0.hasValue);
+    EXPECT_EQ(true, curInterval1.hasBase);
+    EXPECT_EQ(20, curInterval1.base.long_value);
+    EXPECT_EQ(false, curInterval1.hasValue);
+
+    valueProducer.onMatchedLogEvent(1 /*log matcher index*/, *event2);
+
+    // has one slice
+    EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
+    curInterval0 = valueProducer.mCurrentSlicedBucket.begin()->second[0];
+    curInterval1 = valueProducer.mCurrentSlicedBucket.begin()->second[1];
+    EXPECT_EQ(true, curInterval0.hasValue);
+    EXPECT_EQ(5, curInterval0.value.long_value);
+    EXPECT_EQ(true, curInterval1.hasValue);
+    EXPECT_EQ(2, curInterval1.value.long_value);
+
+    // no change in first value field
+    shared_ptr<LogEvent> event3 = make_shared<LogEvent>(tagId, bucket2StartTimeNs + 10);
+    event3->write(1);
+    event3->write(15);
+    event3->write(25);
+    event3->init();
+    valueProducer.onMatchedLogEvent(1 /*log matcher index*/, *event3);
+    EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
+    curInterval0 = valueProducer.mCurrentSlicedBucket.begin()->second[0];
+    curInterval1 = valueProducer.mCurrentSlicedBucket.begin()->second[1];
+    EXPECT_EQ(true, curInterval0.hasBase);
+    EXPECT_EQ(15, curInterval0.base.long_value);
+    EXPECT_EQ(true, curInterval0.hasValue);
+    EXPECT_EQ(true, curInterval1.hasBase);
+    EXPECT_EQ(25, curInterval1.base.long_value);
+    EXPECT_EQ(true, curInterval1.hasValue);
+
+    shared_ptr<LogEvent> event4 = make_shared<LogEvent>(tagId, bucket2StartTimeNs + 15);
+    event4->write(1);
+    event4->write(15);
+    event4->write(29);
+    event4->init();
+    valueProducer.onMatchedLogEvent(1 /*log matcher index*/, *event4);
+    EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
+    curInterval0 = valueProducer.mCurrentSlicedBucket.begin()->second[0];
+    curInterval1 = valueProducer.mCurrentSlicedBucket.begin()->second[1];
+    EXPECT_EQ(true, curInterval0.hasBase);
+    EXPECT_EQ(15, curInterval0.base.long_value);
+    EXPECT_EQ(true, curInterval0.hasValue);
+    EXPECT_EQ(true, curInterval1.hasBase);
+    EXPECT_EQ(29, curInterval1.base.long_value);
+    EXPECT_EQ(true, curInterval1.hasValue);
+
+    valueProducer.flushIfNeededLocked(bucket3StartTimeNs);
+
+    EXPECT_EQ(1UL, valueProducer.mPastBuckets.size());
+    EXPECT_EQ(2UL, valueProducer.mPastBuckets.begin()->second.size());
+    EXPECT_EQ(2UL, valueProducer.mPastBuckets.begin()->second[0].values.size());
+    EXPECT_EQ(1UL, valueProducer.mPastBuckets.begin()->second[1].values.size());
+
+    EXPECT_EQ(5, valueProducer.mPastBuckets.begin()->second[0].values[0].long_value);
+    EXPECT_EQ(0, valueProducer.mPastBuckets.begin()->second[0].valueIndex[0]);
+    EXPECT_EQ(2, valueProducer.mPastBuckets.begin()->second[0].values[1].long_value);
+    EXPECT_EQ(1, valueProducer.mPastBuckets.begin()->second[0].valueIndex[1]);
+
+    EXPECT_EQ(3, valueProducer.mPastBuckets.begin()->second[1].values[0].long_value);
+    EXPECT_EQ(1, valueProducer.mPastBuckets.begin()->second[1].valueIndex[0]);
+}
+
 /*
  * Tests zero default base.
  */
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 92f47e7..e77e212 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -1808,6 +1808,29 @@
         mCalled = true;
     }
 
+    /**
+     * Called when activity gets or looses the top resumed position in the system.
+     *
+     * <p>Starting with {@link android.os.Build.VERSION_CODES#Q} multiple activities can be resumed
+     * at the same time in multi-window and multi-display modes. This callback should be used
+     * instead of {@link #onResume()} as an indication that the activity can try to open
+     * exclusive-access devices like camera.</p>
+     *
+     * <p>It will always be delivered after the activity was resumed and before it is paused. In
+     * some cases it might be skipped and activity can go straight from {@link #onResume()} to
+     * {@link #onPause()} without receiving the top resumed state.</p>
+     *
+     * @param isTopResumedActivity {@code true} if it's the topmost resumed activity in the system,
+     *                             {@code false} otherwise. A call with this as {@code true} will
+     *                             always be followed by another one with {@code false}.
+     *
+     * @see #onResume()
+     * @see #onPause()
+     * @see #onWindowFocusChanged(boolean)
+     */
+    public void onTopResumedActivityChanged(boolean isTopResumedActivity) {
+    }
+
     void setVoiceInteractor(IVoiceInteractor voiceInteractor) {
         if (mVoiceInteractor != null) {
             for (Request activeRequest: mVoiceInteractor.getActiveRequests()) {
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index ee3d27c..03a09ee 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -449,6 +449,14 @@
         ViewRootImpl.ActivityConfigCallback configCallback;
         ActivityClientRecord nextIdle;
 
+        // Indicates whether this activity is currently the topmost resumed one in the system.
+        // This holds the last reported value from server.
+        boolean isTopResumedActivity;
+        // This holds the value last sent to the activity. This is needed, because an update from
+        // server may come at random time, but we always need to report changes between ON_RESUME
+        // and ON_PAUSE to the app.
+        boolean lastReportedTopResumedState;
+
         ProfilerInfo profilerInfo;
 
         @UnsupportedAppUsage
@@ -3295,16 +3303,14 @@
         final boolean resumed = !r.paused;
         if (resumed) {
             r.activity.mTemporaryPause = true;
-            mInstrumentation.callActivityOnPause(r.activity);
+            performPauseActivityIfNeeded(r, "performNewIntents");
         }
         checkAndBlockForNetworkAccess();
         deliverNewIntents(r, intents);
         if (resumed) {
-            r.activity.performResume(false, "performNewIntents");
+            performResumeActivity(token, false, "performNewIntents");
             r.activity.mTemporaryPause = false;
-        }
-
-        if (r.paused && andPause) {
+        } else if (andPause) {
             // In this case the activity was in the paused state when we delivered the intent,
             // to guarantee onResume gets called after onNewIntent we temporarily resume the
             // activity and pause again as the caller wanted.
@@ -3957,6 +3963,8 @@
             r.state = null;
             r.persistentState = null;
             r.setState(ON_RESUME);
+
+            reportTopResumedActivityChanged(r, r.isTopResumedActivity);
         } catch (Exception e) {
             if (!mInstrumentation.onException(r.activity, e)) {
                 throw new RuntimeException("Unable to resume activity "
@@ -4111,6 +4119,45 @@
         Looper.myQueue().addIdleHandler(new Idler());
     }
 
+
+    @Override
+    public void handleTopResumedActivityChanged(IBinder token, boolean onTop, String reason) {
+        ActivityClientRecord r = mActivities.get(token);
+        if (r == null || r.activity == null) {
+            Slog.w(TAG, "Not found target activity to report position change for token: " + token);
+            return;
+        }
+
+        if (DEBUG_ORDER) {
+            Slog.d(TAG, "Received position change to top: " + onTop + " for activity: " + r);
+        }
+
+        if (r.isTopResumedActivity == onTop) {
+            throw new IllegalStateException("Activity top position already set to onTop=" + onTop);
+        }
+
+        r.isTopResumedActivity = onTop;
+
+        if (r.getLifecycleState() == ON_RESUME) {
+            reportTopResumedActivityChanged(r, onTop);
+        } else {
+            if (DEBUG_ORDER) {
+                Slog.d(TAG, "Won't deliver top position change in state=" + r.getLifecycleState());
+            }
+        }
+    }
+
+    /**
+     * Call {@link Activity#onTopResumedActivityChanged(boolean)} if its top resumed state changed
+     * since the last report.
+     */
+    private void reportTopResumedActivityChanged(ActivityClientRecord r, boolean onTop) {
+        if (r.lastReportedTopResumedState != onTop) {
+            r.lastReportedTopResumedState = onTop;
+            r.activity.onTopResumedActivityChanged(onTop);
+        }
+    }
+
     @Override
     public void handlePauseActivity(IBinder token, boolean finished, boolean userLeaving,
             int configChanges, PendingTransactionActions pendingActions, String reason) {
@@ -4202,6 +4249,10 @@
             return;
         }
 
+        // Always reporting top resumed position loss when pausing an activity. If necessary, it
+        // will be restored in performResumeActivity().
+        reportTopResumedActivityChanged(r, false /* onTop */);
+
         try {
             r.activity.mCalled = false;
             mInstrumentation.callActivityOnPause(r.activity);
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index 364d3c9..d2630d5 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -555,9 +555,11 @@
     public static final int OP_WRITE_MEDIA_IMAGES = 86;
     /** @hide Has a legacy (non-isolated) view of storage. */
     public static final int OP_LEGACY_STORAGE = 87;
+    /** @hide Accessing accessibility features */
+    public static final int OP_ACCESS_ACCESSIBILITY = 88;
     /** @hide */
     @UnsupportedAppUsage
-    public static final int _NUM_OP = 88;
+    public static final int _NUM_OP = 89;
 
     /** Access to coarse location information. */
     public static final String OPSTR_COARSE_LOCATION = "android:coarse_location";
@@ -826,6 +828,8 @@
     public static final String OPSTR_WRITE_MEDIA_IMAGES = "android:write_media_images";
     /** @hide Has a legacy (non-isolated) view of storage. */
     public static final String OPSTR_LEGACY_STORAGE = "android:legacy_storage";
+    /** @hide Interact with accessibility. */
+    public static final String OPSTR_ACCESS_ACCESSIBILITY = "android:access_accessibility";
 
     // Warning: If an permission is added here it also has to be added to
     // com.android.packageinstaller.permission.utils.EventLogger
@@ -985,6 +989,7 @@
             OP_READ_MEDIA_IMAGES,               // READ_MEDIA_IMAGES
             OP_WRITE_MEDIA_IMAGES,              // WRITE_MEDIA_IMAGES
             OP_LEGACY_STORAGE,                  // LEGACY_STORAGE
+            OP_ACCESS_ACCESSIBILITY,            // ACCESS_ACCESSIBILITY
     };
 
     /**
@@ -1079,6 +1084,7 @@
             OPSTR_READ_MEDIA_IMAGES,
             OPSTR_WRITE_MEDIA_IMAGES,
             OPSTR_LEGACY_STORAGE,
+            OPSTR_ACCESS_ACCESSIBILITY,
     };
 
     /**
@@ -1174,6 +1180,7 @@
             "READ_MEDIA_IMAGES",
             "WRITE_MEDIA_IMAGES",
             "LEGACY_STORAGE",
+            "ACCESS_ACCESSIBILITY",
     };
 
     /**
@@ -1270,6 +1277,7 @@
             Manifest.permission.READ_MEDIA_IMAGES,
             null, // no permission for OP_WRITE_MEDIA_IMAGES
             null, // no permission for OP_LEGACY_STORAGE
+            null, // no permission for OP_ACCESS_ACCESSIBILITY
     };
 
     /**
@@ -1366,6 +1374,7 @@
             null, // READ_MEDIA_IMAGES
             null, // WRITE_MEDIA_IMAGES
             null, // LEGACY_STORAGE
+            null, // ACCESS_ACCESSIBILITY
     };
 
     /**
@@ -1461,6 +1470,7 @@
             false, // READ_MEDIA_IMAGES
             false, // WRITE_MEDIA_IMAGES
             false, // LEGACY_STORAGE
+            false, // ACCESS_ACCESSIBILITY
     };
 
     /**
@@ -1555,6 +1565,7 @@
             AppOpsManager.MODE_ALLOWED, // READ_MEDIA_IMAGES
             AppOpsManager.MODE_ERRORED, // WRITE_MEDIA_IMAGES
             AppOpsManager.MODE_DEFAULT, // LEGACY_STORAGE
+            AppOpsManager.MODE_ALLOWED, // ACCESS_ACCESSIBILITY
     };
 
     /**
@@ -1653,6 +1664,7 @@
             false, // READ_MEDIA_IMAGES
             false, // WRITE_MEDIA_IMAGES
             false, // LEGACY_STORAGE
+            false, // ACCESS_ACCESSIBILITY
     };
 
     /**
diff --git a/core/java/android/app/AppOpsManagerInternal.java b/core/java/android/app/AppOpsManagerInternal.java
index b556033..da45054 100644
--- a/core/java/android/app/AppOpsManagerInternal.java
+++ b/core/java/android/app/AppOpsManagerInternal.java
@@ -78,7 +78,7 @@
     /**
      * Sets the app-ops mode for a certain app-op and uid.
      *
-     * <p>Similar as {@link AppOpsManager#setMode} but does not require the package manager to be
+     * <p>Similar as {@link AppOpsManager#setUidMode} but does not require the package manager to be
      * working. Hence this can be used very early during boot.
      *
      * <p>Only for internal callers. Does <u>not</u> verify that package name belongs to uid.
@@ -88,4 +88,12 @@
      * @param mode The new mode to set.
      */
     public abstract void setUidMode(int code, int uid, int mode);
+
+    /**
+     * Set all {@link #setMode (package) modes} for this uid to the default value.
+     *
+     * @param code The app-op
+     * @param uid The uid
+     */
+    public abstract void setAllPkgModesToDefault(int code, int uid);
 }
diff --git a/core/java/android/app/ClientTransactionHandler.java b/core/java/android/app/ClientTransactionHandler.java
index 07dbb6b..70badfa 100644
--- a/core/java/android/app/ClientTransactionHandler.java
+++ b/core/java/android/app/ClientTransactionHandler.java
@@ -105,6 +105,16 @@
             boolean isForward, String reason);
 
     /**
+     * Notify the activity about top resumed state change.
+     * @param token Target activity token.
+     * @param isTopResumedActivity Current state of the activity, {@code true} if it's the
+     *                             topmost resumed activity in the system, {@code false} otherwise.
+     * @param reason Reason for performing this operation.
+     */
+    public abstract void handleTopResumedActivityChanged(IBinder token,
+            boolean isTopResumedActivity, String reason);
+
+    /**
      * Stop the activity.
      * @param token Target activity token.
      * @param show Flag indicating whether activity is still shown.
diff --git a/core/java/android/app/DownloadManager.java b/core/java/android/app/DownloadManager.java
index 853b45e..acc7094 100644
--- a/core/java/android/app/DownloadManager.java
+++ b/core/java/android/app/DownloadManager.java
@@ -1067,7 +1067,12 @@
      * COLUMN_* constants.
      */
     public Cursor query(Query query) {
-        Cursor underlyingCursor = query.runQuery(mResolver, UNDERLYING_COLUMNS, mBaseUri);
+        return query(query, UNDERLYING_COLUMNS);
+    }
+
+    /** @hide */
+    public Cursor query(Query query, String[] projection) {
+        Cursor underlyingCursor = query.runQuery(mResolver, projection, mBaseUri);
         if (underlyingCursor == null) {
             return null;
         }
diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl
index fb65da1..412d7f4 100644
--- a/core/java/android/app/IActivityManager.aidl
+++ b/core/java/android/app/IActivityManager.aidl
@@ -277,6 +277,7 @@
     void unstableProviderDied(in IBinder connection);
     boolean isIntentSenderAnActivity(in IIntentSender sender);
     boolean isIntentSenderAForegroundService(in IIntentSender sender);
+    boolean isIntentSenderABroadcast(in IIntentSender sender);
     int startActivityAsUser(in IApplicationThread caller, in String callingPackage,
             in Intent intent, in String resolvedType, in IBinder resultTo, in String resultWho,
             int requestCode, int flags, in ProfilerInfo profilerInfo,
diff --git a/core/java/android/app/INotificationManager.aidl b/core/java/android/app/INotificationManager.aidl
index 199c133..8953940 100644
--- a/core/java/android/app/INotificationManager.aidl
+++ b/core/java/android/app/INotificationManager.aidl
@@ -68,6 +68,7 @@
     void setBubblesAllowed(String pkg, int uid, boolean allowed);
     boolean areBubblesAllowed(String pkg);
     boolean areBubblesAllowedForPackage(String pkg, int uid);
+    boolean hasUserApprovedBubblesForPackage(String pkg, int uid);
 
     void createNotificationChannelGroups(String pkg, in ParceledListSlice channelGroupList);
     void createNotificationChannels(String pkg, in ParceledListSlice channelsList);
@@ -94,6 +95,7 @@
     boolean areChannelsBypassingDnd();
     int getAppsBypassingDndCount(int uid);
     ParceledListSlice getNotificationChannelsBypassingDnd(String pkg, int userId);
+    boolean isPackagePaused(String pkg);
 
     // TODO: Remove this when callers have been migrated to the equivalent
     // INotificationListener method.
diff --git a/core/java/android/app/NotificationManager.java b/core/java/android/app/NotificationManager.java
index c4b4b40..621f134 100644
--- a/core/java/android/app/NotificationManager.java
+++ b/core/java/android/app/NotificationManager.java
@@ -1094,6 +1094,22 @@
     }
 
     /**
+     * Returns whether notifications from this package are temporarily hidden. This
+     * could be done because the package was marked as distracting to the user via
+     * {@code PackageManager#setDistractingPackageRestrictions(String[], int)} or because the
+     * package is {@code PackageManager#setPackagesSuspended(String[], boolean, PersistableBundle,
+     * PersistableBundle, SuspendDialogInfo) suspended}.
+     */
+    public boolean areNotificationsPaused() {
+        INotificationManager service = getService();
+        try {
+            return service.isPackagePaused(mContext.getPackageName());
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
      * Checks the ability to modify notification do not disturb policy for the calling package.
      *
      * <p>
diff --git a/core/java/android/app/PendingIntent.java b/core/java/android/app/PendingIntent.java
index 75d95b2..55014eb 100644
--- a/core/java/android/app/PendingIntent.java
+++ b/core/java/android/app/PendingIntent.java
@@ -1113,6 +1113,19 @@
 
     /**
      * @hide
+     * Check whether this PendingIntent will launch an Activity.
+     */
+    public boolean isBroadcast() {
+        try {
+            return ActivityManager.getService()
+                .isIntentSenderABroadcast(mTarget);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * @hide
      * Return the Intent of this PendingIntent.
      */
     @UnsupportedAppUsage
diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
index 2dc225a..ee13164 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -102,6 +102,7 @@
 import android.net.IEthernetManager;
 import android.net.IIpMemoryStore;
 import android.net.IIpSecService;
+import android.net.INetd;
 import android.net.INetworkPolicyManager;
 import android.net.IpMemoryStore;
 import android.net.IpSecManager;
@@ -328,6 +329,14 @@
                 return new ConnectivityManager(context, service);
             }});
 
+        registerService(Context.NETD_SERVICE, INetd.class, new StaticServiceFetcher<INetd>() {
+            @Override
+            public INetd createService() throws ServiceNotFoundException {
+                return INetd.Stub.asInterface(
+                        ServiceManager.getServiceOrThrow(Context.NETD_SERVICE));
+            }
+        });
+
         registerService(Context.NETWORK_STACK_SERVICE, NetworkStack.class,
                 new StaticServiceFetcher<NetworkStack>() {
                     @Override
diff --git a/core/java/android/app/role/IRoleManager.aidl b/core/java/android/app/role/IRoleManager.aidl
index 2964fbc..cf62e8d 100644
--- a/core/java/android/app/role/IRoleManager.aidl
+++ b/core/java/android/app/role/IRoleManager.aidl
@@ -18,6 +18,8 @@
 
 import android.app.role.IOnRoleHoldersChangedListener;
 import android.app.role.IRoleManagerCallback;
+import android.os.Bundle;
+import android.telephony.IFinancialSmsCallback;
 
 /**
  * @hide
@@ -52,4 +54,8 @@
     List<String> getHeldRolesFromController(in String packageName);
 
     String getDefaultSmsPackage(int userId);
+    /**
+     * Get filtered SMS messages for financial app.
+     */
+    void getSmsMessagesForFinancialApp(in String callingPkg, in Bundle params, in IFinancialSmsCallback callback);
 }
diff --git a/core/java/android/app/servertransaction/TopResumedActivityChangeItem.java b/core/java/android/app/servertransaction/TopResumedActivityChangeItem.java
new file mode 100644
index 0000000..4064a02
--- /dev/null
+++ b/core/java/android/app/servertransaction/TopResumedActivityChangeItem.java
@@ -0,0 +1,112 @@
+/*
+ * 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.app.servertransaction;
+
+import static android.os.Trace.TRACE_TAG_ACTIVITY_MANAGER;
+
+import android.app.ClientTransactionHandler;
+import android.os.IBinder;
+import android.os.Parcel;
+import android.os.Trace;
+
+/**
+ * Top resumed activity changed callback.
+ * @hide
+ */
+public class TopResumedActivityChangeItem extends ClientTransactionItem {
+
+    private boolean mOnTop;
+
+    @Override
+    public void execute(ClientTransactionHandler client, IBinder token,
+            PendingTransactionActions pendingActions) {
+        Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "topResumedActivityChangeItem");
+        client.handleTopResumedActivityChanged(token, mOnTop, "topResumedActivityChangeItem");
+        Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
+    }
+
+
+    // ObjectPoolItem implementation
+
+    private TopResumedActivityChangeItem() {}
+
+    /** Obtain an instance initialized with provided params. */
+    public static TopResumedActivityChangeItem obtain(boolean onTop) {
+        TopResumedActivityChangeItem instance =
+                ObjectPool.obtain(TopResumedActivityChangeItem.class);
+        if (instance == null) {
+            instance = new TopResumedActivityChangeItem();
+        }
+        instance.mOnTop = onTop;
+
+        return instance;
+    }
+
+    @Override
+    public void recycle() {
+        mOnTop = false;
+        ObjectPool.recycle(this);
+    }
+
+
+    // Parcelable implementation
+
+    /** Write to Parcel. */
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeBoolean(mOnTop);
+    }
+
+    /** Read from Parcel. */
+    private TopResumedActivityChangeItem(Parcel in) {
+        mOnTop = in.readBoolean();
+    }
+
+    public static final Creator<TopResumedActivityChangeItem> CREATOR =
+            new Creator<TopResumedActivityChangeItem>() {
+                public TopResumedActivityChangeItem createFromParcel(Parcel in) {
+                    return new TopResumedActivityChangeItem(in);
+                }
+
+                public TopResumedActivityChangeItem[] newArray(int size) {
+                    return new TopResumedActivityChangeItem[size];
+                }
+            };
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) {
+            return true;
+        }
+        if (o == null || getClass() != o.getClass()) {
+            return false;
+        }
+        final TopResumedActivityChangeItem other = (TopResumedActivityChangeItem) o;
+        return mOnTop == other.mOnTop;
+    }
+
+    @Override
+    public int hashCode() {
+        int result = 17;
+        result = 31 * result + (mOnTop ? 1 : 0);
+        return result;
+    }
+
+    @Override
+    public String toString() {
+        return "TopResumedActivityChangeItem{onTop=" + mOnTop + "}";
+    }
+}
diff --git a/core/java/android/app/usage/UsageStatsManagerInternal.java b/core/java/android/app/usage/UsageStatsManagerInternal.java
index 3d3c03a..43ce521 100644
--- a/core/java/android/app/usage/UsageStatsManagerInternal.java
+++ b/core/java/android/app/usage/UsageStatsManagerInternal.java
@@ -287,19 +287,14 @@
 
     /** A class which is used to share the usage limit data for an app or a group of apps. */
     public static class AppUsageLimitData {
-        private final boolean mGroupLimit;
         private final long mTotalUsageLimit;
         private final long mUsageRemaining;
 
-        public AppUsageLimitData(boolean groupLimit, long totalUsageLimit, long usageRemaining) {
-            this.mGroupLimit = groupLimit;
+        public AppUsageLimitData(long totalUsageLimit, long usageRemaining) {
             this.mTotalUsageLimit = totalUsageLimit;
             this.mUsageRemaining = usageRemaining;
         }
 
-        public boolean isGroupLimit() {
-            return mGroupLimit;
-        }
         public long getTotalUsageLimit() {
             return mTotalUsageLimit;
         }
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 280f1ac..87f9e46 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -3637,6 +3637,16 @@
 
     /**
      * Use with {@link #getSystemService(String)} to retrieve a
+     * {@link android.net.INetd} for communicating with the network stack
+     * @hide
+     * @see #getSystemService(String)
+     * @hide
+     */
+    @SystemApi
+    public static final String NETD_SERVICE = "netd";
+
+    /**
+     * Use with {@link #getSystemService(String)} to retrieve a
      * {@link NetworkStack} for communicating with the network stack
      * @hide
      * @see #getSystemService(String)
diff --git a/core/java/android/content/pm/CrossProfileApps.java b/core/java/android/content/pm/CrossProfileApps.java
index b7366f1..e897b91 100644
--- a/core/java/android/content/pm/CrossProfileApps.java
+++ b/core/java/android/content/pm/CrossProfileApps.java
@@ -18,7 +18,6 @@
 import android.annotation.NonNull;
 import android.annotation.RequiresPermission;
 import android.annotation.SystemApi;
-import android.annotation.UnsupportedAppUsage;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.res.Resources;
@@ -77,18 +76,6 @@
     }
 
     /**
-     * @deprecated use {@link #startActivity(ComponentName, UserHandle)} instead.
-     *
-     * @removed
-     * @hide
-     */
-    @Deprecated
-    @UnsupportedAppUsage
-    public void startAnyActivity(@NonNull ComponentName component, @NonNull UserHandle targetUser) {
-        startActivity(component, targetUser);
-    }
-
-    /**
      * Starts the specified activity of the caller package in the specified profile. Unlike
      * {@link #startMainActivity}, this can start any activity of the caller package, not just
      * the main activity.
diff --git a/core/java/android/content/pm/LauncherApps.java b/core/java/android/content/pm/LauncherApps.java
index 89630e1..36bb5d4 100644
--- a/core/java/android/content/pm/LauncherApps.java
+++ b/core/java/android/content/pm/LauncherApps.java
@@ -1658,35 +1658,23 @@
      * A class that encapsulates information about the usage limit set for an app or
      * a group of apps.
      *
-     * <p>The launcher can query specifics about the usage limit such as if it is a group limit,
-     * how much usage time the limit has, and how much of the total usage time is remaining
-     * via the APIs available in this class.
+     * <p>The launcher can query specifics about the usage limit such as how much usage time
+     * the limit has and how much of the total usage time is remaining via the APIs available
+     * in this class.
      *
      * @see #getAppUsageLimit(String, UserHandle)
      */
     public static final class AppUsageLimit implements Parcelable {
-        private final boolean mGroupLimit;
         private final long mTotalUsageLimit;
         private final long mUsageRemaining;
 
         /** @hide */
-        public AppUsageLimit(boolean groupLimit, long totalUsageLimit, long usageRemaining) {
-            this.mGroupLimit = groupLimit;
+        public AppUsageLimit(long totalUsageLimit, long usageRemaining) {
             this.mTotalUsageLimit = totalUsageLimit;
             this.mUsageRemaining = usageRemaining;
         }
 
         /**
-         * Returns whether this limit refers to a group of apps.
-         *
-         * @return {@code TRUE} if the limit refers to a group of apps, {@code FALSE} otherwise.
-         * @hide
-         */
-        public boolean isGroupLimit() {
-            return mGroupLimit;
-        }
-
-        /**
          * Returns the total usage limit in milliseconds set for an app or a group of apps.
          *
          * @return the total usage limit in milliseconds
@@ -1706,7 +1694,6 @@
         }
 
         private AppUsageLimit(Parcel source) {
-            mGroupLimit = source.readBoolean();
             mTotalUsageLimit = source.readLong();
             mUsageRemaining = source.readLong();
         }
@@ -1730,7 +1717,6 @@
 
         @Override
         public void writeToParcel(Parcel dest, int flags) {
-            dest.writeBoolean(mGroupLimit);
             dest.writeLong(mTotalUsageLimit);
             dest.writeLong(mUsageRemaining);
         }
diff --git a/core/java/android/content/rollback/IRollbackManager.aidl b/core/java/android/content/rollback/IRollbackManager.aidl
index 63d75a0..226d76a 100644
--- a/core/java/android/content/rollback/IRollbackManager.aidl
+++ b/core/java/android/content/rollback/IRollbackManager.aidl
@@ -26,7 +26,7 @@
     ParceledListSlice getAvailableRollbacks();
     ParceledListSlice getRecentlyExecutedRollbacks();
 
-    void executeRollback(in RollbackInfo rollback, String callerPackageName,
+    void commitRollback(int rollbackId, String callerPackageName,
             in IntentSender statusReceiver);
 
     // Exposed for use from the system server only. Callback from the package
diff --git a/core/java/android/content/rollback/RollbackInfo.java b/core/java/android/content/rollback/RollbackInfo.java
index 8532b5a..812f995 100644
--- a/core/java/android/content/rollback/RollbackInfo.java
+++ b/core/java/android/content/rollback/RollbackInfo.java
@@ -17,6 +17,7 @@
 package android.content.rollback;
 
 import android.annotation.SystemApi;
+import android.content.pm.PackageInstaller;
 import android.os.Parcel;
 import android.os.Parcelable;
 
@@ -38,9 +39,6 @@
 
     private final List<PackageRollbackInfo> mPackages;
 
-    // TODO: Add a flag to indicate if reboot is required, when rollback of
-    // staged installs is supported.
-
     /** @hide */
     public RollbackInfo(int rollbackId, List<PackageRollbackInfo> packages) {
         this.mRollbackId = rollbackId;
@@ -66,6 +64,24 @@
         return mPackages;
     }
 
+    /**
+     * Returns true if this rollback requires reboot to take effect after
+     * being committed.
+     */
+    public boolean isStaged() {
+        // TODO: Support rollback of staged installs.
+        return false;
+    }
+
+    /**
+     * Returns the session ID for the committed rollback for staged rollbacks.
+     * Only applicable for rollbacks that have been committed.
+     */
+    public int getSessionId() {
+        // TODO: Support rollback of staged installs.
+        return PackageInstaller.SessionInfo.INVALID_ID;
+    }
+
     @Override
     public int describeContents() {
         return 0;
diff --git a/core/java/android/content/rollback/RollbackManager.java b/core/java/android/content/rollback/RollbackManager.java
index 2566ac5..f8abcfc 100644
--- a/core/java/android/content/rollback/RollbackManager.java
+++ b/core/java/android/content/rollback/RollbackManager.java
@@ -102,16 +102,15 @@
      * <p>
      * TODO: Specify the returns status codes.
      *
-     * @param rollback to commit
+     * @param rollbackId ID of the rollback to commit
      * @param statusReceiver where to deliver the results
      * @throws SecurityException if the caller does not have the
      *            MANAGE_ROLLBACKS permission.
      */
     @RequiresPermission(android.Manifest.permission.MANAGE_ROLLBACKS)
-    public void commitRollback(@NonNull RollbackInfo rollback,
-            @NonNull IntentSender statusReceiver) {
+    public void commitRollback(int rollbackId, @NonNull IntentSender statusReceiver) {
         try {
-            mBinder.executeRollback(rollback, mCallerPackageName, statusReceiver);
+            mBinder.commitRollback(rollbackId, mCallerPackageName, statusReceiver);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
diff --git a/core/java/android/hardware/HardwareBuffer.java b/core/java/android/hardware/HardwareBuffer.java
index d2c0e7b..5d4928c 100644
--- a/core/java/android/hardware/HardwareBuffer.java
+++ b/core/java/android/hardware/HardwareBuffer.java
@@ -182,6 +182,38 @@
     }
 
     /**
+     * Queries whether the given buffer description is supported by the system. If this returns
+     * true, then the allocation may succeed until resource exhaustion occurs. If this returns
+     * false then this combination will never succeed.
+     *
+     * @param width The width in pixels of the buffer
+     * @param height The height in pixels of the buffer
+     * @param format The @Format of each pixel
+     * @param layers The number of layers in the buffer
+     * @param usage The @Usage flags describing how the buffer will be used
+     * @return True if the combination is supported, false otherwise.
+     */
+    public static boolean isSupported(int width, int height, @Format int format, int layers,
+            @Usage long usage) {
+        if (!HardwareBuffer.isSupportedFormat(format)) {
+            throw new IllegalArgumentException("Invalid pixel format " + format);
+        }
+        if (width <= 0) {
+            throw new IllegalArgumentException("Invalid width " + width);
+        }
+        if (height <= 0) {
+            throw new IllegalArgumentException("Invalid height " + height);
+        }
+        if (layers <= 0) {
+            throw new IllegalArgumentException("Invalid layer count " + layers);
+        }
+        if (format == BLOB && height != 1) {
+            throw new IllegalArgumentException("Height must be 1 when using the BLOB format");
+        }
+        return nIsSupported(width, height, format, layers, usage);
+    }
+
+    /**
      * Private use only. See {@link #create(int, int, int, int, long)}. May also be
      * called from JNI using an already allocated native <code>HardwareBuffer</code>.
      */
@@ -386,4 +418,6 @@
     private static native int nGetLayers(long nativeObject);
     @FastNative
     private static native long nGetUsage(long nativeObject);
+    private static native boolean nIsSupported(int width, int height, int format, int layers,
+            long usage);
 }
diff --git a/core/java/android/hardware/biometrics/BiometricFaceConstants.java b/core/java/android/hardware/biometrics/BiometricFaceConstants.java
index 209afb8..125dabe 100644
--- a/core/java/android/hardware/biometrics/BiometricFaceConstants.java
+++ b/core/java/android/hardware/biometrics/BiometricFaceConstants.java
@@ -295,12 +295,22 @@
     public static final int FACE_ACQUIRED_FACE_OBSCURED = 19;
 
     /**
+     * This message represents the earliest message sent at the beginning of the authentication
+     * pipeline. It is expected to be used to measure latency. For example, in a camera-based
+     * authentication system it's expected to be sent prior to camera initialization. Note this
+     * should be sent whenever authentication is restarted (see IBiometricsFace#userActivity).
+     * The framework will measure latency based on the time between the last START message and the
+     * onAuthenticated callback.
+     */
+    public static final int FACE_ACQUIRED_START = 20;
+
+    /**
      * Hardware vendors may extend this list if there are conditions that do not fall under one of
      * the above categories. Vendors are responsible for providing error strings for these errors.
      *
      * @hide
      */
-    public static final int FACE_ACQUIRED_VENDOR = 20;
+    public static final int FACE_ACQUIRED_VENDOR = 21;
 
     /**
      * @hide
diff --git a/core/java/android/hardware/camera2/CameraCharacteristics.java b/core/java/android/hardware/camera2/CameraCharacteristics.java
index 9758308..425b956 100644
--- a/core/java/android/hardware/camera2/CameraCharacteristics.java
+++ b/core/java/android/hardware/camera2/CameraCharacteristics.java
@@ -3721,6 +3721,59 @@
             new Key<android.hardware.camera2.params.RecommendedStreamConfiguration[]>("android.depth.availableRecommendedDepthStreamConfigurations", android.hardware.camera2.params.RecommendedStreamConfiguration[].class);
 
     /**
+     * <p>The available dynamic depth dataspace stream
+     * configurations that this camera device supports
+     * (i.e. format, width, height, output/input stream).</p>
+     * <p>These are output stream configurations for use with
+     * dataSpace DYNAMIC_DEPTH. The configurations are
+     * listed as <code>(format, width, height, input?)</code> tuples.</p>
+     * <p>Only devices that support depth output for at least
+     * the HAL_PIXEL_FORMAT_Y16 dense depth map along with
+     * HAL_PIXEL_FORMAT_BLOB with the same size or size with
+     * the same aspect ratio can have dynamic depth dataspace
+     * stream configuration. {@link CameraCharacteristics#DEPTH_DEPTH_IS_EXCLUSIVE android.depth.depthIsExclusive} also
+     * needs to be set to FALSE.</p>
+     * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
+     *
+     * @see CameraCharacteristics#DEPTH_DEPTH_IS_EXCLUSIVE
+     * @hide
+     */
+    public static final Key<android.hardware.camera2.params.StreamConfiguration[]> DEPTH_AVAILABLE_DYNAMIC_DEPTH_STREAM_CONFIGURATIONS =
+            new Key<android.hardware.camera2.params.StreamConfiguration[]>("android.depth.availableDynamicDepthStreamConfigurations", android.hardware.camera2.params.StreamConfiguration[].class);
+
+    /**
+     * <p>This lists the minimum frame duration for each
+     * format/size combination for dynamic depth output streams.</p>
+     * <p>This should correspond to the frame duration when only that
+     * stream is active, with all processing (typically in android.*.mode)
+     * set to either OFF or FAST.</p>
+     * <p>When multiple streams are used in a request, the minimum frame
+     * duration will be max(individual stream min durations).</p>
+     * <p>The minimum frame duration of a stream (of a particular format, size)
+     * is the same regardless of whether the stream is input or output.</p>
+     * <p><b>Units</b>: (format, width, height, ns) x n</p>
+     * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
+     * @hide
+     */
+    public static final Key<android.hardware.camera2.params.StreamConfigurationDuration[]> DEPTH_AVAILABLE_DYNAMIC_DEPTH_MIN_FRAME_DURATIONS =
+            new Key<android.hardware.camera2.params.StreamConfigurationDuration[]>("android.depth.availableDynamicDepthMinFrameDurations", android.hardware.camera2.params.StreamConfigurationDuration[].class);
+
+    /**
+     * <p>This lists the maximum stall duration for each
+     * output format/size combination for dynamic depth streams.</p>
+     * <p>A stall duration is how much extra time would get added
+     * to the normal minimum frame duration for a repeating request
+     * that has streams with non-zero stall.</p>
+     * <p>All dynamic depth output streams may have a nonzero stall
+     * duration.</p>
+     * <p><b>Units</b>: (format, width, height, ns) x n</p>
+     * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
+     * @hide
+     */
+    public static final Key<android.hardware.camera2.params.StreamConfigurationDuration[]> DEPTH_AVAILABLE_DYNAMIC_DEPTH_STALL_DURATIONS =
+            new Key<android.hardware.camera2.params.StreamConfigurationDuration[]>("android.depth.availableDynamicDepthStallDurations", android.hardware.camera2.params.StreamConfigurationDuration[].class);
+
+    /**
      * <p>String containing the ids of the underlying physical cameras.</p>
      * <p>For a logical camera, this is concatenation of all underlying physical camera IDs.
      * The null terminator for physical camera ID must be preserved so that the whole string
diff --git a/core/java/android/hardware/camera2/impl/CameraMetadataNative.java b/core/java/android/hardware/camera2/impl/CameraMetadataNative.java
index c527ab4..7877a4d 100644
--- a/core/java/android/hardware/camera2/impl/CameraMetadataNative.java
+++ b/core/java/android/hardware/camera2/impl/CameraMetadataNative.java
@@ -1119,6 +1119,8 @@
                 continue;
             }
 
+            // Dynamic depth streams involve alot of SW processing and currently cannot be
+            // recommended.
             StreamConfigurationMap map = null;
             switch (i) {
                 case RecommendedStreamConfigurationMap.USECASE_PREVIEW:
@@ -1127,28 +1129,44 @@
                     map = new StreamConfigurationMap(scData.streamConfigurationArray,
                             scData.minDurationArray, scData.stallDurationArray,
                             /*depthconfiguration*/ null, /*depthminduration*/ null,
-                            /*depthstallduration*/ null, /*highspeedvideoconfigurations*/ null,
+                            /*depthstallduration*/ null,
+                            /*dynamicDepthConfigurations*/ null,
+                            /*dynamicDepthMinFrameDurations*/ null,
+                            /*dynamicDepthStallDurations*/ null,
+                            /*highspeedvideoconfigurations*/ null,
                             /*inputoutputformatsmap*/ null, listHighResolution, supportsPrivate[i]);
                     break;
                 case RecommendedStreamConfigurationMap.USECASE_RECORD:
                     map = new StreamConfigurationMap(scData.streamConfigurationArray,
                             scData.minDurationArray, scData.stallDurationArray,
                             /*depthconfiguration*/ null, /*depthminduration*/ null,
-                            /*depthstallduration*/ null, highSpeedVideoConfigurations,
+                            /*depthstallduration*/ null,
+                            /*dynamicDepthConfigurations*/ null,
+                            /*dynamicDepthMinFrameDurations*/ null,
+                            /*dynamicDepthStallDurations*/ null,
+                            highSpeedVideoConfigurations,
                             /*inputoutputformatsmap*/ null, listHighResolution, supportsPrivate[i]);
                     break;
                 case RecommendedStreamConfigurationMap.USECASE_ZSL:
                     map = new StreamConfigurationMap(scData.streamConfigurationArray,
                             scData.minDurationArray, scData.stallDurationArray,
                             depthScData.streamConfigurationArray, depthScData.minDurationArray,
-                            depthScData.stallDurationArray, /*highSpeedVideoConfigurations*/ null,
+                            depthScData.stallDurationArray,
+                            /*dynamicDepthConfigurations*/ null,
+                            /*dynamicDepthMinFrameDurations*/ null,
+                            /*dynamicDepthStallDurations*/ null,
+                            /*highSpeedVideoConfigurations*/ null,
                             inputOutputFormatsMap, listHighResolution, supportsPrivate[i]);
                     break;
                 default:
                     map = new StreamConfigurationMap(scData.streamConfigurationArray,
                             scData.minDurationArray, scData.stallDurationArray,
                             depthScData.streamConfigurationArray, depthScData.minDurationArray,
-                            depthScData.stallDurationArray, /*highSpeedVideoConfigurations*/ null,
+                            depthScData.stallDurationArray,
+                            /*dynamicDepthConfigurations*/ null,
+                            /*dynamicDepthMinFrameDurations*/ null,
+                            /*dynamicDepthStallDurations*/ null,
+                            /*highSpeedVideoConfigurations*/ null,
                             /*inputOutputFormatsMap*/ null, listHighResolution, supportsPrivate[i]);
             }
 
@@ -1206,6 +1224,12 @@
                 CameraCharacteristics.DEPTH_AVAILABLE_DEPTH_MIN_FRAME_DURATIONS);
         StreamConfigurationDuration[] depthStallDurations = getBase(
                 CameraCharacteristics.DEPTH_AVAILABLE_DEPTH_STALL_DURATIONS);
+        StreamConfiguration[] dynamicDepthConfigurations = getBase(
+                CameraCharacteristics.DEPTH_AVAILABLE_DYNAMIC_DEPTH_STREAM_CONFIGURATIONS);
+        StreamConfigurationDuration[] dynamicDepthMinFrameDurations = getBase(
+                CameraCharacteristics.DEPTH_AVAILABLE_DYNAMIC_DEPTH_MIN_FRAME_DURATIONS);
+        StreamConfigurationDuration[] dynamicDepthStallDurations = getBase(
+                CameraCharacteristics.DEPTH_AVAILABLE_DYNAMIC_DEPTH_STALL_DURATIONS);
         HighSpeedVideoConfiguration[] highSpeedVideoConfigurations = getBase(
                 CameraCharacteristics.CONTROL_AVAILABLE_HIGH_SPEED_VIDEO_CONFIGURATIONS);
         ReprocessFormatsMap inputOutputFormatsMap = getBase(
@@ -1214,7 +1238,8 @@
         return new StreamConfigurationMap(
                 configurations, minFrameDurations, stallDurations,
                 depthConfigurations, depthMinFrameDurations, depthStallDurations,
-                highSpeedVideoConfigurations, inputOutputFormatsMap,
+                dynamicDepthConfigurations, dynamicDepthMinFrameDurations,
+                dynamicDepthStallDurations, highSpeedVideoConfigurations, inputOutputFormatsMap,
                 listHighResolution);
     }
 
diff --git a/core/java/android/hardware/camera2/params/StreamConfigurationMap.java b/core/java/android/hardware/camera2/params/StreamConfigurationMap.java
index dd052a8..a22e008 100644
--- a/core/java/android/hardware/camera2/params/StreamConfigurationMap.java
+++ b/core/java/android/hardware/camera2/params/StreamConfigurationMap.java
@@ -95,13 +95,17 @@
             StreamConfiguration[] depthConfigurations,
             StreamConfigurationDuration[] depthMinFrameDurations,
             StreamConfigurationDuration[] depthStallDurations,
+            StreamConfiguration[] dynamicDepthConfigurations,
+            StreamConfigurationDuration[] dynamicDepthMinFrameDurations,
+            StreamConfigurationDuration[] dynamicDepthStallDurations,
             HighSpeedVideoConfiguration[] highSpeedVideoConfigurations,
             ReprocessFormatsMap inputOutputFormatsMap,
             boolean listHighResolution) {
         this(configurations, minFrameDurations, stallDurations,
                     depthConfigurations, depthMinFrameDurations, depthStallDurations,
-                    highSpeedVideoConfigurations, inputOutputFormatsMap, listHighResolution,
-                    /*enforceImplementationDefined*/ true);
+                    dynamicDepthConfigurations, dynamicDepthMinFrameDurations,
+                    dynamicDepthStallDurations, highSpeedVideoConfigurations, inputOutputFormatsMap,
+                    listHighResolution, /*enforceImplementationDefined*/ true);
     }
 
     /**
@@ -131,6 +135,9 @@
             StreamConfiguration[] depthConfigurations,
             StreamConfigurationDuration[] depthMinFrameDurations,
             StreamConfigurationDuration[] depthStallDurations,
+            StreamConfiguration[] dynamicDepthConfigurations,
+            StreamConfigurationDuration[] dynamicDepthMinFrameDurations,
+            StreamConfigurationDuration[] dynamicDepthStallDurations,
             HighSpeedVideoConfiguration[] highSpeedVideoConfigurations,
             ReprocessFormatsMap inputOutputFormatsMap,
             boolean listHighResolution,
@@ -163,6 +170,19 @@
                     "depthStallDurations");
         }
 
+        if (dynamicDepthConfigurations == null) {
+            mDynamicDepthConfigurations = new StreamConfiguration[0];
+            mDynamicDepthMinFrameDurations = new StreamConfigurationDuration[0];
+            mDynamicDepthStallDurations = new StreamConfigurationDuration[0];
+        } else {
+            mDynamicDepthConfigurations = checkArrayElementsNotNull(dynamicDepthConfigurations,
+                    "dynamicDepthConfigurations");
+            mDynamicDepthMinFrameDurations = checkArrayElementsNotNull(
+                    dynamicDepthMinFrameDurations, "dynamicDepthMinFrameDurations");
+            mDynamicDepthStallDurations = checkArrayElementsNotNull(dynamicDepthStallDurations,
+                    "dynamicDepthStallDurations");
+        }
+
         if (highSpeedVideoConfigurations == null) {
             mHighSpeedVideoConfigurations = new HighSpeedVideoConfiguration[0];
         } else {
@@ -205,6 +225,15 @@
             mDepthOutputFormats.put(config.getFormat(),
                     mDepthOutputFormats.get(config.getFormat()) + 1);
         }
+        for (StreamConfiguration config : mDynamicDepthConfigurations) {
+            if (!config.isOutput()) {
+                // Ignoring input configs
+                continue;
+            }
+
+            mDynamicDepthOutputFormats.put(config.getFormat(),
+                    mDynamicDepthOutputFormats.get(config.getFormat()) + 1);
+        }
 
         if (configurations != null && enforceImplementationDefined &&
                 mOutputFormats.indexOfKey(HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED) < 0) {
@@ -335,6 +364,8 @@
         int dataspace = imageFormatToDataspace(format);
         if (dataspace == HAL_DATASPACE_DEPTH) {
             return mDepthOutputFormats.indexOfKey(internalFormat) >= 0;
+        } else if (dataspace == HAL_DATASPACE_DYNAMIC_DEPTH) {
+            return mDynamicDepthOutputFormats.indexOfKey(internalFormat) >= 0;
         } else {
             return getFormatsMap(/*output*/true).indexOfKey(internalFormat) >= 0;
         }
@@ -446,7 +477,9 @@
         boolean isFlexible = SurfaceUtils.isFlexibleConsumer(surface);
 
         StreamConfiguration[] configs =
-                surfaceDataspace != HAL_DATASPACE_DEPTH ? mConfigurations : mDepthConfigurations;
+                surfaceDataspace == HAL_DATASPACE_DEPTH ? mDepthConfigurations :
+                surfaceDataspace == HAL_DATASPACE_DYNAMIC_DEPTH ? mDynamicDepthConfigurations :
+                mConfigurations;
         for (StreamConfiguration config : configs) {
             if (config.getFormat() == surfaceFormat && config.isOutput()) {
                 // Matching format, either need exact size match, or a flexible consumer
@@ -479,7 +512,9 @@
         int dataspace = imageFormatToDataspace(format);
 
         StreamConfiguration[] configs =
-            dataspace != HAL_DATASPACE_DEPTH ? mConfigurations : mDepthConfigurations;
+            dataspace == HAL_DATASPACE_DEPTH ? mDepthConfigurations :
+            dataspace == HAL_DATASPACE_DYNAMIC_DEPTH ? mDynamicDepthConfigurations :
+            mConfigurations;
         for (StreamConfiguration config : configs) {
             if ((config.getFormat() == internalFormat) && config.isOutput() &&
                     config.getSize().equals(size)) {
@@ -992,6 +1027,12 @@
                     Arrays.equals(mMinFrameDurations, other.mMinFrameDurations) &&
                     Arrays.equals(mStallDurations, other.mStallDurations) &&
                     Arrays.equals(mDepthConfigurations, other.mDepthConfigurations) &&
+                    Arrays.equals(mDepthMinFrameDurations, other.mDepthMinFrameDurations) &&
+                    Arrays.equals(mDepthStallDurations, other.mDepthStallDurations) &&
+                    Arrays.equals(mDynamicDepthConfigurations, other.mDynamicDepthConfigurations) &&
+                    Arrays.equals(mDynamicDepthMinFrameDurations,
+                            other.mDynamicDepthMinFrameDurations) &&
+                    Arrays.equals(mDynamicDepthStallDurations, other.mDynamicDepthStallDurations) &&
                     Arrays.equals(mHighSpeedVideoConfigurations,
                             other.mHighSpeedVideoConfigurations);
         }
@@ -1005,9 +1046,10 @@
     public int hashCode() {
         // XX: do we care about order?
         return HashCodeHelpers.hashCodeGeneric(
-                mConfigurations, mMinFrameDurations,
-                mStallDurations,
-                mDepthConfigurations, mHighSpeedVideoConfigurations);
+                mConfigurations, mMinFrameDurations, mStallDurations,
+                mDepthConfigurations, mDepthMinFrameDurations, mDepthStallDurations,
+                mDynamicDepthConfigurations, mDynamicDepthMinFrameDurations,
+                mDynamicDepthStallDurations, mHighSpeedVideoConfigurations);
     }
 
     // Check that the argument is supported by #getOutputFormats or #getInputFormats
@@ -1022,6 +1064,10 @@
                 if (mDepthOutputFormats.indexOfKey(internalFormat) >= 0) {
                     return format;
                 }
+            } else if (internalDataspace == HAL_DATASPACE_DYNAMIC_DEPTH) {
+                if (mDynamicDepthOutputFormats.indexOfKey(internalFormat) >= 0) {
+                    return format;
+                }
             } else {
                 if (mAllOutputFormats.indexOfKey(internalFormat) >= 0) {
                     return format;
@@ -1245,6 +1291,7 @@
         switch (format) {
             case ImageFormat.JPEG:
             case ImageFormat.DEPTH_POINT_CLOUD:
+            case ImageFormat.DEPTH_JPEG:
                 return HAL_PIXEL_FORMAT_BLOB;
             case ImageFormat.DEPTH16:
                 return HAL_PIXEL_FORMAT_Y16;
@@ -1264,6 +1311,7 @@
      * <li>ImageFormat.JPEG => HAL_DATASPACE_V0_JFIF
      * <li>ImageFormat.DEPTH_POINT_CLOUD => HAL_DATASPACE_DEPTH
      * <li>ImageFormat.DEPTH16 => HAL_DATASPACE_DEPTH
+     * <li>ImageFormat.DEPTH_JPEG => HAL_DATASPACE_DYNAMIC_DEPTH
      * <li>others => HAL_DATASPACE_UNKNOWN
      * </ul>
      * </p>
@@ -1293,6 +1341,8 @@
             case ImageFormat.DEPTH16:
             case ImageFormat.RAW_DEPTH:
                 return HAL_DATASPACE_DEPTH;
+            case ImageFormat.DEPTH_JPEG:
+                return HAL_DATASPACE_DYNAMIC_DEPTH;
             default:
                 return HAL_DATASPACE_UNKNOWN;
         }
@@ -1343,12 +1393,16 @@
         SparseIntArray formatsMap =
                 !output ? mInputFormats :
                 dataspace == HAL_DATASPACE_DEPTH ? mDepthOutputFormats :
+                dataspace == HAL_DATASPACE_DYNAMIC_DEPTH ? mDynamicDepthOutputFormats :
                 highRes ? mHighResOutputFormats :
                 mOutputFormats;
 
         int sizesCount = formatsMap.get(format);
-        if ( ((!output || dataspace == HAL_DATASPACE_DEPTH) && sizesCount == 0) ||
-                (output && dataspace != HAL_DATASPACE_DEPTH && mAllOutputFormats.get(format) == 0)) {
+        if ( ((!output || (dataspace == HAL_DATASPACE_DEPTH ||
+                            dataspace == HAL_DATASPACE_DYNAMIC_DEPTH)) && sizesCount == 0) ||
+                (output && (dataspace != HAL_DATASPACE_DEPTH &&
+                            dataspace != HAL_DATASPACE_DYNAMIC_DEPTH) &&
+                 mAllOutputFormats.get(format) == 0)) {
             // Only throw if this is really not supported at all
             throw new IllegalArgumentException("format not available");
         }
@@ -1357,9 +1411,13 @@
         int sizeIndex = 0;
 
         StreamConfiguration[] configurations =
-                (dataspace == HAL_DATASPACE_DEPTH) ? mDepthConfigurations : mConfigurations;
+                (dataspace == HAL_DATASPACE_DEPTH) ? mDepthConfigurations :
+                (dataspace == HAL_DATASPACE_DYNAMIC_DEPTH) ? mDynamicDepthConfigurations :
+                mConfigurations;
         StreamConfigurationDuration[] minFrameDurations =
-                (dataspace == HAL_DATASPACE_DEPTH) ? mDepthMinFrameDurations : mMinFrameDurations;
+                (dataspace == HAL_DATASPACE_DEPTH) ? mDepthMinFrameDurations :
+                (dataspace == HAL_DATASPACE_DYNAMIC_DEPTH) ? mDynamicDepthMinFrameDurations :
+                mMinFrameDurations;
 
         for (StreamConfiguration config : configurations) {
             int fmt = config.getFormat();
@@ -1386,7 +1444,21 @@
             }
         }
 
-        if (sizeIndex != sizesCount) {
+        // Dynamic depth streams can have both fast and also high res modes.
+        if ((sizeIndex != sizesCount) && (dataspace == HAL_DATASPACE_DYNAMIC_DEPTH)) {
+
+            if (sizeIndex > sizesCount) {
+                throw new AssertionError(
+                        "Too many dynamic depth sizes (expected " + sizesCount + ", actual " +
+                        sizeIndex + ")");
+            }
+
+            if (sizeIndex <= 0) {
+                sizes = new Size[0];
+            } else {
+                sizes = Arrays.copyOf(sizes, sizeIndex);
+            }
+        } else if (sizeIndex != sizesCount) {
             throw new AssertionError(
                     "Too few sizes (expected " + sizesCount + ", actual " + sizeIndex + ")");
         }
@@ -1409,6 +1481,10 @@
             for (int j = 0; j < mDepthOutputFormats.size(); j++) {
                 formats[i++] = depthFormatToPublic(mDepthOutputFormats.keyAt(j));
             }
+            if (mDynamicDepthOutputFormats.size() > 0) {
+                // Only one publicly dynamic depth format is available.
+                formats[i++] = ImageFormat.DEPTH_JPEG;
+            }
         }
         if (formats.length != i) {
             throw new AssertionError("Too few formats " + i + ", expected " + formats.length);
@@ -1451,11 +1527,13 @@
     private StreamConfigurationDuration[] getDurations(int duration, int dataspace) {
         switch (duration) {
             case DURATION_MIN_FRAME:
-                return (dataspace == HAL_DATASPACE_DEPTH) ?
-                        mDepthMinFrameDurations : mMinFrameDurations;
+                return (dataspace == HAL_DATASPACE_DEPTH) ? mDepthMinFrameDurations :
+                        (dataspace == HAL_DATASPACE_DYNAMIC_DEPTH) ?
+                        mDynamicDepthMinFrameDurations : mMinFrameDurations;
             case DURATION_STALL:
-                return (dataspace == HAL_DATASPACE_DEPTH) ?
-                        mDepthStallDurations : mStallDurations;
+                return (dataspace == HAL_DATASPACE_DEPTH) ? mDepthStallDurations :
+                        (dataspace == HAL_DATASPACE_DYNAMIC_DEPTH) ? mDynamicDepthStallDurations :
+                        mStallDurations;
             default:
                 throw new IllegalArgumentException("duration was invalid");
         }
@@ -1467,6 +1545,7 @@
         int size = formatsMap.size();
         if (output) {
             size += mDepthOutputFormats.size();
+            size += mDynamicDepthOutputFormats.size();
         }
 
         return size;
@@ -1486,10 +1565,11 @@
         return false;
     }
 
-    private boolean isSupportedInternalConfiguration(int format, int dataspace,
-            Size size) {
+    private boolean isSupportedInternalConfiguration(int format, int dataspace, Size size) {
         StreamConfiguration[] configurations =
-                (dataspace == HAL_DATASPACE_DEPTH) ? mDepthConfigurations : mConfigurations;
+                (dataspace == HAL_DATASPACE_DEPTH) ? mDepthConfigurations :
+                (dataspace == HAL_DATASPACE_DYNAMIC_DEPTH) ? mDynamicDepthConfigurations :
+                mConfigurations;
 
         for (int i = 0; i < configurations.length; i++) {
             if (configurations[i].getFormat() == format &&
@@ -1681,6 +1761,8 @@
                 return "DEPTH16";
             case ImageFormat.DEPTH_POINT_CLOUD:
                 return "DEPTH_POINT_CLOUD";
+            case ImageFormat.DEPTH_JPEG:
+                return "DEPTH_JPEG";
             case ImageFormat.RAW_DEPTH:
                 return "RAW_DEPTH";
             case ImageFormat.PRIVATE:
@@ -1712,6 +1794,7 @@
             (1 << HAL_DATASPACE_RANGE_SHIFT);
 
     private static final int HAL_DATASPACE_DEPTH = 0x1000;
+    private static final int HAL_DATASPACE_DYNAMIC_DEPTH = 0x1002;
 
     private static final long DURATION_20FPS_NS = 50000000L;
     /**
@@ -1728,6 +1811,10 @@
     private final StreamConfigurationDuration[] mDepthMinFrameDurations;
     private final StreamConfigurationDuration[] mDepthStallDurations;
 
+    private final StreamConfiguration[] mDynamicDepthConfigurations;
+    private final StreamConfigurationDuration[] mDynamicDepthMinFrameDurations;
+    private final StreamConfigurationDuration[] mDynamicDepthStallDurations;
+
     private final HighSpeedVideoConfiguration[] mHighSpeedVideoConfigurations;
     private final ReprocessFormatsMap mInputOutputFormatsMap;
 
@@ -1745,6 +1832,8 @@
     private final SparseIntArray mInputFormats = new SparseIntArray();
     /** internal format -> num depth output sizes mapping, for HAL_DATASPACE_DEPTH */
     private final SparseIntArray mDepthOutputFormats = new SparseIntArray();
+    /** internal format -> num dynamic depth output sizes mapping, for HAL_DATASPACE_DYNAMIC_DEPTH */
+    private final SparseIntArray mDynamicDepthOutputFormats = new SparseIntArray();
     /** High speed video Size -> FPS range count mapping*/
     private final HashMap</*HighSpeedVideoSize*/Size, /*Count*/Integer> mHighSpeedVideoSizeMap =
             new HashMap<Size, Integer>();
diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java
index 5b3ad77..333cfbd 100644
--- a/core/java/android/inputmethodservice/InputMethodService.java
+++ b/core/java/android/inputmethodservice/InputMethodService.java
@@ -597,6 +597,7 @@
                     Log.v(TAG, "Making IME window invisible");
                 }
                 setImeWindowStatus(IME_ACTIVE | IME_INVISIBLE, mBackDisposition);
+                applyVisibilityInInsetsConsumer(false /* setVisible */);
                 onPreRenderedWindowVisibilityChanged(false /* setVisible */);
             } else {
                 mShowInputFlags = 0;
@@ -625,10 +626,10 @@
                     ? mDecorViewVisible && mWindowVisible : isInputViewShown();
             if (dispatchOnShowInputRequested(flags, false)) {
                 if (mIsPreRendered) {
-                    // TODO: notify visibility to insets consumer.
                     if (DEBUG) {
                         Log.v(TAG, "Making IME window visible");
                     }
+                    applyVisibilityInInsetsConsumer(true /* setVisible */);
                     onPreRenderedWindowVisibilityChanged(true /* setVisible */);
                 } else {
                     showWindow(true);
@@ -1887,10 +1888,23 @@
             if (DEBUG) Log.v(TAG, "showWindow: draw decorView!");
             mWindow.show();
         }
+        maybeNotifyPreRendered();
         mDecorViewWasVisible = true;
         mInShowWindow = false;
     }
 
+    /**
+     * Notify {@link android.view.ImeInsetsSourceConsumer} if IME has been pre-rendered
+     * for current EditorInfo, when pre-rendering is enabled.
+     */
+    private void maybeNotifyPreRendered() {
+        if (!mCanPreRender || !mIsPreRendered) {
+            return;
+        }
+        mPrivOps.reportPreRendered(getCurrentInputEditorInfo());
+    }
+
+
     private boolean prepareWindow(boolean showInput) {
         boolean doShowInput = false;
         mDecorViewVisible = true;
@@ -1942,6 +1956,18 @@
         }
     }
 
+    /**
+     * Apply the IME visibility in {@link android.view.ImeInsetsSourceConsumer} when
+     * pre-rendering is enabled.
+     * @param setVisible {@code true} to make it visible, false to hide it.
+     */
+    private void applyVisibilityInInsetsConsumer(boolean setVisible) {
+        if (!mIsPreRendered) {
+            return;
+        }
+        mPrivOps.applyImeVisibility(setVisible);
+    }
+
     private void finishViews(boolean finishingInput) {
         if (mInputViewStarted) {
             if (DEBUG) Log.v(TAG, "CALL: onFinishInputView");
@@ -2081,6 +2107,7 @@
             // When IME is not pre-rendered, this will actually show the IME.
             if (DEBUG) Log.v(TAG, "showWindow: draw decorView!");
             mWindow.show();
+            maybeNotifyPreRendered();
             mDecorViewWasVisible = true;
             mInShowWindow = false;
         } else {
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index 5bb24ba..3bae12e 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -1014,20 +1014,54 @@
      *                   to remove an existing always-on VPN configuration.
      * @param lockdownEnabled {@code true} to disallow networking when the VPN is not connected or
      *        {@code false} otherwise.
+     * @param lockdownWhitelist The list of packages that are allowed to access network directly
+     *         when VPN is in lockdown mode but is not running. Non-existent packages are ignored so
+     *         this method must be called when a package that should be whitelisted is installed or
+     *         uninstalled.
      * @return {@code true} if the package is set as always-on VPN controller;
      *         {@code false} otherwise.
      * @hide
      */
+    @RequiresPermission(android.Manifest.permission.CONTROL_ALWAYS_ON_VPN)
     public boolean setAlwaysOnVpnPackageForUser(int userId, @Nullable String vpnPackage,
-            boolean lockdownEnabled) {
+            boolean lockdownEnabled, @Nullable List<String> lockdownWhitelist) {
         try {
-            return mService.setAlwaysOnVpnPackage(userId, vpnPackage, lockdownEnabled);
+            return mService.setAlwaysOnVpnPackage(
+                    userId, vpnPackage, lockdownEnabled, lockdownWhitelist);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
     }
 
     /**
+     * Configures an always-on VPN connection through a specific application.
+     * This connection is automatically granted and persisted after a reboot.
+     *
+     * <p>The designated package should declare a {@link VpnService} in its
+     *    manifest guarded by {@link android.Manifest.permission.BIND_VPN_SERVICE},
+     *    otherwise the call will fail.
+     *
+     * @param userId The identifier of the user to set an always-on VPN for.
+     * @param vpnPackage The package name for an installed VPN app on the device, or {@code null}
+     *                   to remove an existing always-on VPN configuration.
+     * @param lockdownEnabled {@code true} to disallow networking when the VPN is not connected or
+     *        {@code false} otherwise.
+     * @return {@code true} if the package is set as always-on VPN controller;
+     *         {@code false} otherwise.
+     * @hide
+     */
+    @RequiresPermission(android.Manifest.permission.CONTROL_ALWAYS_ON_VPN)
+    public boolean setAlwaysOnVpnPackageForUser(int userId, @Nullable String vpnPackage,
+            boolean lockdownEnabled) {
+        try {
+            return mService.setAlwaysOnVpnPackage(
+                    userId, vpnPackage, lockdownEnabled, /* whitelist */ null);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+   /**
      * Returns the package name of the currently set always-on VPN application.
      * If there is no always-on VPN set, or the VPN is provided by the system instead
      * of by an app, {@code null} will be returned.
@@ -1036,6 +1070,7 @@
      *         or {@code null} if none is set.
      * @hide
      */
+    @RequiresPermission(android.Manifest.permission.CONTROL_ALWAYS_ON_VPN)
     public String getAlwaysOnVpnPackageForUser(int userId) {
         try {
             return mService.getAlwaysOnVpnPackage(userId);
@@ -1045,6 +1080,36 @@
     }
 
     /**
+     * @return whether always-on VPN is in lockdown mode.
+     *
+     * @hide
+     **/
+    @RequiresPermission(android.Manifest.permission.CONTROL_ALWAYS_ON_VPN)
+    public boolean isVpnLockdownEnabled(int userId) {
+        try {
+            return mService.isVpnLockdownEnabled(userId);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+
+    }
+
+    /**
+     * @return the list of packages that are allowed to access network when always-on VPN is in
+     * lockdown mode but not connected. Returns {@code null} when VPN lockdown is not active.
+     *
+     * @hide
+     **/
+    @RequiresPermission(android.Manifest.permission.CONTROL_ALWAYS_ON_VPN)
+    public List<String> getVpnLockdownWhitelist(int userId) {
+        try {
+            return mService.getVpnLockdownWhitelist(userId);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
      * Returns details about the currently active default data network
      * for a given uid.  This is for internal use only to avoid spying
      * other apps.
diff --git a/core/java/android/net/DhcpResults.java b/core/java/android/net/DhcpResults.java
index b5d8226..6c291c2 100644
--- a/core/java/android/net/DhcpResults.java
+++ b/core/java/android/net/DhcpResults.java
@@ -17,24 +17,39 @@
 package android.net;
 
 import android.annotation.UnsupportedAppUsage;
-import android.net.NetworkUtils;
 import android.os.Parcel;
+import android.os.Parcelable;
 import android.text.TextUtils;
 import android.util.Log;
 
 import java.net.Inet4Address;
+import java.net.InetAddress;
+import java.util.ArrayList;
+import java.util.List;
 import java.util.Objects;
 
 /**
  * A simple object for retrieving the results of a DHCP request.
  * Optimized (attempted) for that jni interface
- * TODO - remove when DhcpInfo is deprecated.  Move the remaining api to LinkProperties.
+ * TODO: remove this class and replace with other existing constructs
  * @hide
  */
-public class DhcpResults extends StaticIpConfiguration {
+public final class DhcpResults implements Parcelable {
     private static final String TAG = "DhcpResults";
 
     @UnsupportedAppUsage
+    public LinkAddress ipAddress;
+
+    @UnsupportedAppUsage
+    public InetAddress gateway;
+
+    @UnsupportedAppUsage
+    public final ArrayList<InetAddress> dnsServers = new ArrayList<>();
+
+    @UnsupportedAppUsage
+    public String domains;
+
+    @UnsupportedAppUsage
     public Inet4Address serverAddress;
 
     /** Vendor specific information (from RFC 2132). */
@@ -48,23 +63,36 @@
     @UnsupportedAppUsage
     public int mtu;
 
-    @UnsupportedAppUsage
     public DhcpResults() {
         super();
     }
 
-    @UnsupportedAppUsage
+    /**
+     * Create a {@link StaticIpConfiguration} based on the DhcpResults.
+     */
+    public StaticIpConfiguration toStaticIpConfiguration() {
+        final StaticIpConfiguration s = new StaticIpConfiguration();
+        // All these except dnsServers are immutable, so no need to make copies.
+        s.ipAddress = ipAddress;
+        s.gateway = gateway;
+        s.dnsServers.addAll(dnsServers);
+        s.domains = domains;
+        return s;
+    }
+
     public DhcpResults(StaticIpConfiguration source) {
-        super(source);
+        if (source != null) {
+            ipAddress = source.ipAddress;
+            gateway = source.gateway;
+            dnsServers.addAll(source.dnsServers);
+            domains = source.domains;
+        }
     }
 
     /** copy constructor */
-    @UnsupportedAppUsage
     public DhcpResults(DhcpResults source) {
-        super(source);
-
+        this(source == null ? null : source.toStaticIpConfiguration());
         if (source != null) {
-            // All these are immutable, so no need to make copies.
             serverAddress = source.serverAddress;
             vendorInfo = source.vendorInfo;
             leaseDuration = source.leaseDuration;
@@ -73,6 +101,14 @@
     }
 
     /**
+     * @see StaticIpConfiguration#getRoutes(String)
+     * @hide
+     */
+    public List<RouteInfo> getRoutes(String iface) {
+        return toStaticIpConfiguration().getRoutes(iface);
+    }
+
+    /**
      * Test if this DHCP lease includes vendor hint that network link is
      * metered, and sensitive to heavy data transfers.
      */
@@ -85,7 +121,11 @@
     }
 
     public void clear() {
-        super.clear();
+        ipAddress = null;
+        gateway = null;
+        dnsServers.clear();
+        domains = null;
+        serverAddress = null;
         vendorInfo = null;
         leaseDuration = 0;
         mtu = 0;
@@ -111,20 +151,20 @@
 
         DhcpResults target = (DhcpResults)obj;
 
-        return super.equals((StaticIpConfiguration) obj) &&
-                Objects.equals(serverAddress, target.serverAddress) &&
-                Objects.equals(vendorInfo, target.vendorInfo) &&
-                leaseDuration == target.leaseDuration &&
-                mtu == target.mtu;
+        return toStaticIpConfiguration().equals(target.toStaticIpConfiguration())
+                && Objects.equals(serverAddress, target.serverAddress)
+                && Objects.equals(vendorInfo, target.vendorInfo)
+                && leaseDuration == target.leaseDuration
+                && mtu == target.mtu;
     }
 
-    /** Implement the Parcelable interface */
+    /**
+     * Implement the Parcelable interface
+     */
     public static final Creator<DhcpResults> CREATOR =
         new Creator<DhcpResults>() {
             public DhcpResults createFromParcel(Parcel in) {
-                DhcpResults dhcpResults = new DhcpResults();
-                readFromParcel(dhcpResults, in);
-                return dhcpResults;
+                return readFromParcel(in);
             }
 
             public DhcpResults[] newArray(int size) {
@@ -134,19 +174,26 @@
 
     /** Implement the Parcelable interface */
     public void writeToParcel(Parcel dest, int flags) {
-        super.writeToParcel(dest, flags);
+        toStaticIpConfiguration().writeToParcel(dest, flags);
         dest.writeInt(leaseDuration);
         dest.writeInt(mtu);
         NetworkUtils.parcelInetAddress(dest, serverAddress, flags);
         dest.writeString(vendorInfo);
     }
 
-    private static void readFromParcel(DhcpResults dhcpResults, Parcel in) {
-        StaticIpConfiguration.readFromParcel(dhcpResults, in);
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    private static DhcpResults readFromParcel(Parcel in) {
+        final StaticIpConfiguration s = StaticIpConfiguration.CREATOR.createFromParcel(in);
+        final DhcpResults dhcpResults = new DhcpResults(s);
         dhcpResults.leaseDuration = in.readInt();
         dhcpResults.mtu = in.readInt();
         dhcpResults.serverAddress = (Inet4Address) NetworkUtils.unparcelInetAddress(in);
         dhcpResults.vendorInfo = in.readString();
+        return dhcpResults;
     }
 
     // Utils for jni population - false on success
@@ -184,25 +231,70 @@
         return false;
     }
 
-    public boolean setServerAddress(String addrString) {
-        try {
-            serverAddress = (Inet4Address) NetworkUtils.numericToInetAddress(addrString);
-        } catch (IllegalArgumentException|ClassCastException e) {
-            Log.e(TAG, "setServerAddress failed with addrString " + addrString);
-            return true;
-        }
-        return false;
+    public LinkAddress getIpAddress() {
+        return ipAddress;
+    }
+
+    public void setIpAddress(LinkAddress ipAddress) {
+        this.ipAddress = ipAddress;
+    }
+
+    public InetAddress getGateway() {
+        return gateway;
+    }
+
+    public void setGateway(InetAddress gateway) {
+        this.gateway = gateway;
+    }
+
+    public List<InetAddress> getDnsServers() {
+        return dnsServers;
+    }
+
+    /**
+     * Add a DNS server to this configuration.
+     */
+    public void addDnsServer(InetAddress server) {
+        dnsServers.add(server);
+    }
+
+    public String getDomains() {
+        return domains;
+    }
+
+    public void setDomains(String domains) {
+        this.domains = domains;
+    }
+
+    public Inet4Address getServerAddress() {
+        return serverAddress;
+    }
+
+    public void setServerAddress(Inet4Address addr) {
+        serverAddress = addr;
+    }
+
+    public int getLeaseDuration() {
+        return leaseDuration;
     }
 
     public void setLeaseDuration(int duration) {
         leaseDuration = duration;
     }
 
+    public String getVendorInfo() {
+        return vendorInfo;
+    }
+
     public void setVendorInfo(String info) {
         vendorInfo = info;
     }
 
-    public void setDomains(String newDomains) {
-        domains = newDomains;
+    public int getMtu() {
+        return mtu;
+    }
+
+    public void setMtu(int mtu) {
+        this.mtu = mtu;
     }
 }
diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl
index e97060a..fd7360f 100644
--- a/core/java/android/net/IConnectivityManager.aidl
+++ b/core/java/android/net/IConnectivityManager.aidl
@@ -125,8 +125,11 @@
 
     boolean updateLockdownVpn();
     boolean isAlwaysOnVpnPackageSupported(int userId, String packageName);
-    boolean setAlwaysOnVpnPackage(int userId, String packageName, boolean lockdown);
+    boolean setAlwaysOnVpnPackage(int userId, String packageName, boolean lockdown,
+            in List<String> lockdownWhitelist);
     String getAlwaysOnVpnPackage(int userId);
+    boolean isVpnLockdownEnabled(int userId);
+    List<String> getVpnLockdownWhitelist(int userId);
 
     int checkMobileProvisioning(int suggestedTimeOutMs);
 
diff --git a/core/java/android/net/IpSecTransform.java b/core/java/android/net/IpSecTransform.java
index 23c8aa3..e519fdf 100644
--- a/core/java/android/net/IpSecTransform.java
+++ b/core/java/android/net/IpSecTransform.java
@@ -257,7 +257,6 @@
      *
      * @hide
      */
-    @SystemApi
     public static class NattKeepaliveCallback {
         /** The specified {@code Network} is not connected. */
         public static final int ERROR_INVALID_NETWORK = 1;
@@ -288,7 +287,6 @@
      *
      * @hide
      */
-    @SystemApi
     @RequiresPermission(anyOf = {
             android.Manifest.permission.MANAGE_IPSEC_TUNNELS,
             android.Manifest.permission.PACKET_KEEPALIVE_OFFLOAD
@@ -331,7 +329,6 @@
      *
      * @hide
      */
-    @SystemApi
     @RequiresPermission(anyOf = {
             android.Manifest.permission.MANAGE_IPSEC_TUNNELS,
             android.Manifest.permission.PACKET_KEEPALIVE_OFFLOAD
diff --git a/core/java/android/net/NetworkUtils.java b/core/java/android/net/NetworkUtils.java
index c996d01..39db4fe 100644
--- a/core/java/android/net/NetworkUtils.java
+++ b/core/java/android/net/NetworkUtils.java
@@ -21,8 +21,10 @@
 
 import android.annotation.NonNull;
 import android.annotation.UnsupportedAppUsage;
+import android.net.shared.Inet4AddressUtils;
 import android.os.Build;
 import android.os.Parcel;
+import android.system.ErrnoException;
 import android.system.Os;
 import android.util.Log;
 import android.util.Pair;
@@ -39,8 +41,6 @@
 import java.util.Locale;
 import java.util.TreeSet;
 
-import android.system.ErrnoException;
-
 /**
  * Native methods for managing network interfaces.
  *
@@ -177,119 +177,37 @@
             FileDescriptor fd) throws IOException;
 
     /**
-     * @see #intToInet4AddressHTL(int)
-     * @deprecated Use either {@link #intToInet4AddressHTH(int)}
-     *             or {@link #intToInet4AddressHTL(int)}
+     * @see Inet4AddressUtils#intToInet4AddressHTL(int)
+     * @deprecated Use either {@link Inet4AddressUtils#intToInet4AddressHTH(int)}
+     *             or {@link Inet4AddressUtils#intToInet4AddressHTL(int)}
      */
     @Deprecated
     @UnsupportedAppUsage
     public static InetAddress intToInetAddress(int hostAddress) {
-        return intToInet4AddressHTL(hostAddress);
+        return Inet4AddressUtils.intToInet4AddressHTL(hostAddress);
     }
 
     /**
-     * Convert a IPv4 address from an integer to an InetAddress (0x04030201 -> 1.2.3.4)
-     *
-     * <p>This method uses the higher-order int bytes as the lower-order IPv4 address bytes,
-     * which is an unusual convention. Consider {@link #intToInet4AddressHTH(int)} instead.
-     * @param hostAddress an int coding for an IPv4 address, where higher-order int byte is
-     *                    lower-order IPv4 address byte
-     */
-    public static Inet4Address intToInet4AddressHTL(int hostAddress) {
-        return intToInet4AddressHTH(Integer.reverseBytes(hostAddress));
-    }
-
-    /**
-     * Convert a IPv4 address from an integer to an InetAddress (0x01020304 -> 1.2.3.4)
-     * @param hostAddress an int coding for an IPv4 address
-     */
-    public static Inet4Address intToInet4AddressHTH(int hostAddress) {
-        byte[] addressBytes = { (byte) (0xff & (hostAddress >> 24)),
-                (byte) (0xff & (hostAddress >> 16)),
-                (byte) (0xff & (hostAddress >> 8)),
-                (byte) (0xff & hostAddress) };
-
-        try {
-            return (Inet4Address) InetAddress.getByAddress(addressBytes);
-        } catch (UnknownHostException e) {
-            throw new AssertionError();
-        }
-    }
-
-    /**
-     * @see #inet4AddressToIntHTL(Inet4Address)
-     * @deprecated Use either {@link #inet4AddressToIntHTH(Inet4Address)}
-     *             or {@link #inet4AddressToIntHTL(Inet4Address)}
+     * @see Inet4AddressUtils#inet4AddressToIntHTL(Inet4Address)
+     * @deprecated Use either {@link Inet4AddressUtils#inet4AddressToIntHTH(Inet4Address)}
+     *             or {@link Inet4AddressUtils#inet4AddressToIntHTL(Inet4Address)}
      */
     @Deprecated
     public static int inetAddressToInt(Inet4Address inetAddr)
             throws IllegalArgumentException {
-        return inet4AddressToIntHTL(inetAddr);
+        return Inet4AddressUtils.inet4AddressToIntHTL(inetAddr);
     }
 
     /**
-     * Convert an IPv4 address from an InetAddress to an integer (1.2.3.4 -> 0x01020304)
-     *
-     * <p>This conversion can help order IP addresses: considering the ordering
-     * 192.0.2.1 < 192.0.2.2 < ..., resulting ints will follow that ordering if read as unsigned
-     * integers with {@link Integer#toUnsignedLong}.
-     * @param inetAddr is an InetAddress corresponding to the IPv4 address
-     * @return the IP address as integer
-     */
-    public static int inet4AddressToIntHTH(Inet4Address inetAddr)
-            throws IllegalArgumentException {
-        byte [] addr = inetAddr.getAddress();
-        return ((addr[0] & 0xff) << 24) | ((addr[1] & 0xff) << 16)
-                | ((addr[2] & 0xff) << 8) | (addr[3] & 0xff);
-    }
-
-    /**
-     * Convert a IPv4 address from an InetAddress to an integer (1.2.3.4 -> 0x04030201)
-     *
-     * <p>This method stores the higher-order IPv4 address bytes in the lower-order int bytes,
-     * which is an unusual convention. Consider {@link #inet4AddressToIntHTH(Inet4Address)} instead.
-     * @param inetAddr is an InetAddress corresponding to the IPv4 address
-     * @return the IP address as integer
-     */
-    public static int inet4AddressToIntHTL(Inet4Address inetAddr) {
-        return Integer.reverseBytes(inet4AddressToIntHTH(inetAddr));
-    }
-
-    /**
-     * @see #prefixLengthToV4NetmaskIntHTL(int)
-     * @deprecated Use either {@link #prefixLengthToV4NetmaskIntHTH(int)}
-     *             or {@link #prefixLengthToV4NetmaskIntHTL(int)}
+     * @see Inet4AddressUtils#prefixLengthToV4NetmaskIntHTL(int)
+     * @deprecated Use either {@link Inet4AddressUtils#prefixLengthToV4NetmaskIntHTH(int)}
+     *             or {@link Inet4AddressUtils#prefixLengthToV4NetmaskIntHTL(int)}
      */
     @Deprecated
     @UnsupportedAppUsage
     public static int prefixLengthToNetmaskInt(int prefixLength)
             throws IllegalArgumentException {
-        return prefixLengthToV4NetmaskIntHTL(prefixLength);
-    }
-
-    /**
-     * Convert a network prefix length to an IPv4 netmask integer (prefixLength 17 -> 0xffff8000)
-     * @return the IPv4 netmask as an integer
-     */
-    public static int prefixLengthToV4NetmaskIntHTH(int prefixLength)
-            throws IllegalArgumentException {
-        if (prefixLength < 0 || prefixLength > 32) {
-            throw new IllegalArgumentException("Invalid prefix length (0 <= prefix <= 32)");
-        }
-        // (int)a << b is equivalent to a << (b & 0x1f): can't shift by 32 (-1 << 32 == -1)
-        return prefixLength == 0 ? 0 : 0xffffffff << (32 - prefixLength);
-    }
-
-    /**
-     * Convert a network prefix length to an IPv4 netmask integer (prefixLength 17 -> 0x0080ffff).
-     *
-     * <p>This method stores the higher-order IPv4 address bytes in the lower-order int bytes,
-     * which is an unusual convention. Consider {@link #prefixLengthToV4NetmaskIntHTH(int)} instead.
-     * @return the IPv4 netmask as an integer
-     */
-    public static int prefixLengthToV4NetmaskIntHTL(int prefixLength)
-            throws IllegalArgumentException {
-        return Integer.reverseBytes(prefixLengthToV4NetmaskIntHTH(prefixLength));
+        return Inet4AddressUtils.prefixLengthToV4NetmaskIntHTL(prefixLength);
     }
 
     /**
@@ -307,17 +225,13 @@
      * @return the network prefix length
      * @throws IllegalArgumentException the specified netmask was not contiguous.
      * @hide
+     * @deprecated use {@link Inet4AddressUtils#netmaskToPrefixLength(Inet4Address)}
      */
     @UnsupportedAppUsage
+    @Deprecated
     public static int netmaskToPrefixLength(Inet4Address netmask) {
-        // inetAddressToInt returns an int in *network* byte order.
-        int i = Integer.reverseBytes(inetAddressToInt(netmask));
-        int prefixLength = Integer.bitCount(i);
-        int trailingZeros = Integer.numberOfTrailingZeros(i);
-        if (trailingZeros != 32 - prefixLength) {
-            throw new IllegalArgumentException("Non-contiguous netmask: " + Integer.toHexString(i));
-        }
-        return prefixLength;
+        // This is only here because some apps seem to be using it (@UnsupportedAppUsage).
+        return Inet4AddressUtils.netmaskToPrefixLength(netmask);
     }
 
 
@@ -408,16 +322,8 @@
      */
     @UnsupportedAppUsage
     public static int getImplicitNetmask(Inet4Address address) {
-        int firstByte = address.getAddress()[0] & 0xff;  // Convert to an unsigned value.
-        if (firstByte < 128) {
-            return 8;
-        } else if (firstByte < 192) {
-            return 16;
-        } else if (firstByte < 224) {
-            return 24;
-        } else {
-            return 32;  // Will likely not end well for other reasons.
-        }
+        // Only here because it seems to be used by apps
+        return Inet4AddressUtils.getImplicitNetmask(address);
     }
 
     /**
@@ -445,28 +351,6 @@
     }
 
     /**
-     * Get a prefix mask as Inet4Address for a given prefix length.
-     *
-     * <p>For example 20 -> 255.255.240.0
-     */
-    public static Inet4Address getPrefixMaskAsInet4Address(int prefixLength)
-            throws IllegalArgumentException {
-        return intToInet4AddressHTH(prefixLengthToV4NetmaskIntHTH(prefixLength));
-    }
-
-    /**
-     * Get the broadcast address for a given prefix.
-     *
-     * <p>For example 192.168.0.1/24 -> 192.168.0.255
-     */
-    public static Inet4Address getBroadcastAddress(Inet4Address addr, int prefixLength)
-            throws IllegalArgumentException {
-        final int intBroadcastAddr = inet4AddressToIntHTH(addr)
-                | ~prefixLengthToV4NetmaskIntHTH(prefixLength);
-        return intToInet4AddressHTH(intBroadcastAddr);
-    }
-
-    /**
      * Check if IP address type is consistent between two InetAddress.
      * @return true if both are the same type.  False otherwise.
      */
diff --git a/core/java/android/net/StaticIpConfiguration.java b/core/java/android/net/StaticIpConfiguration.java
index 3aa56b9..25bae3c 100644
--- a/core/java/android/net/StaticIpConfiguration.java
+++ b/core/java/android/net/StaticIpConfiguration.java
@@ -16,10 +16,11 @@
 
 package android.net;
 
+import android.annotation.SystemApi;
+import android.annotation.TestApi;
 import android.annotation.UnsupportedAppUsage;
-import android.net.LinkAddress;
-import android.os.Parcelable;
 import android.os.Parcel;
+import android.os.Parcelable;
 
 import java.net.InetAddress;
 import java.util.ArrayList;
@@ -46,17 +47,22 @@
  *
  * @hide
  */
-public class StaticIpConfiguration implements Parcelable {
+@SystemApi
+@TestApi
+public final class StaticIpConfiguration implements Parcelable {
+    /** @hide */
     @UnsupportedAppUsage
     public LinkAddress ipAddress;
+    /** @hide */
     @UnsupportedAppUsage
     public InetAddress gateway;
+    /** @hide */
     @UnsupportedAppUsage
     public final ArrayList<InetAddress> dnsServers;
+    /** @hide */
     @UnsupportedAppUsage
     public String domains;
 
-    @UnsupportedAppUsage
     public StaticIpConfiguration() {
         dnsServers = new ArrayList<InetAddress>();
     }
@@ -79,6 +85,41 @@
         domains = null;
     }
 
+    public LinkAddress getIpAddress() {
+        return ipAddress;
+    }
+
+    public void setIpAddress(LinkAddress ipAddress) {
+        this.ipAddress = ipAddress;
+    }
+
+    public InetAddress getGateway() {
+        return gateway;
+    }
+
+    public void setGateway(InetAddress gateway) {
+        this.gateway = gateway;
+    }
+
+    public List<InetAddress> getDnsServers() {
+        return dnsServers;
+    }
+
+    public String getDomains() {
+        return domains;
+    }
+
+    public void setDomains(String newDomains) {
+        domains = newDomains;
+    }
+
+    /**
+     * Add a DNS server to this configuration.
+     */
+    public void addDnsServer(InetAddress server) {
+        dnsServers.add(server);
+    }
+
     /**
      * Returns the network routes specified by this object. Will typically include a
      * directly-connected route for the IP address's local subnet and a default route. If the
@@ -86,7 +127,6 @@
      * 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.
      */
-    @UnsupportedAppUsage
     public List<RouteInfo> getRoutes(String iface) {
         List<RouteInfo> routes = new ArrayList<RouteInfo>(3);
         if (ipAddress != null) {
@@ -107,6 +147,7 @@
      * contained in the LinkProperties will not be a complete picture of the link's configuration,
      * because any configuration information that is obtained dynamically by the network (e.g.,
      * IPv6 configuration) will not be included.
+     * @hide
      */
     public LinkProperties toLinkProperties(String iface) {
         LinkProperties lp = new LinkProperties();
@@ -124,6 +165,7 @@
         return lp;
     }
 
+    @Override
     public String toString() {
         StringBuffer str = new StringBuffer();
 
@@ -143,6 +185,7 @@
         return str.toString();
     }
 
+    @Override
     public int hashCode() {
         int result = 13;
         result = 47 * result + (ipAddress == null ? 0 : ipAddress.hashCode());
@@ -168,12 +211,10 @@
     }
 
     /** Implement the Parcelable interface */
-    public static Creator<StaticIpConfiguration> CREATOR =
+    public static final Creator<StaticIpConfiguration> CREATOR =
         new Creator<StaticIpConfiguration>() {
             public StaticIpConfiguration createFromParcel(Parcel in) {
-                StaticIpConfiguration s = new StaticIpConfiguration();
-                readFromParcel(s, in);
-                return s;
+                return readFromParcel(in);
             }
 
             public StaticIpConfiguration[] newArray(int size) {
@@ -182,11 +223,13 @@
         };
 
     /** Implement the Parcelable interface */
+    @Override
     public int describeContents() {
         return 0;
     }
 
     /** Implement the Parcelable interface */
+    @Override
     public void writeToParcel(Parcel dest, int flags) {
         dest.writeParcelable(ipAddress, flags);
         NetworkUtils.parcelInetAddress(dest, gateway, flags);
@@ -197,7 +240,9 @@
         dest.writeString(domains);
     }
 
-    protected static void readFromParcel(StaticIpConfiguration s, Parcel in) {
+    /** @hide */
+    public static StaticIpConfiguration readFromParcel(Parcel in) {
+        final StaticIpConfiguration s = new StaticIpConfiguration();
         s.ipAddress = in.readParcelable(null);
         s.gateway = NetworkUtils.unparcelInetAddress(in);
         s.dnsServers.clear();
@@ -206,5 +251,6 @@
             s.dnsServers.add(NetworkUtils.unparcelInetAddress(in));
         }
         s.domains = in.readString();
+        return s;
     }
 }
diff --git a/core/java/android/net/TrafficStats.java b/core/java/android/net/TrafficStats.java
index bbf8f97..49c6f74 100644
--- a/core/java/android/net/TrafficStats.java
+++ b/core/java/android/net/TrafficStats.java
@@ -128,10 +128,14 @@
     public static final int TAG_SYSTEM_APP = 0xFFFFFF05;
 
     /** @hide */
+    @SystemApi
+    @TestApi
     public static final int TAG_SYSTEM_DHCP = 0xFFFFFF40;
     /** @hide */
     public static final int TAG_SYSTEM_NTP = 0xFFFFFF41;
     /** @hide */
+    @SystemApi
+    @TestApi
     public static final int TAG_SYSTEM_PROBE = 0xFFFFFF42;
     /** @hide */
     public static final int TAG_SYSTEM_NEIGHBOR = 0xFFFFFF43;
@@ -140,6 +144,8 @@
     /** @hide */
     public static final int TAG_SYSTEM_PAC = 0xFFFFFF45;
     /** @hide */
+    @SystemApi
+    @TestApi
     public static final int TAG_SYSTEM_DHCP_SERVER = 0xFFFFFF46;
 
     private static INetworkStatsService sStatsService;
diff --git a/core/java/android/net/apf/ApfCapabilities.java b/core/java/android/net/apf/ApfCapabilities.java
index f28cdc9..baf5585 100644
--- a/core/java/android/net/apf/ApfCapabilities.java
+++ b/core/java/android/net/apf/ApfCapabilities.java
@@ -16,11 +16,19 @@
 
 package android.net.apf;
 
+import android.annotation.SystemApi;
+import android.annotation.TestApi;
+import android.content.Context;
+
+import com.android.internal.R;
+
 /**
  * APF program support capabilities.
  *
  * @hide
  */
+@SystemApi
+@TestApi
 public class ApfCapabilities {
     /**
      * Version of APF instruction set supported for packet filtering. 0 indicates no support for
@@ -69,4 +77,18 @@
     public boolean hasDataAccess() {
         return apfVersionSupported >= 4;
     }
+
+    /**
+     * @return Whether the APF Filter in the device should filter out IEEE 802.3 Frames.
+     */
+    public boolean getApfDrop8023Frames(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 int[] getApfEthTypeBlackList(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 1634694..7432687 100644
--- a/core/java/android/net/captiveportal/CaptivePortalProbeResult.java
+++ b/core/java/android/net/captiveportal/CaptivePortalProbeResult.java
@@ -17,11 +17,15 @@
 package android.net.captiveportal;
 
 import android.annotation.Nullable;
+import android.annotation.SystemApi;
+import android.annotation.TestApi;
 
 /**
  * Result of calling isCaptivePortal().
  * @hide
  */
+@SystemApi
+@TestApi
 public final class CaptivePortalProbeResult {
     public static final int SUCCESS_CODE = 204;
     public static final int FAILED_CODE = 599;
diff --git a/core/java/android/net/captiveportal/CaptivePortalProbeSpec.java b/core/java/android/net/captiveportal/CaptivePortalProbeSpec.java
index 57a926a..7ad4ecf 100644
--- a/core/java/android/net/captiveportal/CaptivePortalProbeSpec.java
+++ b/core/java/android/net/captiveportal/CaptivePortalProbeSpec.java
@@ -21,21 +21,26 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.SystemApi;
+import android.annotation.TestApi;
 import android.text.TextUtils;
 import android.util.Log;
 
+import com.android.internal.annotations.VisibleForTesting;
+
 import java.net.MalformedURLException;
 import java.net.URL;
 import java.text.ParseException;
 import java.util.ArrayList;
+import java.util.Collection;
 import java.util.List;
 import java.util.regex.Pattern;
 import java.util.regex.PatternSyntaxException;
 
 /** @hide */
+@SystemApi
+@TestApi
 public abstract class CaptivePortalProbeSpec {
-    public static final String HTTP_LOCATION_HEADER_NAME = "Location";
-
     private static final String TAG = CaptivePortalProbeSpec.class.getSimpleName();
     private static final String REGEX_SEPARATOR = "@@/@@";
     private static final String SPEC_SEPARATOR = "@@,@@";
@@ -55,7 +60,9 @@
      * @throws MalformedURLException The URL has invalid format for {@link URL#URL(String)}.
      * @throws ParseException The string is empty, does not match the above format, or a regular
      * expression is invalid for {@link Pattern#compile(String)}.
+     * @hide
      */
+    @VisibleForTesting
     @NonNull
     public static CaptivePortalProbeSpec parseSpec(String spec) throws ParseException,
             MalformedURLException {
@@ -113,7 +120,8 @@
      * <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.
      */
-    public static CaptivePortalProbeSpec[] parseCaptivePortalProbeSpecs(String settingsVal) {
+    public static Collection<CaptivePortalProbeSpec> parseCaptivePortalProbeSpecs(
+            String settingsVal) {
         List<CaptivePortalProbeSpec> specs = new ArrayList<>();
         if (settingsVal != null) {
             for (String spec : TextUtils.split(settingsVal, SPEC_SEPARATOR)) {
@@ -128,7 +136,7 @@
         if (specs.isEmpty()) {
             Log.e(TAG, String.format("could not create any validation spec from %s", settingsVal));
         }
-        return specs.toArray(new CaptivePortalProbeSpec[specs.size()]);
+        return specs;
     }
 
     /**
diff --git a/core/java/android/net/shared/Inet4AddressUtils.java b/core/java/android/net/shared/Inet4AddressUtils.java
new file mode 100644
index 0000000..bec0c84
--- /dev/null
+++ b/core/java/android/net/shared/Inet4AddressUtils.java
@@ -0,0 +1,166 @@
+/*
+ * 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.shared;
+
+import java.net.Inet4Address;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+
+/**
+ * Collection of utilities to work with IPv4 addresses.
+ * @hide
+ */
+public class Inet4AddressUtils {
+
+    /**
+     * Convert a IPv4 address from an integer to an InetAddress (0x04030201 -> 1.2.3.4)
+     *
+     * <p>This method uses the higher-order int bytes as the lower-order IPv4 address bytes,
+     * which is an unusual convention. Consider {@link #intToInet4AddressHTH(int)} instead.
+     * @param hostAddress an int coding for an IPv4 address, where higher-order int byte is
+     *                    lower-order IPv4 address byte
+     */
+    public static Inet4Address intToInet4AddressHTL(int hostAddress) {
+        return intToInet4AddressHTH(Integer.reverseBytes(hostAddress));
+    }
+
+    /**
+     * Convert a IPv4 address from an integer to an InetAddress (0x01020304 -> 1.2.3.4)
+     * @param hostAddress an int coding for an IPv4 address
+     */
+    public static Inet4Address intToInet4AddressHTH(int hostAddress) {
+        byte[] addressBytes = { (byte) (0xff & (hostAddress >> 24)),
+                (byte) (0xff & (hostAddress >> 16)),
+                (byte) (0xff & (hostAddress >> 8)),
+                (byte) (0xff & hostAddress) };
+
+        try {
+            return (Inet4Address) InetAddress.getByAddress(addressBytes);
+        } catch (UnknownHostException e) {
+            throw new AssertionError();
+        }
+    }
+
+    /**
+     * Convert an IPv4 address from an InetAddress to an integer (1.2.3.4 -> 0x01020304)
+     *
+     * <p>This conversion can help order IP addresses: considering the ordering
+     * 192.0.2.1 < 192.0.2.2 < ..., resulting ints will follow that ordering if read as unsigned
+     * integers with {@link Integer#toUnsignedLong}.
+     * @param inetAddr is an InetAddress corresponding to the IPv4 address
+     * @return the IP address as integer
+     */
+    public static int inet4AddressToIntHTH(Inet4Address inetAddr)
+            throws IllegalArgumentException {
+        byte [] addr = inetAddr.getAddress();
+        return ((addr[0] & 0xff) << 24) | ((addr[1] & 0xff) << 16)
+                | ((addr[2] & 0xff) << 8) | (addr[3] & 0xff);
+    }
+
+    /**
+     * Convert a IPv4 address from an InetAddress to an integer (1.2.3.4 -> 0x04030201)
+     *
+     * <p>This method stores the higher-order IPv4 address bytes in the lower-order int bytes,
+     * which is an unusual convention. Consider {@link #inet4AddressToIntHTH(Inet4Address)} instead.
+     * @param inetAddr is an InetAddress corresponding to the IPv4 address
+     * @return the IP address as integer
+     */
+    public static int inet4AddressToIntHTL(Inet4Address inetAddr) {
+        return Integer.reverseBytes(inet4AddressToIntHTH(inetAddr));
+    }
+
+    /**
+     * Convert a network prefix length to an IPv4 netmask integer (prefixLength 17 -> 0xffff8000)
+     * @return the IPv4 netmask as an integer
+     */
+    public static int prefixLengthToV4NetmaskIntHTH(int prefixLength)
+            throws IllegalArgumentException {
+        if (prefixLength < 0 || prefixLength > 32) {
+            throw new IllegalArgumentException("Invalid prefix length (0 <= prefix <= 32)");
+        }
+        // (int)a << b is equivalent to a << (b & 0x1f): can't shift by 32 (-1 << 32 == -1)
+        return prefixLength == 0 ? 0 : 0xffffffff << (32 - prefixLength);
+    }
+
+    /**
+     * Convert a network prefix length to an IPv4 netmask integer (prefixLength 17 -> 0x0080ffff).
+     *
+     * <p>This method stores the higher-order IPv4 address bytes in the lower-order int bytes,
+     * which is an unusual convention. Consider {@link #prefixLengthToV4NetmaskIntHTH(int)} instead.
+     * @return the IPv4 netmask as an integer
+     */
+    public static int prefixLengthToV4NetmaskIntHTL(int prefixLength)
+            throws IllegalArgumentException {
+        return Integer.reverseBytes(prefixLengthToV4NetmaskIntHTH(prefixLength));
+    }
+
+    /**
+     * Convert an IPv4 netmask to a prefix length, checking that the netmask is contiguous.
+     * @param netmask as a {@code Inet4Address}.
+     * @return the network prefix length
+     * @throws IllegalArgumentException the specified netmask was not contiguous.
+     * @hide
+     */
+    public static int netmaskToPrefixLength(Inet4Address netmask) {
+        // inetAddressToInt returns an int in *network* byte order.
+        int i = inet4AddressToIntHTH(netmask);
+        int prefixLength = Integer.bitCount(i);
+        int trailingZeros = Integer.numberOfTrailingZeros(i);
+        if (trailingZeros != 32 - prefixLength) {
+            throw new IllegalArgumentException("Non-contiguous netmask: " + Integer.toHexString(i));
+        }
+        return prefixLength;
+    }
+
+    /**
+     * Returns the implicit netmask of an IPv4 address, as was the custom before 1993.
+     */
+    public static int getImplicitNetmask(Inet4Address address) {
+        int firstByte = address.getAddress()[0] & 0xff;  // Convert to an unsigned value.
+        if (firstByte < 128) {
+            return 8;
+        } else if (firstByte < 192) {
+            return 16;
+        } else if (firstByte < 224) {
+            return 24;
+        } else {
+            return 32;  // Will likely not end well for other reasons.
+        }
+    }
+
+    /**
+     * Get the broadcast address for a given prefix.
+     *
+     * <p>For example 192.168.0.1/24 -> 192.168.0.255
+     */
+    public static Inet4Address getBroadcastAddress(Inet4Address addr, int prefixLength)
+            throws IllegalArgumentException {
+        final int intBroadcastAddr = inet4AddressToIntHTH(addr)
+                | ~prefixLengthToV4NetmaskIntHTH(prefixLength);
+        return intToInet4AddressHTH(intBroadcastAddr);
+    }
+
+    /**
+     * Get a prefix mask as Inet4Address for a given prefix length.
+     *
+     * <p>For example 20 -> 255.255.240.0
+     */
+    public static Inet4Address getPrefixMaskAsInet4Address(int prefixLength)
+            throws IllegalArgumentException {
+        return intToInet4AddressHTH(prefixLengthToV4NetmaskIntHTH(prefixLength));
+    }
+}
diff --git a/core/java/android/net/util/SocketUtils.java b/core/java/android/net/util/SocketUtils.java
index de67cf5..2df08a1 100644
--- a/core/java/android/net/util/SocketUtils.java
+++ b/core/java/android/net/util/SocketUtils.java
@@ -20,13 +20,17 @@
 import static android.system.OsConstants.SO_BINDTODEVICE;
 
 import android.annotation.SystemApi;
+import android.annotation.TestApi;
 import android.net.NetworkUtils;
 import android.system.ErrnoException;
 import android.system.NetlinkSocketAddress;
 import android.system.Os;
 import android.system.PacketSocketAddress;
 
+import libcore.io.IoBridge;
+
 import java.io.FileDescriptor;
+import java.io.IOException;
 import java.net.SocketAddress;
 
 /**
@@ -34,6 +38,7 @@
  * @hide
  */
 @SystemApi
+@TestApi
 public class SocketUtils {
     /**
      * Create a raw datagram socket that is bound to an interface.
@@ -57,18 +62,25 @@
     }
 
     /**
-     * Make a socket address to bind to packet sockets.
+     * Make socket address that packet sockets can bind to.
      */
     public static SocketAddress makePacketSocketAddress(short protocol, int ifIndex) {
         return new PacketSocketAddress(protocol, ifIndex);
     }
 
     /**
-     * Make a socket address to send raw packets.
+     * Make a socket address that packet socket can send packets to.
      */
     public static SocketAddress makePacketSocketAddress(int ifIndex, byte[] hwAddr) {
         return new PacketSocketAddress(ifIndex, hwAddr);
     }
 
+    /**
+     * @see IoBridge#closeAndSignalBlockedThreads(FileDescriptor)
+     */
+    public static void closeSocket(FileDescriptor fd) throws IOException {
+        IoBridge.closeAndSignalBlockedThreads(fd);
+    }
+
     private SocketUtils() {}
 }
diff --git a/core/java/android/nfc/INfcAdapter.aidl b/core/java/android/nfc/INfcAdapter.aidl
index 6801618..0b2cfdd 100644
--- a/core/java/android/nfc/INfcAdapter.aidl
+++ b/core/java/android/nfc/INfcAdapter.aidl
@@ -68,4 +68,8 @@
     void removeNfcUnlockHandler(INfcUnlockHandler unlockHandler);
 
     void verifyNfcPermission();
+    boolean isNfcSecureEnabled();
+    boolean deviceSupportsNfcSecure();
+    boolean setNfcSecure(boolean enable);
+
 }
diff --git a/core/java/android/nfc/NfcAdapter.java b/core/java/android/nfc/NfcAdapter.java
index e55e036..a7d2ee9 100644
--- a/core/java/android/nfc/NfcAdapter.java
+++ b/core/java/android/nfc/NfcAdapter.java
@@ -1702,6 +1702,63 @@
     }
 
     /**
+     * Sets Secure NFC feature.
+     * <p>This API is for the Settings application.
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS)
+    public boolean setNfcSecure(boolean enable) {
+        if (!sHasNfcFeature) {
+            throw new UnsupportedOperationException();
+        }
+        try {
+            return sService.setNfcSecure(enable);
+        } catch (RemoteException e) {
+            attemptDeadServiceRecovery(e);
+            return false;
+        }
+    }
+
+    /**
+     * Checks if the device supports Secure NFC functionality.
+     *
+     * @return True if device supports Secure NFC, false otherwise
+     * @throws UnsupportedOperationException if FEATURE_NFC is unavailable.
+     */
+    public boolean deviceSupportsNfcSecure() {
+        if (!sHasNfcFeature) {
+            throw new UnsupportedOperationException();
+        }
+        try {
+            return sService.deviceSupportsNfcSecure();
+        } catch (RemoteException e) {
+            attemptDeadServiceRecovery(e);
+            return false;
+        }
+    }
+
+    /**
+     * Checks Secure NFC feature is enabled.
+     *
+     * @return True if device supports Secure NFC is enabled, false otherwise
+     * @throws UnsupportedOperationException if FEATURE_NFC is unavailable.
+     * @throws UnsupportedOperationException if device doesn't support
+     *         Secure NFC functionality. {@link #deviceSupportsNfcSecure}
+     */
+    public boolean isNfcSecureEnabled() {
+        if (!sHasNfcFeature) {
+            throw new UnsupportedOperationException();
+        }
+        try {
+            return sService.isNfcSecureEnabled();
+        } catch (RemoteException e) {
+            attemptDeadServiceRecovery(e);
+            return false;
+        }
+    }
+
+    /**
      * Enable NDEF Push feature.
      * <p>This API is for the Settings application.
      * @hide
diff --git a/core/java/android/os/BugreportManager.java b/core/java/android/os/BugreportManager.java
index 6f5f807..3a5b8a8 100644
--- a/core/java/android/os/BugreportManager.java
+++ b/core/java/android/os/BugreportManager.java
@@ -21,6 +21,7 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.RequiresPermission;
+import android.annotation.SystemApi;
 import android.annotation.SystemService;
 import android.content.Context;
 import android.os.IBinder.DeathRecipient;
@@ -35,8 +36,7 @@
  *
  * @hide
  */
-// TODO: Expose API when the implementation is more complete.
-//@SystemApi
+@SystemApi
 @SystemService(Context.BUGREPORT_SERVICE)
 public class BugreportManager {
     private final Context mContext;
diff --git a/core/java/android/os/BugreportParams.java b/core/java/android/os/BugreportParams.java
index 4e696ae..3871375 100644
--- a/core/java/android/os/BugreportParams.java
+++ b/core/java/android/os/BugreportParams.java
@@ -17,6 +17,7 @@
 package android.os;
 
 import android.annotation.IntDef;
+import android.annotation.SystemApi;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
@@ -26,8 +27,7 @@
  *
  * @hide
  */
-// TODO: Expose API when the implementation is more complete.
-// @SystemApi
+@SystemApi
 public final class BugreportParams {
     private final int mMode;
 
diff --git a/core/java/android/os/DumpstateOptions.java b/core/java/android/os/DumpstateOptions.java
deleted file mode 100644
index 53037b24..0000000
--- a/core/java/android/os/DumpstateOptions.java
+++ /dev/null
@@ -1,57 +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 android.os;
-
-/**
- * Options passed to dumpstate service.
- *
- * @hide
- */
-public final class DumpstateOptions implements Parcelable {
-    // If true the caller can get callbacks with per-section
-    // progress details.
-    private final boolean mGetSectionDetails;
-    // Name of the caller.
-    private final String mName;
-
-    public DumpstateOptions(Parcel in) {
-        mGetSectionDetails = in.readBoolean();
-        mName = in.readString();
-    }
-
-    @Override
-    public int describeContents() {
-        return 0;
-    }
-
-    @Override
-     public void writeToParcel(Parcel out, int flags) {
-        out.writeBoolean(mGetSectionDetails);
-        out.writeString(mName);
-    }
-
-    public static final Parcelable.Creator<DumpstateOptions> CREATOR =
-            new Parcelable.Creator<DumpstateOptions>() {
-        public DumpstateOptions createFromParcel(Parcel in) {
-            return new DumpstateOptions(in);
-        }
-
-        public DumpstateOptions[] newArray(int size) {
-            return new DumpstateOptions[size];
-        }
-    };
-}
diff --git a/core/java/android/os/Environment.java b/core/java/android/os/Environment.java
index a236300..3feccf5 100644
--- a/core/java/android/os/Environment.java
+++ b/core/java/android/os/Environment.java
@@ -50,6 +50,7 @@
 
     /** {@hide} */
     public static final String DIR_ANDROID = "Android";
+    private static final String DIR_SANDBOX = "sandbox";
     private static final String DIR_DATA = "data";
     private static final String DIR_MEDIA = "media";
     private static final String DIR_OBB = "obb";
@@ -117,6 +118,10 @@
             return buildPaths(getExternalDirs(), type);
         }
 
+        public File[] buildExternalStorageAndroidSandboxDirs() {
+            return buildPaths(getExternalDirs(), DIR_ANDROID, DIR_SANDBOX);
+        }
+
         public File[] buildExternalStorageAndroidDataDirs() {
             return buildPaths(getExternalDirs(), DIR_ANDROID, DIR_DATA);
         }
@@ -824,6 +829,15 @@
      * Returns the path for android-specific data on the SD card.
      * @hide
      */
+    public static File[] buildExternalStorageAndroidSandboxDirs() {
+        throwIfUserRequired();
+        return sCurrentUser.buildExternalStorageAndroidSandboxDirs();
+    }
+
+    /**
+     * Returns the path for android-specific data on the SD card.
+     * @hide
+     */
     public static File[] buildExternalStorageAndroidDataDirs() {
         throwIfUserRequired();
         return sCurrentUser.buildExternalStorageAndroidDataDirs();
diff --git a/core/java/android/os/FileObserver.java b/core/java/android/os/FileObserver.java
index dd85e15..da03895 100644
--- a/core/java/android/os/FileObserver.java
+++ b/core/java/android/os/FileObserver.java
@@ -16,11 +16,15 @@
 
 package android.os;
 
+import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.util.Log;
 
+import java.io.File;
 import java.lang.ref.WeakReference;
+import java.util.Arrays;
 import java.util.HashMap;
+import java.util.List;
 
 /**
  * Monitors files (using <a href="http://en.wikipedia.org/wiki/Inotify">inotify</a>)
@@ -28,7 +32,7 @@
  * the device (including this one).  FileObserver is an abstract class;
  * subclasses must implement the event handler {@link #onEvent(int, String)}.
  *
- * <p>Each FileObserver instance monitors a single file or directory.
+ * <p>Each FileObserver instance can monitor multiple files or directories.
  * If a directory is monitored, events will be triggered for all files and
  * subdirectories inside the monitored directory.</p>
  *
@@ -86,21 +90,32 @@
             observe(m_fd);
         }
 
-        public int startWatching(String path, int mask, FileObserver observer) {
-            int wfd = startWatching(m_fd, path, mask);
+        public int[] startWatching(List<File> files, int mask, FileObserver observer) {
+            final int count = files.size();
+            final String[] paths = new String[count];
+            for (int i = 0; i < count; ++i) {
+                paths[i] = files.get(i).getAbsolutePath();
+            }
+            final int[] wfds = new int[count];
+            Arrays.fill(wfds, -1);
 
-            Integer i = new Integer(wfd);
-            if (wfd >= 0) {
-                synchronized (m_observers) {
-                    m_observers.put(i, new WeakReference(observer));
+            startWatching(m_fd, paths, mask, wfds);
+
+            final WeakReference<FileObserver> fileObserverWeakReference =
+                    new WeakReference<>(observer);
+            synchronized (m_observers) {
+                for (int wfd : wfds) {
+                    if (wfd >= 0) {
+                        m_observers.put(wfd, fileObserverWeakReference);
+                    }
                 }
             }
 
-            return i;
+            return wfds;
         }
 
-        public void stopWatching(int descriptor) {
-            stopWatching(m_fd, descriptor);
+        public void stopWatching(int[] descriptors) {
+            stopWatching(m_fd, descriptors);
         }
 
         public void onEvent(int wfd, int mask, String path) {
@@ -129,8 +144,8 @@
 
         private native int init();
         private native void observe(int fd);
-        private native int startWatching(int fd, String path, int mask);
-        private native void stopWatching(int fd, int wfd);
+        private native void startWatching(int fd, String[] paths, int mask, int[] wfds);
+        private native void stopWatching(int fd, int[] wfds);
     }
 
     private static ObserverThread s_observerThread;
@@ -141,15 +156,34 @@
     }
 
     // instance
-    private String m_path;
-    private Integer m_descriptor;
-    private int m_mask;
+    private final List<File> mFiles;
+    private int[] mDescriptors;
+    private final int mMask;
 
     /**
      * Equivalent to FileObserver(path, FileObserver.ALL_EVENTS).
+     *
+     * @deprecated use {@link #FileObserver(File)} instead.
      */
+    @Deprecated
     public FileObserver(String path) {
-        this(path, ALL_EVENTS);
+        this(new File(path));
+    }
+
+    /**
+     * Equivalent to FileObserver(file, FileObserver.ALL_EVENTS).
+     */
+    public FileObserver(@NonNull File file) {
+        this(Arrays.asList(file));
+    }
+
+    /**
+     * Equivalent to FileObserver(paths, FileObserver.ALL_EVENTS).
+     *
+     * @param files The files or directories to monitor
+     */
+    public FileObserver(@NonNull List<File> files) {
+        this(files, ALL_EVENTS);
     }
 
     /**
@@ -159,11 +193,36 @@
      *
      * @param path The file or directory to monitor
      * @param mask The event or events (added together) to watch for
+     *
+     * @deprecated use {@link #FileObserver(File, int)} instead.
      */
+    @Deprecated
     public FileObserver(String path, int mask) {
-        m_path = path;
-        m_mask = mask;
-        m_descriptor = -1;
+        this(new File(path), mask);
+    }
+
+    /**
+     * Create a new file observer for a certain file or directory.
+     * Monitoring does not start on creation!  You must call
+     * {@link #startWatching()} before you will receive events.
+     *
+     * @param file The file or directory to monitor
+     * @param mask The event or events (added together) to watch for
+     */
+    public FileObserver(@NonNull File file, int mask) {
+        this(Arrays.asList(file), mask);
+    }
+
+    /**
+     * Version of {@link #FileObserver(File, int)} that allows callers to monitor
+     * multiple files or directories.
+     *
+     * @param files The files or directories to monitor
+     * @param mask The event or events (added together) to watch for
+     */
+    public FileObserver(@NonNull List<File> files, int mask) {
+        mFiles = files;
+        mMask = mask;
     }
 
     protected void finalize() {
@@ -176,8 +235,8 @@
      * If monitoring is already started, this call has no effect.
      */
     public void startWatching() {
-        if (m_descriptor < 0) {
-            m_descriptor = s_observerThread.startWatching(m_path, m_mask, this);
+        if (mDescriptors == null) {
+            mDescriptors = s_observerThread.startWatching(mFiles, mMask, this);
         }
     }
 
@@ -187,9 +246,9 @@
      * monitoring is already stopped, this call has no effect.
      */
     public void stopWatching() {
-        if (m_descriptor >= 0) {
-            s_observerThread.stopWatching(m_descriptor);
-            m_descriptor = -1;
+        if (mDescriptors != null) {
+            s_observerThread.stopWatching(mDescriptors);
+            mDescriptors = null;
         }
     }
 
diff --git a/core/java/android/os/ParcelUuid.java b/core/java/android/os/ParcelUuid.java
index 2c68ddd..5b45ac2 100644
--- a/core/java/android/os/ParcelUuid.java
+++ b/core/java/android/os/ParcelUuid.java
@@ -16,6 +16,8 @@
 
 package android.os;
 
+import android.annotation.UnsupportedAppUsage;
+
 import java.util.UUID;
 
 /**
@@ -109,6 +111,7 @@
 
    public static final Parcelable.Creator<ParcelUuid> CREATOR =
                new Parcelable.Creator<ParcelUuid>() {
+        @UnsupportedAppUsage
         public ParcelUuid createFromParcel(Parcel source) {
             long mostSigBits = source.readLong();
             long leastSigBits = source.readLong();
diff --git a/core/java/android/os/SELinux.java b/core/java/android/os/SELinux.java
index 94441ca..a96618a 100644
--- a/core/java/android/os/SELinux.java
+++ b/core/java/android/os/SELinux.java
@@ -16,6 +16,7 @@
 
 package android.os;
 
+import android.annotation.UnsupportedAppUsage;
 import android.util.Slog;
 
 import java.io.File;
@@ -69,6 +70,7 @@
      * @param path the pathname of the file object.
      * @return a security context given as a String.
      */
+    @UnsupportedAppUsage
     public static final native String getFileContext(String path);
 
     /**
diff --git a/core/java/android/os/ZygoteProcess.java b/core/java/android/os/ZygoteProcess.java
index 9e47179..e94ad2b 100644
--- a/core/java/android/os/ZygoteProcess.java
+++ b/core/java/android/os/ZygoteProcess.java
@@ -74,6 +74,19 @@
     public static final String ZYGOTE_SECONDARY_SOCKET_NAME = "zygote_secondary";
 
     /**
+     * @hide for internal use only.
+     */
+    public static final int ZYGOTE_CONNECT_TIMEOUT_MS = 20000;
+
+    /**
+     * @hide for internal use only.
+     *
+     * Use a relatively short delay, because for app zygote, this is in the critical path of
+     * service launch.
+     */
+    public static final int ZYGOTE_CONNECT_RETRY_DELAY_MS = 50;
+
+    /**
      * @hide for internal use only
      */
     public static final String BLASTULA_POOL_SOCKET_NAME = "blastula_pool";
@@ -933,7 +946,8 @@
      * @param address The name of the socket to connect to.
      */
     public static void waitForConnectionToZygote(LocalSocketAddress zygoteSocketAddress) {
-        for (int n = 20; n >= 0; n--) {
+        int numRetries = ZYGOTE_CONNECT_TIMEOUT_MS / ZYGOTE_CONNECT_RETRY_DELAY_MS;
+        for (int n = numRetries; n >= 0; n--) {
             try {
                 final ZygoteState zs =
                         ZygoteState.connect(zygoteSocketAddress, null);
@@ -945,7 +959,7 @@
             }
 
             try {
-                Thread.sleep(1000);
+                Thread.sleep(ZYGOTE_CONNECT_RETRY_DELAY_MS);
             } catch (InterruptedException ie) {
             }
         }
diff --git a/core/java/android/provider/DeviceConfig.java b/core/java/android/provider/DeviceConfig.java
index 148dd91..d58e00a 100644
--- a/core/java/android/provider/DeviceConfig.java
+++ b/core/java/android/provider/DeviceConfig.java
@@ -112,14 +112,12 @@
     @SystemApi
     public interface IntelligenceAttention {
         String NAMESPACE = "intelligence_attention";
-        /**
-         * If {@code true}, enables the attention check.
-         */
-        String PROPERTY_ATTENTION_CHECK_ENABLED = "attention_check_enabled";
-        /**
-         * Settings for performing the attention check.
-         */
-        String PROPERTY_ATTENTION_CHECK_SETTINGS = "attention_check_settings";
+
+        /** If {@code true}, enables the attention features. */
+        String PROPERTY_ATTENTION_ENABLED = "attention_enabled";
+
+        /** Settings for the attention features. */
+        String PROPERTY_ATTENTION_SETTINGS = "attention_settings";
     }
 
     /**
@@ -182,6 +180,22 @@
     }
 
     /**
+     * Namespace for {@link AttentionManagerService} related features.
+     *
+     * @hide
+     */
+    @SystemApi
+    public interface AttentionManagerService {
+        String NAMESPACE = "attention_manager_service";
+
+        /** If {@code true}, enables {@link AttentionManagerService} features. */
+        String PROPERTY_SERVICE_ENABLED = "service_enabled";
+
+        /** Allows a CTS to inject a fake implementation. */
+        String PROPERTY_COMPONENT_NAME = "component_name";
+    }
+
+    /**
      * Namespace for storage-related features.
      *
      * @hide
diff --git a/core/java/android/provider/Downloads.java b/core/java/android/provider/Downloads.java
index b348da4..63bbb9c 100644
--- a/core/java/android/provider/Downloads.java
+++ b/core/java/android/provider/Downloads.java
@@ -837,6 +837,14 @@
         }
     }
 
+    /** @hide */
+    public static final String MEDIASTORE_DOWNLOADS_DELETED_CALL = "mediastore_downloads_deleted";
+
+    /** @hide */
+    public static final String EXTRA_IDS = "ids";
+    /** @hide */
+    public static final String EXTRA_MIME_TYPES = "mime_types";
+
     /**
      * Query where clause for general querying.
      */
diff --git a/core/java/android/provider/MediaStore.java b/core/java/android/provider/MediaStore.java
index 887175a..124c50a 100644
--- a/core/java/android/provider/MediaStore.java
+++ b/core/java/android/provider/MediaStore.java
@@ -158,6 +158,8 @@
     public static final String PARAM_PROGRESS = "progress";
     /** {@hide} */
     public static final String PARAM_REQUIRE_ORIGINAL = "requireOriginal";
+    /** {@hide} */
+    public static final String PARAM_LIMIT = "limit";
 
     /**
      * Activity Action: Launch a music player.
@@ -513,7 +515,12 @@
      * @see MediaStore#createPending(Context, PendingParams)
      */
     public static @NonNull Uri setIncludePending(@NonNull Uri uri) {
-        return uri.buildUpon().appendQueryParameter(PARAM_INCLUDE_PENDING, "1").build();
+        return setIncludePending(uri.buildUpon()).build();
+    }
+
+    /** @hide */
+    public static @NonNull Uri.Builder setIncludePending(@NonNull Uri.Builder uriBuilder) {
+        return uriBuilder.appendQueryParameter(PARAM_INCLUDE_PENDING, "1");
     }
 
     /**
@@ -982,6 +989,11 @@
      * work with multiple media file types in a single query.
      */
     public static final class Files {
+        /** @hide */
+        public static final String TABLE = "files";
+
+        /** @hide */
+        public static final Uri EXTERNAL_CONTENT_URI = getContentUri(VOLUME_EXTERNAL);
 
         /**
          * Get the content:// style URI for the files table on the
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 43e68e5..290b556 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -486,6 +486,37 @@
             "android.settings.WIFI_IP_SETTINGS";
 
     /**
+     * Activity Action: Show setting page to process an Easy Connect (Wi-Fi DPP) QR code and start
+     * configuration. This intent should be used when you want to use this device to take on the
+     * configurator role for an IoT/other device. When provided with a valid DPP URI string Settings
+     * will open a wifi selection screen for the user to indicate which network they would like
+     * to configure the device specified in the DPP URI string for and carry them through the rest
+     * of the flow for provisioning the device.
+     * <p>
+     * In some cases, a matching Activity may not exist, so ensure you safeguard
+     * against this by checking WifiManager.isEasyConnectSupported();
+     * <p>
+     * Input:
+     * The following keys in the bundle with their associated value.
+     * <ul>
+     *     <li>"qrCode": Standard Easy Connect (Wi-Fi DPP) URI bootstrapping information as a
+     *     string.</li>
+     * </ul>
+     * <p>
+     * Output: Nothing.
+     */
+    @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+    public static final String ACTION_PROCESS_WIFI_EASY_CONNECT_QR_CODE =
+            "android.settings.PROCESS_WIFI_EASY_CONNECT_QR_CODE";
+
+    /**
+     * An extra to put in the bundle for {@link #ACTION_PROCESS_WIFI_EASY_CONNECT_QR_CODE} intents.
+     * It must contain properly formatted Easy Connect (Wi-Fi DPP) URI bootstrapping information for
+     * the process to proceed.
+     */
+    public static final String EXTRA_QR_CODE = "android.provider.extra.QR_CODE";
+
+    /**
      * Activity Action: Show settings to allow configuration of data and view data usage.
      * <p>
      * In some cases, a matching Activity may not exist, so ensure you
@@ -5800,6 +5831,16 @@
         public static final String ALWAYS_ON_VPN_LOCKDOWN = "always_on_vpn_lockdown";
 
         /**
+         * Comma separated list of packages that are allowed to access the network when VPN is in
+         * lockdown mode but not running.
+         * @see #ALWAYS_ON_VPN_LOCKDOWN
+         *
+         * @hide
+         */
+        public static final String ALWAYS_ON_VPN_LOCKDOWN_WHITELIST =
+                "always_on_vpn_lockdown_whitelist";
+
+        /**
          * Whether applications can be installed for this user via the system's
          * {@link Intent#ACTION_INSTALL_PACKAGE} mechanism.
          *
@@ -11723,6 +11764,7 @@
          * entity_list_default                      (String[])
          * entity_list_not_editable                 (String[])
          * entity_list_editable                     (String[])
+         * lang_id_threshold_override               (float)
          * </pre>
          *
          * <p>
@@ -11767,6 +11809,44 @@
         public static final String SYNC_MANAGER_CONSTANTS = "sync_manager_constants";
 
         /**
+         * Broadcast dispatch tuning parameters specific to foreground broadcasts.
+         *
+         * This is encoded as a key=value list, separated by commas. Ex: "foo=1,bar=true"
+         *
+         * The following keys are supported:
+         * <pre>
+         * bcast_timeout                (long)
+         * bcast_slow_time              (long)
+         * bcast_deferral               (long)
+         * bcast_deferral_decay_factor  (float)
+         * bcast_deferral_floor         (long)
+         * </pre>
+         *
+         * @hide
+         */
+        public static final String BROADCAST_FG_CONSTANTS = "bcast_fg_constants";
+
+        /**
+         * Broadcast dispatch tuning parameters specific to background broadcasts.
+         *
+         * This is encoded as a key=value list, separated by commas. Ex: "foo=1,bar=true".
+         * See {@link #BROADCAST_FG_CONSTANTS} for the list of supported keys.
+         *
+         * @hide
+         */
+        public static final String BROADCAST_BG_CONSTANTS = "bcast_bg_constants";
+
+        /**
+         * Broadcast dispatch tuning parameters specific to specific "offline" broadcasts.
+         *
+         * This is encoded as a key=value list, separated by commas. Ex: "foo=1,bar=true".
+         * See {@link #BROADCAST_FG_CONSTANTS} for the list of supported keys.
+         *
+         * @hide
+         */
+        public static final String BROADCAST_OFFLOAD_CONSTANTS = "bcast_offload_constants";
+
+        /**
          * Whether or not App Standby feature is enabled by system. This controls throttling of apps
          * based on usage patterns and predictions. Platform will turn on this feature if both this
          * flag and {@link #ADAPTIVE_BATTERY_MANAGEMENT_ENABLED} is on.
diff --git a/core/java/android/service/notification/Adjustment.java b/core/java/android/service/notification/Adjustment.java
index b6788f5..93189b3 100644
--- a/core/java/android/service/notification/Adjustment.java
+++ b/core/java/android/service/notification/Adjustment.java
@@ -63,15 +63,17 @@
 
     /**
      * Data type: ArrayList of {@link android.app.Notification.Action}.
-     * Used to suggest extra actions for a notification.
+     * Used to suggest contextual actions for a notification.
+     *
+     * @see Notification.Action.Builder#setContextual(boolean)
      */
-    public static final String KEY_SMART_ACTIONS = "key_smart_actions";
+    public static final String KEY_CONTEXTUAL_ACTIONS = "key_contextual_actions";
 
     /**
      * Data type: ArrayList of {@link CharSequence}.
      * Used to suggest smart replies for a notification.
      */
-    public static final String KEY_SMART_REPLIES = "key_smart_replies";
+    public static final String KEY_TEXT_REPLIES = "key_text_replies";
 
     /**
      * Data type: int, one of importance values e.g.
diff --git a/core/java/android/service/notification/StatusBarNotification.java b/core/java/android/service/notification/StatusBarNotification.java
index 3a644d4..551bb8a 100644
--- a/core/java/android/service/notification/StatusBarNotification.java
+++ b/core/java/android/service/notification/StatusBarNotification.java
@@ -28,6 +28,7 @@
 import android.os.Parcelable;
 import android.os.UserHandle;
 
+import com.android.internal.logging.nano.MetricsProto;
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 
 /**
@@ -410,7 +411,9 @@
             .clearSubtype()
             .addTaggedData(MetricsEvent.FIELD_NOTIFICATION_GROUP_ID, getGroupLogTag())
             .addTaggedData(MetricsEvent.FIELD_NOTIFICATION_GROUP_SUMMARY,
-                getNotification().isGroupSummary() ? 1 : 0);
+                getNotification().isGroupSummary() ? 1 : 0)
+            .addTaggedData(MetricsProto.MetricsEvent.FIELD_NOTIFICATION_CATEGORY,
+                    getNotification().category);
     }
 
     private String getGroupLogTag() {
diff --git a/core/java/android/view/ImeInsetsSourceConsumer.java b/core/java/android/view/ImeInsetsSourceConsumer.java
new file mode 100644
index 0000000..7026d2b
--- /dev/null
+++ b/core/java/android/view/ImeInsetsSourceConsumer.java
@@ -0,0 +1,157 @@
+/*
+ * 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 static android.view.InsetsState.TYPE_IME;
+
+import android.os.Parcel;
+import android.text.TextUtils;
+import android.view.SurfaceControl.Transaction;
+import android.view.WindowInsets.Type;
+import android.view.inputmethod.EditorInfo;
+import android.view.inputmethod.InputMethodManager;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.util.Arrays;
+import java.util.function.Supplier;
+
+/**
+ * Controls the visibility and animations of IME window insets source.
+ * @hide
+ */
+public final class ImeInsetsSourceConsumer extends InsetsSourceConsumer {
+    private EditorInfo mFocusedEditor;
+    private EditorInfo mPreRenderedEditor;
+    /**
+     * Determines if IME would be shown next time IME is pre-rendered for currently focused
+     * editor {@link #mFocusedEditor} if {@link #isServedEditorRendered} is {@code true}.
+     */
+    private boolean mShowOnNextImeRender;
+    private boolean mHasWindowFocus;
+
+    public ImeInsetsSourceConsumer(
+            InsetsState state, Supplier<Transaction> transactionSupplier,
+            InsetsController controller) {
+        super(TYPE_IME, state, transactionSupplier, controller);
+    }
+
+    public void onPreRendered(EditorInfo info) {
+        mPreRenderedEditor = info;
+        if (mShowOnNextImeRender) {
+            mShowOnNextImeRender = false;
+            if (isServedEditorRendered()) {
+                applyImeVisibility(true /* setVisible */);
+            }
+        }
+    }
+
+    public void onServedEditorChanged(EditorInfo info) {
+        if (isDummyOrEmptyEditor(info)) {
+            mShowOnNextImeRender = false;
+        }
+        mFocusedEditor = info;
+    }
+
+    public void applyImeVisibility(boolean setVisible) {
+        if (!mHasWindowFocus) {
+            // App window doesn't have focus, any visibility changes would be no-op.
+            return;
+        }
+
+        if (setVisible) {
+            mController.show(Type.IME);
+        } else {
+            mController.hide(Type.IME);
+        }
+    }
+
+    @Override
+    public void onWindowFocusGained() {
+        mHasWindowFocus = true;
+        getImm().registerImeConsumer(this);
+    }
+
+    @Override
+    public void onWindowFocusLost() {
+        mHasWindowFocus = false;
+    }
+
+    private boolean isDummyOrEmptyEditor(EditorInfo info) {
+        // TODO(b/123044812): Handle dummy input gracefully in IME Insets API
+        return info == null || (info.fieldId <= 0 && info.inputType <= 0);
+    }
+
+    private boolean isServedEditorRendered() {
+        if (mFocusedEditor == null || mPreRenderedEditor == null
+                || isDummyOrEmptyEditor(mFocusedEditor)
+                || isDummyOrEmptyEditor(mPreRenderedEditor)) {
+            // No view is focused or ready.
+            return false;
+        }
+        return areEditorsSimilar(mFocusedEditor, mPreRenderedEditor);
+    }
+
+    @VisibleForTesting
+    public static boolean areEditorsSimilar(EditorInfo info1, EditorInfo info2) {
+        // We don't need to compare EditorInfo.fieldId (View#id) since that shouldn't change
+        // IME views.
+        boolean areOptionsSimilar =
+                info1.imeOptions == info2.imeOptions
+                && info1.inputType == info2.inputType
+                && TextUtils.equals(info1.packageName, info2.packageName);
+        areOptionsSimilar &= info1.privateImeOptions != null
+                ? info1.privateImeOptions.equals(info2.privateImeOptions) : true;
+
+        if (!areOptionsSimilar) {
+            return false;
+        }
+
+        // compare bundle extras.
+        if ((info1.extras == null && info2.extras == null) || info1.extras == info2.extras) {
+            return true;
+        }
+        if ((info1.extras == null && info2.extras != null)
+                || (info1.extras == null && info2.extras != null)) {
+            return false;
+        }
+        if (info1.extras.hashCode() == info2.extras.hashCode()
+                || info1.extras.equals(info1)) {
+            return true;
+        }
+        if (info1.extras.size() != info2.extras.size()) {
+            return false;
+        }
+        if (info1.extras.toString().equals(info2.extras.toString())) {
+            return true;
+        }
+
+        // Compare bytes
+        Parcel parcel1 = Parcel.obtain();
+        info1.extras.writeToParcel(parcel1, 0);
+        parcel1.setDataPosition(0);
+        Parcel parcel2 = Parcel.obtain();
+        info2.extras.writeToParcel(parcel2, 0);
+        parcel2.setDataPosition(0);
+
+        return Arrays.equals(parcel1.createByteArray(), parcel2.createByteArray());
+    }
+
+    private InputMethodManager getImm() {
+        return mController.getViewRoot().mDisplayContext.getSystemService(InputMethodManager.class);
+    }
+}
diff --git a/core/java/android/view/InsetsController.java b/core/java/android/view/InsetsController.java
index 2142c36..4f9ecd5 100644
--- a/core/java/android/view/InsetsController.java
+++ b/core/java/android/view/InsetsController.java
@@ -16,6 +16,8 @@
 
 package android.view;
 
+import static android.view.InsetsState.TYPE_IME;
+
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
 import android.animation.ObjectAnimator;
@@ -262,7 +264,7 @@
         if (controller != null) {
             return controller;
         }
-        controller = new InsetsSourceConsumer(type, mState, Transaction::new, this);
+        controller = createConsumerOfType(type);
         mSourceConsumers.put(type, controller);
         return controller;
     }
@@ -274,6 +276,32 @@
     }
 
     /**
+     * Called when current window gains focus.
+     */
+    public void onWindowFocusGained() {
+        getSourceConsumer(TYPE_IME).onWindowFocusGained();
+    }
+
+    /**
+     * Called when current window loses focus.
+     */
+    public void onWindowFocusLost() {
+        getSourceConsumer(TYPE_IME).onWindowFocusLost();
+    }
+
+    ViewRootImpl getViewRoot() {
+        return mViewRoot;
+    }
+
+    private InsetsSourceConsumer createConsumerOfType(int type) {
+        if (type == TYPE_IME) {
+            return new ImeInsetsSourceConsumer(mState, Transaction::new, this);
+        } else {
+            return new InsetsSourceConsumer(type, mState, Transaction::new, this);
+        }
+    }
+
+    /**
      * Sends the local visibility state back to window manager.
      */
     private void sendStateToWindowManager() {
diff --git a/core/java/android/view/InsetsSourceConsumer.java b/core/java/android/view/InsetsSourceConsumer.java
index 7937cb6..f48318c 100644
--- a/core/java/android/view/InsetsSourceConsumer.java
+++ b/core/java/android/view/InsetsSourceConsumer.java
@@ -30,12 +30,12 @@
  */
 public class InsetsSourceConsumer {
 
+    protected final InsetsController mController;
+    protected boolean mVisible;
     private final Supplier<Transaction> mTransactionSupplier;
     private final @InternalInsetType int mType;
     private final InsetsState mState;
-    private final InsetsController mController;
     private @Nullable InsetsSourceControl mSourceControl;
-    private boolean mVisible;
 
     public InsetsSourceConsumer(@InternalInsetType int type, InsetsState state,
             Supplier<Transaction> transactionSupplier, InsetsController controller) {
@@ -43,7 +43,7 @@
         mState = state;
         mTransactionSupplier = transactionSupplier;
         mController = controller;
-        mVisible = InsetsState.getDefaultVisibly(type);
+        mVisible = InsetsState.getDefaultVisibility(type);
     }
 
     public void setControl(@Nullable InsetsSourceControl control) {
@@ -76,6 +76,16 @@
         setVisible(false);
     }
 
+    /**
+     * Called when current window gains focus
+     */
+    public void onWindowFocusGained() {}
+
+    /**
+     * Called when current window loses focus.
+     */
+    public void onWindowFocusLost() {}
+
     boolean applyLocalVisibilityOverride() {
 
         // If we don't have control, we are not able to change the visibility.
diff --git a/core/java/android/view/InsetsState.java b/core/java/android/view/InsetsState.java
index a6af1a2..4f809fe6 100644
--- a/core/java/android/view/InsetsState.java
+++ b/core/java/android/view/InsetsState.java
@@ -278,7 +278,7 @@
         }
     }
 
-    public static boolean getDefaultVisibly(@InsetType int type) {
+    public static boolean getDefaultVisibility(@InsetType int type) {
         switch (type) {
             case TYPE_TOP_BAR:
             case TYPE_SIDE_BAR_1:
diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java
index 45e6c50..ecbec65 100644
--- a/core/java/android/view/SurfaceView.java
+++ b/core/java/android/view/SurfaceView.java
@@ -492,7 +492,7 @@
         if (mBackgroundControl == null) {
             return;
         }
-        if ((mSurfaceFlags & PixelFormat.OPAQUE) == 0) {
+        if ((mSurfaceFlags & PixelFormat.OPAQUE) != 0) {
             mBackgroundControl.show();
             mBackgroundControl.setLayer(Integer.MIN_VALUE);
         } else {
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index a031b70..f47eb10 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -2802,6 +2802,11 @@
             hasWindowFocus = mUpcomingWindowFocus;
             inTouchMode = mUpcomingInTouchMode;
         }
+        if (hasWindowFocus) {
+            mInsetsController.onWindowFocusGained();
+        } else {
+            mInsetsController.onWindowFocusLost();
+        }
 
         if (mAdded) {
             profileRendering(hasWindowFocus);
diff --git a/core/java/android/view/contentcapture/ContentCaptureManager.java b/core/java/android/view/contentcapture/ContentCaptureManager.java
index b9017b3..d7f1b9f 100644
--- a/core/java/android/view/contentcapture/ContentCaptureManager.java
+++ b/core/java/android/view/contentcapture/ContentCaptureManager.java
@@ -156,8 +156,7 @@
         // Wait for system server to return the component name.
         final SyncResultReceiver resultReceiver = new SyncResultReceiver(SYNC_CALLS_TIMEOUT_MS);
         mHandler.sendMessage(obtainMessage(
-                ContentCaptureManager::handleReceiverServiceComponentName,
-                this, mContext.getUserId(), resultReceiver));
+                ContentCaptureManager::handleGetComponentName, this, resultReceiver));
 
         try {
             return resultReceiver.getParcelableResult();
@@ -198,7 +197,7 @@
         Preconditions.checkNotNull(request);
 
         try {
-            mService.removeUserData(mContext.getUserId(), request);
+            mService.removeUserData(request);
         } catch (RemoteException e) {
             e.rethrowFromSystemServer();
         }
@@ -227,9 +226,9 @@
 
 
     /** Retrieves the component name of the target content capture service through system_server. */
-    private void handleReceiverServiceComponentName(int userId, IResultReceiver resultReceiver) {
+    private void handleGetComponentName(@NonNull IResultReceiver resultReceiver) {
         try {
-            mService.getReceiverServiceComponentName(userId, resultReceiver);
+            mService.getServiceComponentName(resultReceiver);
         } catch (RemoteException e) {
             Log.w(TAG, "Unable to retrieve service component name: " + e);
         }
diff --git a/core/java/android/view/contentcapture/IContentCaptureManager.aidl b/core/java/android/view/contentcapture/IContentCaptureManager.aidl
index 51aea16..56ed8bf 100644
--- a/core/java/android/view/contentcapture/IContentCaptureManager.aidl
+++ b/core/java/android/view/contentcapture/IContentCaptureManager.aidl
@@ -34,21 +34,21 @@
   */
 oneway interface IContentCaptureManager {
     /**
-     * Starts a new session for the provided {@code userId} running as part of the
+     * Starts a new session for the calling user running as part of the
      * app's activity identified by {@code activityToken}/{@code componentName}.
      *
      * @param sessionId Unique session id as provided by the app.
      * @param flags Meta flags that enable or disable content capture (see
      *     {@link IContentCaptureContext#flags}).
      */
-    void startSession(int userId, IBinder activityToken, in ComponentName componentName,
+    void startSession(IBinder activityToken, in ComponentName componentName,
                       String sessionId, int flags, in IResultReceiver result);
 
     /**
-     * Marks the end of a session for the provided {@code userId} identified by
+     * Marks the end of a session for the calling user identified by
      * the corresponding {@code startSession}'s {@code sessionId}.
      */
-    void finishSession(int userId, String sessionId);
+    void finishSession(String sessionId);
 
     /**
      * Returns the content capture service's component name (if enabled and
@@ -56,10 +56,10 @@
      * @param Receiver of the content capture service's @{code ComponentName}
      *     provided {@code Bundle} with key "{@code EXTRA}".
      */
-    void getReceiverServiceComponentName(int userId, in IResultReceiver result);
+    void getServiceComponentName(in IResultReceiver result);
 
     /**
-     * Requests the removal of user data for the provided {@code userId}.
+     * Requests the removal of user data for the calling user.
      */
-    void removeUserData(int userId, in UserDataRemovalRequest request);
+    void removeUserData(in UserDataRemovalRequest request);
 }
diff --git a/core/java/android/view/contentcapture/MainContentCaptureSession.java b/core/java/android/view/contentcapture/MainContentCaptureSession.java
index 9e99c88..83dbf2d 100644
--- a/core/java/android/view/contentcapture/MainContentCaptureSession.java
+++ b/core/java/android/view/contentcapture/MainContentCaptureSession.java
@@ -211,8 +211,8 @@
         try {
             if (mSystemServerInterface == null) return;
 
-            mSystemServerInterface.startSession(mContext.getUserId(), mApplicationToken,
-                    componentName, mId, flags, new IResultReceiver.Stub() {
+            mSystemServerInterface.startSession(mApplicationToken, componentName, mId, flags,
+                    new IResultReceiver.Stub() {
                         @Override
                         public void send(int resultCode, Bundle resultData) {
                             IBinder binder = null;
@@ -473,7 +473,7 @@
         try {
             if (mSystemServerInterface == null) return;
 
-            mSystemServerInterface.finishSession(mContext.getUserId(), mId);
+            mSystemServerInterface.finishSession(mId);
         } catch (RemoteException e) {
             Log.e(TAG, "Error destroying system-service session " + mId + " for "
                     + getDebugState() + ": " + e);
diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java
index 0cb1800..7fee3ef 100644
--- a/core/java/android/view/inputmethod/InputMethodManager.java
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -55,6 +55,7 @@
 import android.util.Printer;
 import android.util.SparseArray;
 import android.view.Display;
+import android.view.ImeInsetsSourceConsumer;
 import android.view.InputChannel;
 import android.view.InputEvent;
 import android.view.InputEventSender;
@@ -441,6 +442,13 @@
      */
     private int mRequestUpdateCursorAnchorInfoMonitorMode = REQUEST_UPDATE_CURSOR_ANCHOR_INFO_NONE;
 
+    /**
+     * When {@link ViewRootImpl#sNewInsetsMode} is set to
+     * >= {@link ViewRootImpl#NEW_INSETS_MODE_IME}, {@link ImeInsetsSourceConsumer} applies the
+     * IME visibility and listens for other state changes.
+     */
+    private ImeInsetsSourceConsumer mImeInsetsConsumer;
+
     final Pool<PendingEvent> mPendingEventPool = new SimplePool<>(20);
     final SparseArray<PendingEvent> mPendingEvents = new SparseArray<>(20);
 
@@ -454,6 +462,8 @@
     static final int MSG_TIMEOUT_INPUT_EVENT = 6;
     static final int MSG_FLUSH_INPUT_EVENT = 7;
     static final int MSG_REPORT_FULLSCREEN_MODE = 10;
+    static final int MSG_REPORT_PRE_RENDERED = 15;
+    static final int MSG_APPLY_IME_VISIBILITY = 20;
 
     private static boolean isAutofillUIShowing(View servedView) {
         AutofillManager afm = servedView.getContext().getSystemService(AutofillManager.class);
@@ -650,6 +660,23 @@
                     }
                     return;
                 }
+                case MSG_REPORT_PRE_RENDERED: {
+                    synchronized (mH) {
+                        if (mImeInsetsConsumer != null) {
+                            mImeInsetsConsumer.onPreRendered((EditorInfo) msg.obj);
+                        }
+                    }
+                    return;
+
+                }
+                case MSG_APPLY_IME_VISIBILITY: {
+                    synchronized (mH) {
+                        if (mImeInsetsConsumer != null) {
+                            mImeInsetsConsumer.applyImeVisibility(msg.arg1 != 0);
+                        }
+                    }
+                    return;
+                }
             }
         }
     }
@@ -729,6 +756,18 @@
                     .sendToTarget();
         }
 
+        @Override
+        public void reportPreRendered(EditorInfo info) {
+            mH.obtainMessage(MSG_REPORT_PRE_RENDERED, 0, 0, info)
+                    .sendToTarget();
+        }
+
+        @Override
+        public void applyImeVisibility(boolean setVisible) {
+            mH.obtainMessage(MSG_APPLY_IME_VISIBILITY, setVisible ? 1 : 0, 0)
+                    .sendToTarget();
+        }
+
     };
 
     final InputConnection mDummyInputConnection = new BaseInputConnection(this, false);
@@ -1515,6 +1554,7 @@
 
             // Hook 'em up and let 'er rip.
             mCurrentTextBoxAttribute = tba;
+            maybeCallServedViewChangedLocked(tba);
             mServedConnecting = false;
             if (mServedInputConnectionWrapper != null) {
                 mServedInputConnectionWrapper.deactivate();
@@ -1730,6 +1770,10 @@
             mCurrentTextBoxAttribute = null;
             mCompletions = null;
             mServedConnecting = true;
+            // servedView has changed and it's not editable.
+            if (!mServedView.onCheckIsTextEditor()) {
+                maybeCallServedViewChangedLocked(null);
+            }
         }
 
         if (ic != null) {
@@ -1828,6 +1872,21 @@
     }
 
     /**
+     * Register for IME state callbacks and applying visibility in
+     * {@link android.view.ImeInsetsSourceConsumer}.
+     * @hide
+     */
+    public void registerImeConsumer(@NonNull ImeInsetsSourceConsumer imeInsetsConsumer) {
+        if (imeInsetsConsumer == null) {
+            throw new IllegalStateException("ImeInsetsSourceConsumer cannot be null.");
+        }
+
+        synchronized (mH) {
+            mImeInsetsConsumer = imeInsetsConsumer;
+        }
+    }
+
+    /**
      * Report the current selection range.
      *
      * <p><strong>Editor authors</strong>, you need to call this method whenever
@@ -2705,6 +2764,12 @@
         }
     }
 
+    private void maybeCallServedViewChangedLocked(EditorInfo tba) {
+        if (mImeInsetsConsumer != null) {
+            mImeInsetsConsumer.onServedEditorChanged(tba);
+        }
+    }
+
     void doDump(FileDescriptor fd, PrintWriter fout, String[] args) {
         final Printer p = new PrintWriterPrinter(fout);
         p.println("Input method client state for " + this + ":");
diff --git a/core/java/android/view/inputmethod/InputMethodSystemProperty.java b/core/java/android/view/inputmethod/InputMethodSystemProperty.java
index 57ed7f9..7c79d44 100644
--- a/core/java/android/view/inputmethod/InputMethodSystemProperty.java
+++ b/core/java/android/view/inputmethod/InputMethodSystemProperty.java
@@ -93,8 +93,14 @@
      * {@code true} when per-profile IME is enabled.
      * @hide
      */
-    public static final boolean PER_PROFILE_IME_ENABLED = MULTI_CLIENT_IME_ENABLED
-            || Build.IS_DEBUGGABLE && SystemProperties.getBoolean(
-                    PROP_DEBUG_PER_PROFILE_IME, false);
-
+    public static final boolean PER_PROFILE_IME_ENABLED;
+    static {
+        if (MULTI_CLIENT_IME_ENABLED) {
+            PER_PROFILE_IME_ENABLED = true;
+        } else if (Build.IS_DEBUGGABLE) {
+            PER_PROFILE_IME_ENABLED = SystemProperties.getBoolean(PROP_DEBUG_PER_PROFILE_IME, true);
+        } else {
+            PER_PROFILE_IME_ENABLED = true;
+        }
+    }
 }
diff --git a/core/java/android/view/textclassifier/TextClassificationConstants.java b/core/java/android/view/textclassifier/TextClassificationConstants.java
index ce680ec..7f928f7 100644
--- a/core/java/android/view/textclassifier/TextClassificationConstants.java
+++ b/core/java/android/view/textclassifier/TextClassificationConstants.java
@@ -46,6 +46,7 @@
  * entity_list_default                      (String[])
  * entity_list_not_editable                 (String[])
  * entity_list_editable                     (String[])
+ * lang_id_threshold_override               (float)
  * </pre>
  *
  * <p>
@@ -94,6 +95,8 @@
             "in_app_conversation_action_types_default";
     private static final String NOTIFICATION_CONVERSATION_ACTION_TYPES_DEFAULT =
             "notification_conversation_action_types_default";
+    private static final String LANG_ID_THRESHOLD_OVERRIDE =
+            "lang_id_threshold_override";
 
     private static final boolean LOCAL_TEXT_CLASSIFIER_ENABLED_DEFAULT = true;
     private static final boolean SYSTEM_TEXT_CLASSIFIER_ENABLED_DEFAULT = true;
@@ -106,8 +109,8 @@
     private static final int CLASSIFY_TEXT_MAX_RANGE_LENGTH_DEFAULT = 10 * 1000;
     private static final int GENERATE_LINKS_MAX_TEXT_LENGTH_DEFAULT = 100 * 1000;
     private static final int GENERATE_LINKS_LOG_SAMPLE_RATE_DEFAULT = 100;
-    private static final String ENTITY_LIST_DELIMITER = ":";
-    private static final String ENTITY_LIST_DEFAULT_VALUE = new StringJoiner(ENTITY_LIST_DELIMITER)
+    private static final String STRING_LIST_DELIMITER = ":";
+    private static final String ENTITY_LIST_DEFAULT_VALUE = new StringJoiner(STRING_LIST_DELIMITER)
             .add(TextClassifier.TYPE_ADDRESS)
             .add(TextClassifier.TYPE_EMAIL)
             .add(TextClassifier.TYPE_PHONE)
@@ -116,7 +119,7 @@
             .add(TextClassifier.TYPE_DATE_TIME)
             .add(TextClassifier.TYPE_FLIGHT_NUMBER).toString();
     private static final String CONVERSATION_ACTIONS_TYPES_DEFAULT_VALUES =
-            new StringJoiner(ENTITY_LIST_DELIMITER)
+            new StringJoiner(STRING_LIST_DELIMITER)
                     .add(ConversationAction.TYPE_TEXT_REPLY)
                     .add(ConversationAction.TYPE_CREATE_REMINDER)
                     .add(ConversationAction.TYPE_CALL_PHONE)
@@ -127,6 +130,13 @@
                     .add(ConversationAction.TYPE_VIEW_CALENDAR)
                     .add(ConversationAction.TYPE_VIEW_MAP)
                     .toString();
+    /**
+     * < 0  : Not set. Use value from LangId model.
+     * 0 - 1: Override value in LangId model.
+     * > 1  : Effectively turns off the foreign language detection. Scores should never be > 1.
+     * @see EntityConfidence
+     */
+    private static final float LANG_ID_THRESHOLD_OVERRIDE_DEFAULT = -1f;
 
     private final boolean mSystemTextClassifierEnabled;
     private final boolean mLocalTextClassifierEnabled;
@@ -144,6 +154,7 @@
     private final List<String> mEntityListEditable;
     private final List<String> mInAppConversationActionTypesDefault;
     private final List<String> mNotificationConversationActionTypesDefault;
+    private final float mLangIdThresholdOverride;
 
     private TextClassificationConstants(@Nullable String settings) {
         final KeyValueListParser parser = new KeyValueListParser(',');
@@ -186,21 +197,24 @@
         mGenerateLinksLogSampleRate = parser.getInt(
                 GENERATE_LINKS_LOG_SAMPLE_RATE,
                 GENERATE_LINKS_LOG_SAMPLE_RATE_DEFAULT);
-        mEntityListDefault = parseEntityList(parser.getString(
+        mEntityListDefault = parseStringList(parser.getString(
                 ENTITY_LIST_DEFAULT,
                 ENTITY_LIST_DEFAULT_VALUE));
-        mEntityListNotEditable = parseEntityList(parser.getString(
+        mEntityListNotEditable = parseStringList(parser.getString(
                 ENTITY_LIST_NOT_EDITABLE,
                 ENTITY_LIST_DEFAULT_VALUE));
-        mEntityListEditable = parseEntityList(parser.getString(
+        mEntityListEditable = parseStringList(parser.getString(
                 ENTITY_LIST_EDITABLE,
                 ENTITY_LIST_DEFAULT_VALUE));
-        mInAppConversationActionTypesDefault = parseEntityList(parser.getString(
+        mInAppConversationActionTypesDefault = parseStringList(parser.getString(
                 IN_APP_CONVERSATION_ACTION_TYPES_DEFAULT,
                 CONVERSATION_ACTIONS_TYPES_DEFAULT_VALUES));
-        mNotificationConversationActionTypesDefault = parseEntityList(parser.getString(
+        mNotificationConversationActionTypesDefault = parseStringList(parser.getString(
                 NOTIFICATION_CONVERSATION_ACTION_TYPES_DEFAULT,
                 CONVERSATION_ACTIONS_TYPES_DEFAULT_VALUES));
+        mLangIdThresholdOverride = parser.getFloat(
+                LANG_ID_THRESHOLD_OVERRIDE,
+                LANG_ID_THRESHOLD_OVERRIDE_DEFAULT);
     }
 
     /** Load from a settings string. */
@@ -272,8 +286,12 @@
         return mNotificationConversationActionTypesDefault;
     }
 
-    private static List<String> parseEntityList(String listStr) {
-        return Collections.unmodifiableList(Arrays.asList(listStr.split(ENTITY_LIST_DELIMITER)));
+    public float getLangIdThresholdOverride() {
+        return mLangIdThresholdOverride;
+    }
+
+    private static List<String> parseStringList(String listStr) {
+        return Collections.unmodifiableList(Arrays.asList(listStr.split(STRING_LIST_DELIMITER)));
     }
 
     void dump(IndentingPrintWriter pw) {
@@ -296,6 +314,7 @@
         pw.printPair("getInAppConversationActionTypes", mInAppConversationActionTypesDefault);
         pw.printPair("getNotificationConversationActionTypes",
                 mNotificationConversationActionTypesDefault);
+        pw.printPair("getLangIdThresholdOverride", mLangIdThresholdOverride);
         pw.decreaseIndent();
         pw.println();
     }
diff --git a/core/java/android/view/textclassifier/TextClassifierImpl.java b/core/java/android/view/textclassifier/TextClassifierImpl.java
index a5b7c62..7782079 100644
--- a/core/java/android/view/textclassifier/TextClassifierImpl.java
+++ b/core/java/android/view/textclassifier/TextClassifierImpl.java
@@ -567,8 +567,9 @@
             }
         }
 
-        // TODO: Make this configurable.
-        final float foreignTextThreshold = typeCount == 0 ? 0.5f : 0.7f;
+        final float foreignTextThreshold = mSettings.getLangIdThresholdOverride() >= 0
+                ? mSettings.getLangIdThresholdOverride()
+                : 0.5f /* TODO: Load this from the langId model. */;
         boolean isPrimaryAction = true;
         final ArrayList<Intent> sourceIntents = new ArrayList<>();
         for (LabeledIntent labeledIntent : IntentFactory.create(
@@ -602,6 +603,10 @@
     }
 
     private boolean isForeignText(String text, float threshold) {
+        if (threshold > 1) {
+            return false;
+        }
+
         // TODO: Revisit this algorithm.
         try {
             final LangIdModel.LanguageResult[] langResults = getLangIdImpl().detectLanguages(text);
diff --git a/core/java/android/view/textclassifier/TextLanguage.java b/core/java/android/view/textclassifier/TextLanguage.java
index b1609fc..735c3eb 100644
--- a/core/java/android/view/textclassifier/TextLanguage.java
+++ b/core/java/android/view/textclassifier/TextLanguage.java
@@ -89,9 +89,10 @@
     /**
      * Returns the language locale at the specified index. Locales are ordered from high
      * confidence to low confidence.
+     * <p>
+     * See {@link #getLocaleHypothesisCount()} for the number of locales available.
      *
      * @throws IndexOutOfBoundsException if the specified index is out of range.
-     * @see #getLocaleHypothesisCount() for the number of locales available.
      */
     @NonNull
     public ULocale getLocale(int index) {
@@ -109,7 +110,8 @@
     }
 
     /**
-     * Returns a bundle containing non-structured extra information about this result.
+     * Returns a bundle containing non-structured extra information about this result. What is
+     * returned in the extras is specific to the {@link TextClassifier} implementation.
      *
      * <p><b>NOTE: </b>Each call to this method returns a new bundle copy so clients should prefer
      * to hold a reference to the returned bundle rather than frequently calling this method.
diff --git a/core/java/android/widget/Magnifier.java b/core/java/android/widget/Magnifier.java
index afe46701..5147306 100644
--- a/core/java/android/widget/Magnifier.java
+++ b/core/java/android/widget/Magnifier.java
@@ -359,7 +359,7 @@
     /**
      * @return the initial width of the content magnified and copied to the magnifier, in pixels
      * @see Magnifier.Builder#setSize(int, int)
-     * @see Magnifier.Builder#setZoom(float)
+     * @see Magnifier.Builder#setInitialZoom(float)
      */
     @Px
     public int getSourceWidth() {
@@ -369,7 +369,7 @@
     /**
      * @return the initial height of the content magnified and copied to the magnifier, in pixels
      * @see Magnifier.Builder#setSize(int, int)
-     * @see Magnifier.Builder#setZoom(float)
+     * @see Magnifier.Builder#setInitialZoom(float)
      */
     @Px
     public int getSourceHeight() {
@@ -394,7 +394,7 @@
      * If the zoom is x and the magnifier window size is (width, height), the original size
      * of the content being magnified will be (width / x, height / x).
      * @return the zoom applied to the content
-     * @see Magnifier.Builder#setZoom(float)
+     * @see Magnifier.Builder#setInitialZoom(float)
      */
     public float getZoom() {
         return mZoom;
@@ -1196,10 +1196,12 @@
          * (content_width * zoom, content_height * zoom), which will coincide with the size
          * of the magnifier. A zoom of 1 will translate to no magnification (the content will
          * be just copied to the magnifier with no scaling). The zoom defaults to 1.25.
+         * Note that the zoom can also be changed after the instance is built, using the
+         * {@link Magnifier#setZoom(float)} method.
          * @param zoom the zoom to be set
          */
         @NonNull
-        public Builder setZoom(@FloatRange(from = 0f) float zoom) {
+        public Builder setInitialZoom(@FloatRange(from = 0f) float zoom) {
             Preconditions.checkArgumentPositive(zoom, "Zoom should be positive");
             mZoom = zoom;
             return this;
diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java
index 803462d..299801a 100644
--- a/core/java/com/android/internal/app/ChooserActivity.java
+++ b/core/java/com/android/internal/app/ChooserActivity.java
@@ -22,6 +22,8 @@
 import android.app.prediction.AppPredictionManager;
 import android.app.prediction.AppPredictor;
 import android.app.prediction.AppTarget;
+import android.app.prediction.AppTargetEvent;
+import android.app.prediction.AppTargetId;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
@@ -111,6 +113,7 @@
     private static final boolean USE_PREDICTION_MANAGER_FOR_DIRECT_TARGETS = false;
     // TODO(b/123088566) Share these in a better way.
     private static final String APP_PREDICTION_SHARE_UI_SURFACE = "share";
+    public static final String LAUNCH_LOCATON_DIRECT_SHARE = "direct_share";
     private static final int APP_PREDICTION_SHARE_TARGET_QUERY_PACKAGE_LIMIT = 20;
     public static final String APP_PREDICTION_INTENT_FILTER_KEY = "intent_filter";
     private AppPredictor mAppPredictor;
@@ -787,9 +790,11 @@
         // Do nothing. We'll send the voice stuff ourselves.
     }
 
-    // TODO(b/123377860) Send clicked ShortcutInfo to mAppPredictor
     void updateModelAndChooserCounts(TargetInfo info) {
         if (info != null) {
+            if (USE_PREDICTION_MANAGER_FOR_DIRECT_TARGETS) {
+                sendClickToAppPredictor(info);
+            }
             final ResolveInfo ri = info.getResolveInfo();
             Intent targetIntent = getTargetIntent();
             if (ri != null && ri.activityInfo != null && targetIntent != null) {
@@ -802,13 +807,39 @@
                     Log.d(TAG, "ResolveInfo Package is " + ri.activityInfo.packageName);
                     Log.d(TAG, "Action to be updated is " + targetIntent.getAction());
                 }
-            } else if(DEBUG) {
+            } else if (DEBUG) {
                 Log.d(TAG, "Can not log Chooser Counts of null ResovleInfo");
             }
         }
         mIsSuccessfullySelected = true;
     }
 
+    private void sendClickToAppPredictor(TargetInfo targetInfo) {
+        if (!(targetInfo instanceof ChooserTargetInfo)) {
+            return;
+        }
+        ChooserTarget chooserTarget = ((ChooserTargetInfo) targetInfo).getChooserTarget();
+        ComponentName componentName = chooserTarget.getComponentName();
+        Bundle extras = chooserTarget.getIntentExtras();
+        if (extras == null) {
+            return;
+        }
+        String shortcutId = extras.getString(Intent.EXTRA_SHORTCUT_ID);
+        if (shortcutId == null) {
+            return;
+        }
+        mAppPredictor.notifyAppTargetEvent(
+                new AppTargetEvent.Builder(
+                    new AppTarget(
+                        new AppTargetId(shortcutId),
+                        componentName.getPackageName(),
+                        componentName.getClassName(),
+                        getUser()),
+                    AppTargetEvent.ACTION_LAUNCH
+                ).setLaunchLocation(LAUNCH_LOCATON_DIRECT_SHARE)
+                .build());
+    }
+
     void onRefinementResult(TargetInfo selectedTarget, Intent matchingIntent) {
         if (mRefinementResultReceiver != null) {
             mRefinementResultReceiver.destroy();
@@ -1128,6 +1159,10 @@
             return mBadgeContentDescription;
         }
 
+        public ChooserTarget getChooserTarget() {
+            return mChooserTarget;
+        }
+
         @Override
         public TargetInfo cloneFilledIn(Intent fillInIntent, int flags) {
             return new ChooserTargetInfo(this, fillInIntent, flags);
diff --git a/core/java/com/android/internal/inputmethod/IInputMethodPrivilegedOperations.aidl b/core/java/com/android/internal/inputmethod/IInputMethodPrivilegedOperations.aidl
index d0272e0..e27ff00 100644
--- a/core/java/com/android/internal/inputmethod/IInputMethodPrivilegedOperations.aidl
+++ b/core/java/com/android/internal/inputmethod/IInputMethodPrivilegedOperations.aidl
@@ -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.
@@ -17,6 +17,7 @@
 package com.android.internal.inputmethod;
 
 import android.net.Uri;
+import android.view.inputmethod.EditorInfo;
 import android.view.inputmethod.InputMethodSubtype;
 
 import com.android.internal.inputmethod.IInputContentUriToken;
@@ -39,4 +40,6 @@
     boolean switchToNextInputMethod(boolean onlyCurrentIme);
     boolean shouldOfferSwitchingToNextInputMethod();
     void notifyUserAction();
+    void reportPreRendered(in EditorInfo info);
+    void applyImeVisibility(boolean setVisible);
 }
diff --git a/core/java/com/android/internal/inputmethod/InputMethodPrivilegedOperations.java b/core/java/com/android/internal/inputmethod/InputMethodPrivilegedOperations.java
index 8978496..d42c607 100644
--- a/core/java/com/android/internal/inputmethod/InputMethodPrivilegedOperations.java
+++ b/core/java/com/android/internal/inputmethod/InputMethodPrivilegedOperations.java
@@ -23,6 +23,7 @@
 import android.os.IBinder;
 import android.os.RemoteException;
 import android.util.Log;
+import android.view.inputmethod.EditorInfo;
 import android.view.inputmethod.InputMethodSubtype;
 
 import com.android.internal.annotations.GuardedBy;
@@ -347,4 +348,40 @@
             throw e.rethrowFromSystemServer();
         }
     }
+
+    /**
+     * Calls {@link IInputMethodPrivilegedOperations#reportPreRendered(info)}.
+     *
+     * @param info {@link EditorInfo} of the currently rendered {@link TextView}.
+     */
+    @AnyThread
+    public void reportPreRendered(EditorInfo info) {
+        final IInputMethodPrivilegedOperations ops = mOps.getAndWarnIfNull();
+        if (ops == null) {
+            return;
+        }
+        try {
+            ops.reportPreRendered(info);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Calls {@link IInputMethodPrivilegedOperations#applyImeVisibility(boolean)}.
+     *
+     * @param setVisible {@code true} to set IME visible, else hidden.
+     */
+    @AnyThread
+    public void applyImeVisibility(boolean setVisible) {
+        final IInputMethodPrivilegedOperations ops = mOps.getAndWarnIfNull();
+        if (ops == null) {
+            return;
+        }
+        try {
+            ops.applyImeVisibility(setVisible);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
 }
diff --git a/core/java/com/android/internal/statusbar/IStatusBar.aidl b/core/java/com/android/internal/statusbar/IStatusBar.aidl
index 6a28059..943c726 100644
--- a/core/java/com/android/internal/statusbar/IStatusBar.aidl
+++ b/core/java/com/android/internal/statusbar/IStatusBar.aidl
@@ -160,4 +160,9 @@
     void onBiometricError(String error);
     // Used to hide the biometric dialog when the AuthenticationClient is stopped
     void hideBiometricDialog();
+
+    /**
+     * Notifies System UI that the display is ready to show system decorations.
+     */
+    void onDisplayReady(int displayId);
 }
diff --git a/core/java/com/android/internal/util/StateMachine.java b/core/java/com/android/internal/util/StateMachine.java
index e5ad1f4..7398e95 100644
--- a/core/java/com/android/internal/util/StateMachine.java
+++ b/core/java/com/android/internal/util/StateMachine.java
@@ -16,6 +16,7 @@
 
 package com.android.internal.util;
 
+import android.annotation.UnsupportedAppUsage;
 import android.os.Handler;
 import android.os.HandlerThread;
 import android.os.Looper;
@@ -1354,6 +1355,7 @@
      * Add a new state to the state machine, parent will be null
      * @param state to add
      */
+    @UnsupportedAppUsage
     public final void addState(State state) {
         mSmHandler.addState(state, null);
     }
@@ -1372,6 +1374,7 @@
      *
      * @param initialState is the state which will receive the first message.
      */
+    @UnsupportedAppUsage
     public final void setInitialState(State initialState) {
         mSmHandler.setInitialState(initialState);
     }
@@ -1410,6 +1413,7 @@
      *
      * @param destState will be the state that receives the next message.
      */
+    @UnsupportedAppUsage
     public final void transitionTo(IState destState) {
         mSmHandler.transitionTo(destState);
     }
@@ -2053,6 +2057,7 @@
     /**
      * Start the state machine.
      */
+    @UnsupportedAppUsage
     public void start() {
         // mSmHandler can be null if the state machine has quit.
         SmHandler smh = mSmHandler;
diff --git a/core/java/com/android/internal/view/IInputMethodClient.aidl b/core/java/com/android/internal/view/IInputMethodClient.aidl
index 17b2bc4..2cfdaaa 100644
--- a/core/java/com/android/internal/view/IInputMethodClient.aidl
+++ b/core/java/com/android/internal/view/IInputMethodClient.aidl
@@ -16,6 +16,8 @@
 
 package com.android.internal.view;
 
+import android.view.inputmethod.EditorInfo;
+
 import com.android.internal.view.InputBindResult;
 
 /**
@@ -27,4 +29,6 @@
     void onUnbindMethod(int sequence, int unbindReason);
     void setActive(boolean active, boolean fullscreen);
     void reportFullscreenMode(boolean fullscreen);
+    void reportPreRendered(in EditorInfo info);
+    void applyImeVisibility(boolean setVisible);
 }
diff --git a/core/jni/Android.bp b/core/jni/Android.bp
index be12700..9afd5d0 100644
--- a/core/jni/Android.bp
+++ b/core/jni/Android.bp
@@ -166,6 +166,7 @@
         "android_media_AudioRecord.cpp",
         "android_media_AudioSystem.cpp",
         "android_media_AudioTrack.cpp",
+        "android_media_AudioAttributes.cpp",
         "android_media_DeviceCallback.cpp",
         "android_media_JetPlayer.cpp",
         "android_media_MediaMetricsJNI.cpp",
@@ -275,6 +276,7 @@
         "libselinux",
         "libandroidicu",
         "libmedia",
+        "libmedia_helper",
         "libmediametrics",
         "libmeminfo",
         "libaudioclient",
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index f458299..c90071a 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -107,6 +107,7 @@
 extern int register_android_media_AudioRecord(JNIEnv *env);
 extern int register_android_media_AudioSystem(JNIEnv *env);
 extern int register_android_media_AudioTrack(JNIEnv *env);
+extern int register_android_media_AudioAttributes(JNIEnv *env);
 extern int register_android_media_MicrophoneInfo(JNIEnv *env);
 extern int register_android_media_JetPlayer(JNIEnv *env);
 extern int register_android_media_ToneGenerator(JNIEnv *env);
@@ -1470,6 +1471,7 @@
     REG_JNI(register_android_media_AudioSystem),
     REG_JNI(register_android_media_AudioRecord),
     REG_JNI(register_android_media_AudioTrack),
+    REG_JNI(register_android_media_AudioAttributes),
     REG_JNI(register_android_media_JetPlayer),
     REG_JNI(register_android_media_MicrophoneInfo),
     REG_JNI(register_android_media_RemoteDisplay),
diff --git a/core/jni/android/graphics/Bitmap.cpp b/core/jni/android/graphics/Bitmap.cpp
index 5de0883..c74797b 100755
--- a/core/jni/android/graphics/Bitmap.cpp
+++ b/core/jni/android/graphics/Bitmap.cpp
@@ -93,6 +93,11 @@
         mBitmap->setAlphaType(alphaType);
     }
 
+    void setColorSpace(sk_sp<SkColorSpace> colorSpace) {
+        assertValid();
+        mBitmap->setColorSpace(colorSpace);
+    }
+
     const SkImageInfo& info() {
         if (mBitmap) {
             return mBitmap->info();
@@ -959,6 +964,12 @@
     return JNI_TRUE;
 }
 
+static void Bitmap_setColorSpace(JNIEnv* env, jobject, jlong bitmapHandle, jlong colorSpacePtr) {
+    LocalScopedBitmap bitmapHolder(bitmapHandle);
+    sk_sp<SkColorSpace> cs = GraphicsJNI::getNativeColorSpace(colorSpacePtr);
+    bitmapHolder->setColorSpace(cs);
+}
+
 ///////////////////////////////////////////////////////////////////////////////
 
 static jint Bitmap_getPixel(JNIEnv* env, jobject, jlong bitmapHandle,
@@ -1239,6 +1250,7 @@
     {   "nativeCreateGraphicBufferHandle", "(J)Landroid/graphics/GraphicBuffer;",
         (void*) Bitmap_createGraphicBufferHandle },
     {   "nativeGetColorSpace",      "(J[F[F)Z", (void*)Bitmap_getColorSpace },
+    {   "nativeSetColorSpace",      "(JJ)V", (void*)Bitmap_setColorSpace },
     {   "nativeIsSRGB",             "(J)Z", (void*)Bitmap_isSRGB },
     {   "nativeIsSRGBLinear",       "(J)Z", (void*)Bitmap_isSRGBLinear},
     {   "nativeCopyColorSpace",     "(JJ)V",
diff --git a/core/jni/android/graphics/BitmapFactory.cpp b/core/jni/android/graphics/BitmapFactory.cpp
index 7d0d3d8..3f9ec45 100644
--- a/core/jni/android/graphics/BitmapFactory.cpp
+++ b/core/jni/android/graphics/BitmapFactory.cpp
@@ -549,7 +549,7 @@
     // if we only close the file descriptor and not the file object it is used to
     // create.  If we don't explicitly clean up the file (which in turn closes the
     // descriptor) the buffers allocated internally by fseek will be leaked.
-    int dupDescriptor = dup(descriptor);
+    int dupDescriptor = fcntl(descriptor, F_DUPFD_CLOEXEC, 0);
 
     FILE* file = fdopen(dupDescriptor, "r");
     if (file == NULL) {
diff --git a/core/jni/android/graphics/ImageDecoder.cpp b/core/jni/android/graphics/ImageDecoder.cpp
index 5f12665..72e14e7 100644
--- a/core/jni/android/graphics/ImageDecoder.cpp
+++ b/core/jni/android/graphics/ImageDecoder.cpp
@@ -132,7 +132,7 @@
                                "broken file descriptor; fstat returned -1", nullptr, source);
     }
 
-    int dupDescriptor = dup(descriptor);
+    int dupDescriptor = fcntl(descriptor, F_DUPFD_CLOEXEC, 0);
     FILE* file = fdopen(dupDescriptor, "r");
     if (file == NULL) {
         close(dupDescriptor);
diff --git a/core/jni/android_content_res_ApkAssets.cpp b/core/jni/android_content_res_ApkAssets.cpp
index 7738d84..f40b461 100644
--- a/core/jni/android_content_res_ApkAssets.cpp
+++ b/core/jni/android_content_res_ApkAssets.cpp
@@ -72,7 +72,7 @@
     return 0;
   }
 
-  unique_fd dup_fd(::dup(fd));
+  unique_fd dup_fd(::fcntl(fd, F_DUPFD_CLOEXEC, 0));
   if (dup_fd < 0) {
     jniThrowIOException(env, errno);
     return 0;
diff --git a/core/jni/android_ddm_DdmHandleNativeHeap.cpp b/core/jni/android_ddm_DdmHandleNativeHeap.cpp
index 2f25d8f..e22f581 100644
--- a/core/jni/android_ddm_DdmHandleNativeHeap.cpp
+++ b/core/jni/android_ddm_DdmHandleNativeHeap.cpp
@@ -54,7 +54,7 @@
 namespace android {
 
 static void ReadFile(const char* path, String8& s) {
-    int fd = open(path, O_RDONLY);
+    int fd = open(path, O_RDONLY | O_CLOEXEC);
     if (fd != -1) {
         char bytes[1024];
         ssize_t byteCount;
diff --git a/core/jni/android_hardware_HardwareBuffer.cpp b/core/jni/android_hardware_HardwareBuffer.cpp
index 8174a41..2d1fec8 100644
--- a/core/jni/android_hardware_HardwareBuffer.cpp
+++ b/core/jni/android_hardware_HardwareBuffer.cpp
@@ -104,6 +104,21 @@
     return static_cast<jlong>(reinterpret_cast<uintptr_t>(&destroyWrapper));
 }
 
+static jboolean android_hardware_HardwareBuffer_isSupported(JNIEnv* env, jobject clazz,
+        jint width, jint height, jint format, jint layers, jlong usage) {
+
+    AHardwareBuffer_Desc desc;
+    desc.width = width;
+    desc.height = height;
+    desc.format = format;
+    desc.layers = layers;
+    desc.usage = usage;
+    desc.stride = 0;
+    desc.rfu0 = 0;
+    desc.rfu1 = 0;
+    return AHardwareBuffer_isSupported(&desc);
+}
+
 //----------------------------------------------------------------------------
 // Accessors
 // ----------------------------------------------------------------------------
@@ -234,6 +249,8 @@
             (void*) android_hardware_HardwareBuffer_write },
     { "nReadHardwareBufferFromParcel", "(Landroid/os/Parcel;)J",
             (void*) android_hardware_HardwareBuffer_read },
+    { "nIsSupported",  "(IIIIJ)Z",
+            (void*) android_hardware_HardwareBuffer_isSupported },
 
     // --------------- @FastNative ----------------------
     { "nGetWidth", "(J)I",      (void*) android_hardware_HardwareBuffer_getWidth },
diff --git a/core/jni/android_hardware_SerialPort.cpp b/core/jni/android_hardware_SerialPort.cpp
index 190ddce..3ff2446 100644
--- a/core/jni/android_hardware_SerialPort.cpp
+++ b/core/jni/android_hardware_SerialPort.cpp
@@ -134,7 +134,7 @@
 
     int fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
     // duplicate the file descriptor, since ParcelFileDescriptor will eventually close its copy
-    fd = dup(fd);
+    fd = fcntl(fd, F_DUPFD_CLOEXEC, 0);
     if (fd < 0) {
         jniThrowException(env, "java/io/IOException", "Could not open serial port");
         return;
diff --git a/core/jni/android_hardware_UsbDeviceConnection.cpp b/core/jni/android_hardware_UsbDeviceConnection.cpp
index d953aee..b885c28 100644
--- a/core/jni/android_hardware_UsbDeviceConnection.cpp
+++ b/core/jni/android_hardware_UsbDeviceConnection.cpp
@@ -49,7 +49,7 @@
 {
     int fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
     // duplicate the file descriptor, since ParcelFileDescriptor will eventually close its copy
-    fd = dup(fd);
+    fd = fcntl(fd, F_DUPFD_CLOEXEC, 0);
     if (fd < 0)
         return JNI_FALSE;
 
diff --git a/core/jni/android_media_AudioAttributes.cpp b/core/jni/android_media_AudioAttributes.cpp
new file mode 100644
index 0000000..bfe6162
--- /dev/null
+++ b/core/jni/android_media_AudioAttributes.cpp
@@ -0,0 +1,205 @@
+/*
+ * 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.
+ */
+
+//#define LOG_NDEBUG 0
+
+#define LOG_TAG "AudioAttributes-JNI"
+
+#include <inttypes.h>
+#include <jni.h>
+#include <nativehelper/JNIHelp.h>
+#include "core_jni_helpers.h"
+
+#include <utils/Log.h>
+#include <vector>
+
+#include <nativehelper/ScopedLocalRef.h>
+#include <nativehelper/ScopedUtfChars.h>
+
+#include "android_media_AudioAttributes.h"
+#include "android_media_AudioErrors.h"
+
+// ----------------------------------------------------------------------------
+
+using namespace android;
+
+// ----------------------------------------------------------------------------
+static const char* const kClassPathName = "android/media/AudioAttributes";
+
+static jclass gAudioAttributesClass;
+static struct {
+    jfieldID    mUsage;         // AudioAttributes.mUsage
+    jfieldID    mSource;        // AudioAttributes.mSource
+    jfieldID    mContentType;   // AudioAttributes.mContentType
+    jfieldID    mFlags;         // AudioAttributes.mFlags
+    jfieldID    mFormattedTags; // AudioAttributes.mFormattedTags
+} gAudioAttributesFields;
+
+static jclass gAudioAttributesBuilderClass;
+static jmethodID gAudioAttributesBuilderCstor;
+static struct {
+    jmethodID build;
+    jmethodID setUsage;
+    jmethodID setInternalCapturePreset;
+    jmethodID setContentType;
+    jmethodID setFlags;
+    jmethodID addTag;
+} gAudioAttributesBuilderMethods;
+
+
+static jint nativeAudioAttributesFromJavaAudioAttributes(
+        JNIEnv* env, jobject jAudioAttributes, audio_attributes_t *aa)
+{
+    if (env == nullptr) {
+        return AUDIO_JAVA_DEAD_OBJECT;
+    }
+    if (jAudioAttributes == nullptr) {
+        ALOGE("Invalid AudioAttributes java object");
+        return (jint)AUDIO_JAVA_BAD_VALUE;
+    }
+    if (!env->IsInstanceOf(jAudioAttributes, gAudioAttributesClass)) {
+        return (jint)AUDIO_JAVA_BAD_VALUE;
+    }
+    const jstring jtags =
+            (jstring) env->GetObjectField(jAudioAttributes, gAudioAttributesFields.mFormattedTags);
+    if (jtags == nullptr) {
+        return AUDIO_JAVA_NO_INIT;
+    }
+    const char* tags = env->GetStringUTFChars(jtags, NULL);
+    // copying array size -1, char array for tags was calloc'd, no need to NULL-terminate it
+    strncpy(aa->tags, tags, AUDIO_ATTRIBUTES_TAGS_MAX_SIZE - 1);
+    env->ReleaseStringUTFChars(jtags, tags);
+
+    // Record ?
+    aa->source = (audio_source_t) env->GetIntField(jAudioAttributes,
+                                                    gAudioAttributesFields.mSource);
+    // Track ?
+    aa->usage = (audio_usage_t) env->GetIntField(jAudioAttributes, gAudioAttributesFields.mUsage);
+
+    aa->content_type =
+            (audio_content_type_t) env->GetIntField(jAudioAttributes,
+                                                    gAudioAttributesFields.mContentType);
+
+    aa->flags = (audio_flags_mask_t)env->GetIntField(jAudioAttributes,
+                                                      gAudioAttributesFields.mFlags);
+
+    ALOGV("AudioAttributes for usage=%d content=%d source=%d tags=%s flags=%08x tags=%s",
+          aa->usage, aa->content_type, aa->source, aa->tags, aa->flags, aa->tags);
+    return (jint)AUDIO_JAVA_SUCCESS;
+}
+
+static jint nativeAudioAttributesToJavaAudioAttributes(
+        JNIEnv* env, jobject *jAudioAttributes, const audio_attributes_t &attributes)
+{
+    ScopedLocalRef<jobject> jAttributeBuilder(env, env->NewObject(gAudioAttributesBuilderClass,
+                                                                  gAudioAttributesBuilderCstor));
+    if (jAttributeBuilder.get() == nullptr) {
+        return (jint)AUDIO_JAVA_ERROR;
+    }
+    env->CallObjectMethod(jAttributeBuilder.get(),
+                          gAudioAttributesBuilderMethods.setUsage,
+                          attributes.usage);
+    env->CallObjectMethod(jAttributeBuilder.get(),
+                          gAudioAttributesBuilderMethods.setInternalCapturePreset,
+                          attributes.source);
+    env->CallObjectMethod(jAttributeBuilder.get(),
+                          gAudioAttributesBuilderMethods.setContentType,
+                          attributes.content_type);
+    env->CallObjectMethod(jAttributeBuilder.get(),
+                          gAudioAttributesBuilderMethods.setFlags,
+                          attributes.flags);
+    env->CallObjectMethod(jAttributeBuilder.get(),
+                          gAudioAttributesBuilderMethods.addTag,
+                          env->NewStringUTF(attributes.tags));
+
+    *jAudioAttributes = env->CallObjectMethod(jAttributeBuilder.get(),
+                                              gAudioAttributesBuilderMethods.build);
+    return (jint)AUDIO_JAVA_SUCCESS;
+}
+
+// ----------------------------------------------------------------------------
+JNIAudioAttributeHelper::UniqueAaPtr JNIAudioAttributeHelper::makeUnique()
+{
+    audio_attributes_t *aa = new (calloc(1, sizeof(audio_attributes_t)))
+                audio_attributes_t{AUDIO_ATTRIBUTES_INITIALIZER};
+    return UniqueAaPtr{aa, free};
+}
+
+jint JNIAudioAttributeHelper::nativeFromJava(JNIEnv* env, jobject jAudioAttributes,
+                                             audio_attributes_t *paa)
+{
+    return nativeAudioAttributesFromJavaAudioAttributes(env, jAudioAttributes, paa);
+}
+
+jint JNIAudioAttributeHelper::nativeToJava(
+        JNIEnv* env, jobject *jAudioAttributes, const audio_attributes_t &attributes)
+{
+    return nativeAudioAttributesToJavaAudioAttributes(env, jAudioAttributes, attributes);
+}
+
+jint JNIAudioAttributeHelper::getJavaArray(
+        JNIEnv* env, jobjectArray *jAudioAttributeArray, jint numAudioAttributes)
+{
+    *jAudioAttributeArray = env->NewObjectArray(numAudioAttributes, gAudioAttributesClass, NULL);
+    return jAudioAttributeArray == NULL? (jint)AUDIO_JAVA_ERROR : (jint)AUDIO_JAVA_SUCCESS;
+}
+
+/*
+ * JNI registration.
+ */
+static const JNINativeMethod gMethods[] = {
+    // n/a
+};
+
+int register_android_media_AudioAttributes(JNIEnv *env)
+{
+    jclass audioAttributesClass = FindClassOrDie(env, kClassPathName);
+    gAudioAttributesClass = MakeGlobalRefOrDie(env, audioAttributesClass);
+    gAudioAttributesFields.mUsage = GetFieldIDOrDie(env, audioAttributesClass, "mUsage", "I");
+    gAudioAttributesFields.mSource = GetFieldIDOrDie(env, audioAttributesClass, "mSource", "I");
+    gAudioAttributesFields.mContentType =
+            GetFieldIDOrDie(env, audioAttributesClass, "mContentType", "I");
+    gAudioAttributesFields.mFlags = GetFieldIDOrDie(env, audioAttributesClass, "mFlags", "I");
+    gAudioAttributesFields.mFormattedTags =
+            GetFieldIDOrDie(env, audioAttributesClass, "mFormattedTags", "Ljava/lang/String;");
+
+    jclass audioAttributesBuilderClass = FindClassOrDie(
+                env, "android/media/AudioAttributes$Builder");
+    gAudioAttributesBuilderClass = MakeGlobalRefOrDie(env, audioAttributesBuilderClass);
+    gAudioAttributesBuilderCstor = GetMethodIDOrDie(
+                env, audioAttributesBuilderClass, "<init>", "()V");
+    gAudioAttributesBuilderMethods.build = GetMethodIDOrDie(
+                env, audioAttributesBuilderClass, "build", "()Landroid/media/AudioAttributes;");
+    gAudioAttributesBuilderMethods.setUsage = GetMethodIDOrDie(
+                env, audioAttributesBuilderClass, "setUsage",
+                "(I)Landroid/media/AudioAttributes$Builder;");
+    gAudioAttributesBuilderMethods.setInternalCapturePreset = GetMethodIDOrDie(
+                env, audioAttributesBuilderClass, "setInternalCapturePreset",
+                "(I)Landroid/media/AudioAttributes$Builder;");
+    gAudioAttributesBuilderMethods.setContentType = GetMethodIDOrDie(
+                env, audioAttributesBuilderClass, "setContentType",
+                "(I)Landroid/media/AudioAttributes$Builder;");
+    gAudioAttributesBuilderMethods.setFlags = GetMethodIDOrDie(
+                env, audioAttributesBuilderClass, "setFlags",
+                "(I)Landroid/media/AudioAttributes$Builder;");
+    gAudioAttributesBuilderMethods.addTag = GetMethodIDOrDie(
+                env, audioAttributesBuilderClass, "addTag",
+                "(Ljava/lang/String;)Landroid/media/AudioAttributes$Builder;");
+
+    env->DeleteLocalRef(audioAttributesClass);
+
+    return RegisterMethodsOrDie(env, kClassPathName, gMethods, NELEM(gMethods));
+}
diff --git a/core/jni/android_media_AudioAttributes.h b/core/jni/android_media_AudioAttributes.h
new file mode 100644
index 0000000..c558352
--- /dev/null
+++ b/core/jni/android_media_AudioAttributes.h
@@ -0,0 +1,70 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include "jni.h"
+
+#include <memory.h>
+
+#include <system/audio.h>
+
+namespace android {
+
+class JNIAudioAttributeHelper
+{
+public:
+    using UniqueAaPtr = std::unique_ptr<audio_attributes_t, decltype(free)*>;
+
+    /**
+     * @brief makeUnique helper to prevent leak
+     * @return a unique ptr of 0-initialized native audio attributes structure
+     */
+    static UniqueAaPtr makeUnique();
+
+    /**
+     * @brief nativeFromJava Gets the underlying AudioAttributes from an AudioAttributes Java
+     * object.
+     * @param env
+     * @param jAudioAttributes JAVA AudioAttribute object
+     * @param paa native AudioAttribute pointer
+     * @return AUDIO_JAVA_SUCCESS on success, error code otherwise
+     */
+    static jint nativeFromJava(
+            JNIEnv* env, jobject jAudioAttributes, audio_attributes_t *attributes);
+
+    /**
+     * @brief nativeToJava AudioAttributes Java object from a native AudioAttributes.
+     * @param env
+     * @param jAudioAttributes JAVA AudioAttribute object
+     * @param attributes native AudioAttribute
+     * @return AUDIO_JAVA_SUCCESS on success, error code otherwise
+     */
+    static jint nativeToJava(
+            JNIEnv* env, jobject *jAudioAttributes, const audio_attributes_t &attributes);
+
+    /**
+     * @brief getJavaArray: creates an array of JAVA AudioAttributes objects
+     * @param env
+     * @param jAudioAttributeArray
+     * @param numAudioAttributes
+     * @return Array of AudioAttributes objects
+     */
+    static jint getJavaArray(
+            JNIEnv* env, jobjectArray *jAudioAttributeArray, jint numAudioAttributes);
+};
+
+}; // namespace android
diff --git a/core/jni/android_media_AudioRecord.cpp b/core/jni/android_media_AudioRecord.cpp
index 67c3064..02dffdc2 100644
--- a/core/jni/android_media_AudioRecord.cpp
+++ b/core/jni/android_media_AudioRecord.cpp
@@ -35,6 +35,7 @@
 #include "android_media_DeviceCallback.h"
 #include "android_media_MediaMetricsJNI.h"
 #include "android_media_MicrophoneInfo.h"
+#include "android_media_AudioAttributes.h"
 
 // ----------------------------------------------------------------------------
 
@@ -42,7 +43,6 @@
 
 // ----------------------------------------------------------------------------
 static const char* const kClassPathName = "android/media/AudioRecord";
-static const char* const kAudioAttributesClassPathName = "android/media/AudioAttributes";
 
 static jclass gArrayListClass;
 static struct {
@@ -56,12 +56,6 @@
     jfieldID  nativeCallbackCookie;    // provides access to the AudioRecord callback data
     jfieldID  nativeDeviceCallback;    // provides access to the JNIDeviceCallback instance
 };
-struct audio_attributes_fields_t {
-    jfieldID  fieldRecSource;    // AudioAttributes.mSource
-    jfieldID  fieldFlags;        // AudioAttributes.mFlags
-    jfieldID  fieldFormattedTags;// AudioAttributes.mFormattedTags
-};
-static audio_attributes_fields_t javaAudioAttrFields;
 static audio_record_fields_t     javaAudioRecordFields;
 static struct {
     jfieldID  fieldFramePosition;     // AudioTimestamp.framePosition
@@ -213,7 +207,6 @@
     env->ReleasePrimitiveArrayCritical(jSession, nSession, 0);
     nSession = NULL;
 
-    audio_attributes_t *paa = NULL;
     sp<AudioRecord> lpRecorder = 0;
     audiorecord_callback_cookie *lpCallbackData = NULL;
 
@@ -275,15 +268,11 @@
         lpRecorder = new AudioRecord(String16(opPackageNameStr.c_str()));
 
         // read the AudioAttributes values
-        paa = (audio_attributes_t *) calloc(1, sizeof(audio_attributes_t));
-        const jstring jtags =
-                (jstring) env->GetObjectField(jaa, javaAudioAttrFields.fieldFormattedTags);
-        const char* tags = env->GetStringUTFChars(jtags, NULL);
-        // copying array size -1, char array for tags was calloc'd, no need to NULL-terminate it
-        strncpy(paa->tags, tags, AUDIO_ATTRIBUTES_TAGS_MAX_SIZE - 1);
-        env->ReleaseStringUTFChars(jtags, tags);
-        paa->source = (audio_source_t) env->GetIntField(jaa, javaAudioAttrFields.fieldRecSource);
-        paa->flags = (audio_flags_mask_t)env->GetIntField(jaa, javaAudioAttrFields.fieldFlags);
+        auto paa = JNIAudioAttributeHelper::makeUnique();
+        jint jStatus = JNIAudioAttributeHelper::nativeFromJava(env, jaa, paa.get());
+        if (jStatus != (jint)AUDIO_JAVA_SUCCESS) {
+            return jStatus;
+        }
         ALOGV("AudioRecord_setup for source=%d tags=%s flags=%08x", paa->source, paa->tags, paa->flags);
 
         audio_input_flags_t flags = AUDIO_INPUT_FLAG_NONE;
@@ -311,7 +300,7 @@
             AudioRecord::TRANSFER_DEFAULT,
             flags,
             -1, -1,        // default uid, pid
-            paa);
+            paa.get());
 
         if (status != NO_ERROR) {
             ALOGE("Error creating AudioRecord instance: initialization check failed with status %d.",
@@ -368,19 +357,10 @@
     // of the Java object (in mNativeCallbackCookie) so we can free the memory in finalize()
     env->SetLongField(thiz, javaAudioRecordFields.nativeCallbackCookie, (jlong)lpCallbackData);
 
-    if (paa != NULL) {
-        // audio attributes were copied in AudioRecord creation
-        free(paa);
-        paa = NULL;
-    }
-
     return (jint) AUDIO_JAVA_SUCCESS;
 
     // failure:
 native_init_failure:
-    if (paa != NULL) {
-        free(paa);
-    }
     env->DeleteGlobalRef(lpCallbackData->audioRecord_class);
     env->DeleteGlobalRef(lpCallbackData->audioRecord_ref);
     delete lpCallbackData;
@@ -972,13 +952,6 @@
     javaAudioRecordFields.nativeDeviceCallback = GetFieldIDOrDie(env,
             audioRecordClass, JAVA_NATIVEDEVICECALLBACK_FIELD_NAME, "J");
 
-    // Get the AudioAttributes class and fields
-    jclass audioAttrClass = FindClassOrDie(env, kAudioAttributesClassPathName);
-    javaAudioAttrFields.fieldRecSource = GetFieldIDOrDie(env, audioAttrClass, "mSource", "I");
-    javaAudioAttrFields.fieldFlags = GetFieldIDOrDie(env, audioAttrClass, "mFlags", "I");
-    javaAudioAttrFields.fieldFormattedTags = GetFieldIDOrDie(env,
-            audioAttrClass, "mFormattedTags", "Ljava/lang/String;");
-
     // Get the RecordTimestamp class and fields
     jclass audioTimestampClass = FindClassOrDie(env, "android/media/AudioTimestamp");
     javaAudioTimestampFields.fieldFramePosition =
diff --git a/core/jni/android_media_AudioSystem.cpp b/core/jni/android_media_AudioSystem.cpp
index 0d8ede7..34abcd8 100644
--- a/core/jni/android_media_AudioSystem.cpp
+++ b/core/jni/android_media_AudioSystem.cpp
@@ -36,6 +36,7 @@
 #include "android_media_AudioFormat.h"
 #include "android_media_AudioErrors.h"
 #include "android_media_MicrophoneInfo.h"
+#include "android_media_AudioAttributes.h"
 
 // ----------------------------------------------------------------------------
 
@@ -153,15 +154,6 @@
     jfieldID    mRule;
 } gAudioMixMatchCriterionFields;
 
-static jclass gAudioAttributesClass;
-static struct {
-    jfieldID    mUsage;
-    jfieldID    mSource;
-    jfieldID    mContentType;
-    jfieldID    mFlags;
-    jfieldID    mFormattedTags;
-} gAudioAttributesFields;
-
 static const char* const kEventHandlerClassPathName =
         "android/media/AudioPortEventHandler";
 static struct {
@@ -705,27 +697,6 @@
     env->DeleteLocalRef(jValues);
 }
 
-static jint convertAudioAttributesToNative(JNIEnv *env,
-                                           audio_attributes_t *nAudioAttributes,
-                                           const jobject jAudioAttributes)
-{
-    nAudioAttributes->usage = (audio_usage_t)env->GetIntField(jAudioAttributes,
-            gAudioAttributesFields.mUsage);
-    nAudioAttributes->source = (audio_source_t)env->GetIntField(jAudioAttributes,
-            gAudioAttributesFields.mSource);
-    nAudioAttributes->content_type = (audio_content_type_t)env->GetIntField(jAudioAttributes,
-            gAudioAttributesFields.mContentType);
-    nAudioAttributes->flags = env->GetIntField(jAudioAttributes,
-            gAudioAttributesFields.mFlags);
-    const jstring jtags = (jstring)env->GetObjectField(jAudioAttributes,
-            gAudioAttributesFields.mFormattedTags);
-    const char *tags = env->GetStringUTFChars(jtags, NULL);
-    strncpy(nAudioAttributes->tags, tags, AUDIO_ATTRIBUTES_TAGS_MAX_SIZE - 1);
-    env->ReleaseStringUTFChars(jtags, tags);
-    return (jint)AUDIO_JAVA_SUCCESS;
-}
-
-
 static jint convertAudioPortConfigToNative(JNIEnv *env,
                                                struct audio_port_config *nAudioPortConfig,
                                                const jobject jAudioPortConfig,
@@ -1705,22 +1676,19 @@
     if (!env->IsInstanceOf(jAudioPortConfig, gAudioPortConfigClass)) {
         return AUDIO_JAVA_BAD_VALUE;
     }
-    if (!env->IsInstanceOf(jAudioAttributes, gAudioAttributesClass)) {
-        return AUDIO_JAVA_BAD_VALUE;
-    }
     struct audio_port_config nAudioPortConfig = {};
     jint jStatus = convertAudioPortConfigToNativeWithDevicePort(env,
             &nAudioPortConfig, jAudioPortConfig, false);
     if (jStatus != AUDIO_JAVA_SUCCESS) {
         return jStatus;
     }
-    audio_attributes_t nAudioAttributes = {};
-    jStatus = convertAudioAttributesToNative(env, &nAudioAttributes, jAudioAttributes);
-    if (jStatus != AUDIO_JAVA_SUCCESS) {
+    auto paa = JNIAudioAttributeHelper::makeUnique();
+    jStatus = JNIAudioAttributeHelper::nativeFromJava(env, jAudioAttributes, paa.get());
+    if (jStatus != (jint)AUDIO_JAVA_SUCCESS) {
         return jStatus;
     }
     audio_port_handle_t handle;
-    status_t status = AudioSystem::startAudioSource(&nAudioPortConfig, &nAudioAttributes, &handle);
+    status_t status = AudioSystem::startAudioSource(&nAudioPortConfig, paa.get(), &handle);
     ALOGV("AudioSystem::startAudioSource() returned %d handle %d", status, handle);
     return handle > 0 ? handle : nativeToJavaStatus(status);
 }
@@ -1833,12 +1801,16 @@
         case RULE_MATCH_ATTRIBUTE_USAGE:
         case RULE_MATCH_ATTRIBUTE_CAPTURE_PRESET: {
             jobject jAttributes = env->GetObjectField(jCriterion, gAudioMixMatchCriterionFields.mAttr);
+
+            auto paa = JNIAudioAttributeHelper::makeUnique();
+            jint jStatus = JNIAudioAttributeHelper::nativeFromJava(env, jAttributes, paa.get());
+            if (jStatus != (jint)AUDIO_JAVA_SUCCESS) {
+                return jStatus;
+            }
             if (match_rule == RULE_MATCH_ATTRIBUTE_USAGE) {
-                nCriterion.mValue.mUsage = (audio_usage_t)env->GetIntField(jAttributes,
-                        gAudioAttributesFields.mUsage);
+                nCriterion.mValue.mUsage = paa->usage;
             } else {
-                nCriterion.mValue.mSource = (audio_source_t)env->GetIntField(jAttributes,
-                        gAudioAttributesFields.mSource);
+                nCriterion.mValue.mSource = paa->source;
             }
             env->DeleteLocalRef(jAttributes);
             }
@@ -2395,17 +2367,6 @@
                                                        "I");
     gAudioMixMatchCriterionFields.mRule = GetFieldIDOrDie(env, audioMixMatchCriterionClass, "mRule",
                                                        "I");
-
-    jclass audioAttributesClass = FindClassOrDie(env, "android/media/AudioAttributes");
-    gAudioAttributesClass = MakeGlobalRefOrDie(env, audioAttributesClass);
-    gAudioAttributesFields.mUsage = GetFieldIDOrDie(env, audioAttributesClass, "mUsage", "I");
-    gAudioAttributesFields.mSource = GetFieldIDOrDie(env, audioAttributesClass, "mSource", "I");
-    gAudioAttributesFields.mContentType = GetFieldIDOrDie(env,
-            audioAttributesClass, "mContentType", "I");
-    gAudioAttributesFields.mFlags = GetFieldIDOrDie(env, audioAttributesClass, "mFlags", "I");
-    gAudioAttributesFields.mFormattedTags = GetFieldIDOrDie(env,
-            audioAttributesClass, "mFormattedTags", "Ljava/lang/String;");
-
     // AudioTrackRoutingProxy methods
     gClsAudioTrackRoutingProxy =
             android::FindClassOrDie(env, "android/media/AudioTrackRoutingProxy");
diff --git a/core/jni/android_media_AudioTrack.cpp b/core/jni/android_media_AudioTrack.cpp
index 1065738..f9f28da 100644
--- a/core/jni/android_media_AudioTrack.cpp
+++ b/core/jni/android_media_AudioTrack.cpp
@@ -23,6 +23,7 @@
 #include "core_jni_helpers.h"
 
 #include <utils/Log.h>
+#include <media/AudioParameter.h>
 #include <media/AudioSystem.h>
 #include <media/AudioTrack.h>
 
@@ -36,6 +37,7 @@
 #include "android_media_PlaybackParams.h"
 #include "android_media_DeviceCallback.h"
 #include "android_media_VolumeShaper.h"
+#include "android_media_AudioAttributes.h"
 
 #include <cinttypes>
 
@@ -47,7 +49,6 @@
 
 // ----------------------------------------------------------------------------
 static const char* const kClassPathName = "android/media/AudioTrack";
-static const char* const kAudioAttributesClassPathName = "android/media/AudioAttributes";
 
 struct audio_track_fields_t {
     // these fields provide access from C++ to the...
@@ -56,14 +57,7 @@
     jfieldID  jniData;      // stores in Java additional resources used by the native AudioTrack
     jfieldID  fieldStreamType; // ... mStreamType field in the AudioTrack Java object
 };
-struct audio_attributes_fields_t {
-    jfieldID  fieldUsage;        // AudioAttributes.mUsage
-    jfieldID  fieldContentType;  // AudioAttributes.mContentType
-    jfieldID  fieldFlags;        // AudioAttributes.mFlags
-    jfieldID  fieldFormattedTags;// AudioAttributes.mFormattedTags
-};
 static audio_track_fields_t      javaAudioTrackFields;
-static audio_attributes_fields_t javaAudioAttrFields;
 static PlaybackParams::fields_t gPlaybackParamsFields;
 static VolumeShaperHelper::fields_t gVolumeShaperFields;
 
@@ -248,8 +242,6 @@
 
     AudioTrackJniStorage* lpJniStorage = NULL;
 
-    audio_attributes_t *paa = NULL;
-
     jclass clazz = env->GetObjectClass(thiz);
     if (clazz == NULL) {
         ALOGE("Can't find %s when setting up callback.", kClassPathName);
@@ -303,18 +295,11 @@
         lpTrack = new AudioTrack();
 
         // read the AudioAttributes values
-        paa = (audio_attributes_t *) calloc(1, sizeof(audio_attributes_t));
-        const jstring jtags =
-                (jstring) env->GetObjectField(jaa, javaAudioAttrFields.fieldFormattedTags);
-        const char* tags = env->GetStringUTFChars(jtags, NULL);
-        // copying array size -1, char array for tags was calloc'd, no need to NULL-terminate it
-        strncpy(paa->tags, tags, AUDIO_ATTRIBUTES_TAGS_MAX_SIZE - 1);
-        env->ReleaseStringUTFChars(jtags, tags);
-        paa->usage = (audio_usage_t) env->GetIntField(jaa, javaAudioAttrFields.fieldUsage);
-        paa->content_type =
-                (audio_content_type_t) env->GetIntField(jaa, javaAudioAttrFields.fieldContentType);
-        paa->flags = env->GetIntField(jaa, javaAudioAttrFields.fieldFlags);
-
+        auto paa = JNIAudioAttributeHelper::makeUnique();
+        jint jStatus = JNIAudioAttributeHelper::nativeFromJava(env, jaa, paa.get());
+        if (jStatus != (jint)AUDIO_JAVA_SUCCESS) {
+            return jStatus;
+        }
         ALOGV("AudioTrack_setup for usage=%d content=%d flags=0x%#x tags=%s",
                 paa->usage, paa->content_type, paa->flags, paa->tags);
 
@@ -356,7 +341,7 @@
                     offload ? AudioTrack::TRANSFER_SYNC_NOTIF_CALLBACK : AudioTrack::TRANSFER_SYNC,
                     offload ? &offloadInfo : NULL,
                     -1, -1,                       // default uid, pid values
-                    paa);
+                    paa.get());
 
             break;
 
@@ -383,7 +368,7 @@
                     AudioTrack::TRANSFER_SHARED,
                     NULL,                         // default offloadInfo
                     -1, -1,                       // default uid, pid values
-                    paa);
+                    paa.get());
             break;
 
         default:
@@ -451,20 +436,11 @@
     // since we had audio attributes, the stream type was derived from them during the
     // creation of the native AudioTrack: push the same value to the Java object
     env->SetIntField(thiz, javaAudioTrackFields.fieldStreamType, (jint) lpTrack->streamType());
-    if (paa != NULL) {
-        // audio attributes were copied in AudioTrack creation
-        free(paa);
-        paa = NULL;
-    }
-
 
     return (jint) AUDIO_JAVA_SUCCESS;
 
     // failures:
 native_init_failure:
-    if (paa != NULL) {
-        free(paa);
-    }
     if (nSession != NULL) {
         env->ReleasePrimitiveArrayCritical(jSession, nSession, 0);
     }
@@ -1311,6 +1287,33 @@
 }
 
 // ----------------------------------------------------------------------------
+static void android_media_AudioTrack_set_delay_padding(JNIEnv *env,  jobject thiz,
+        jint delayInFrames, jint paddingInFrames) {
+    sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
+    if (lpTrack == NULL) {
+        jniThrowException(env, "java/lang/IllegalStateException",
+                "AudioTrack not initialized");
+        return;
+    }
+    AudioParameter param = AudioParameter();
+    param.addInt(String8(AUDIO_OFFLOAD_CODEC_DELAY_SAMPLES), (int) delayInFrames);
+    param.addInt(String8(AUDIO_OFFLOAD_CODEC_PADDING_SAMPLES), (int) paddingInFrames);
+    lpTrack->setParameters(param.toString());
+}
+
+static void android_media_AudioTrack_set_eos(JNIEnv *env,  jobject thiz) {
+    sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
+    if (lpTrack == NULL) {
+        jniThrowException(env, "java/lang/IllegalStateException",
+                          "AudioTrack not initialized");
+        return;
+    }
+    AudioParameter param = AudioParameter();
+    param.addInt(String8("EOS"), 1);
+    lpTrack->setParameters(param.toString());
+}
+
+// ----------------------------------------------------------------------------
 // ----------------------------------------------------------------------------
 static const JNINativeMethod gMethods[] = {
     // name,              signature,     funcPtr
@@ -1385,6 +1388,8 @@
                                         (void *)android_media_AudioTrack_get_volume_shaper_state},
     {"native_setPresentation", "(II)I", (void *)android_media_AudioTrack_setPresentation},
     {"native_getPortId", "()I", (void *)android_media_AudioTrack_get_port_id},
+    {"native_set_delay_padding", "(II)V", (void *)android_media_AudioTrack_set_delay_padding},
+    {"native_set_eos",        "()V",    (void *)android_media_AudioTrack_set_eos},
 };
 
 
@@ -1440,17 +1445,6 @@
 
     env->DeleteLocalRef(audioTrackClass);
 
-    // Get the AudioAttributes class and fields
-    jclass audioAttrClass = FindClassOrDie(env, kAudioAttributesClassPathName);
-    javaAudioAttrFields.fieldUsage = GetFieldIDOrDie(env, audioAttrClass, "mUsage", "I");
-    javaAudioAttrFields.fieldContentType = GetFieldIDOrDie(env,
-            audioAttrClass, "mContentType", "I");
-    javaAudioAttrFields.fieldFlags = GetFieldIDOrDie(env, audioAttrClass, "mFlags", "I");
-    javaAudioAttrFields.fieldFormattedTags = GetFieldIDOrDie(env,
-            audioAttrClass, "mFormattedTags", "Ljava/lang/String;");
-
-    env->DeleteLocalRef(audioAttrClass);
-
     // initialize PlaybackParams field info
     gPlaybackParamsFields.init(env);
 
diff --git a/core/jni/android_os_Debug.cpp b/core/jni/android_os_Debug.cpp
index 7837248..e9035ed 100644
--- a/core/jni/android_os_Debug.cpp
+++ b/core/jni/android_os_Debug.cpp
@@ -646,7 +646,7 @@
     }
 
     /* dup() the descriptor so we don't close the original with fclose() */
-    int fd = dup(origFd);
+    int fd = fcntl(origFd, F_DUPFD_CLOEXEC, 0);
     if (fd < 0) {
         ALOGW("dup(%d) failed: %s\n", origFd, strerror(errno));
         jniThrowRuntimeException(env, "dup() failed");
diff --git a/core/jni/android_text_Hyphenator.cpp b/core/jni/android_text_Hyphenator.cpp
index 6f9cc22..de30773 100644
--- a/core/jni/android_text_Hyphenator.cpp
+++ b/core/jni/android_text_Hyphenator.cpp
@@ -37,7 +37,7 @@
 
 static const uint8_t* mmapPatternFile(const std::string& locale) {
     const std::string hyFilePath = buildFileName(locale);
-    const int fd = open(hyFilePath.c_str(), O_RDONLY);
+    const int fd = open(hyFilePath.c_str(), O_RDONLY | O_CLOEXEC);
     if (fd == -1) {
         return nullptr;  // Open failed.
     }
diff --git a/core/jni/android_util_Binder.cpp b/core/jni/android_util_Binder.cpp
index f201ceb..df98cdc 100644
--- a/core/jni/android_util_Binder.cpp
+++ b/core/jni/android_util_Binder.cpp
@@ -1184,7 +1184,7 @@
     FILE *f;
 
     snprintf(filename, sizeof(filename), "/proc/%d/cmdline", pid);
-    f = fopen(filename, "r");
+    f = fopen(filename, "re");
     if (!f) {
         *buf = '\0';
         return 1;
diff --git a/core/jni/android_util_FileObserver.cpp b/core/jni/android_util_FileObserver.cpp
index 6f975b2..c64c212 100644
--- a/core/jni/android_util_FileObserver.cpp
+++ b/core/jni/android_util_FileObserver.cpp
@@ -16,6 +16,8 @@
 */
 
 #include <nativehelper/JNIHelp.h>
+#include <nativehelper/ScopedPrimitiveArray.h>
+#include <nativehelper/ScopedUtfChars.h>
 #include "jni.h"
 #include "utils/Log.h"
 #include "utils/misc.h"
@@ -40,7 +42,7 @@
 static jint android_os_fileobserver_init(JNIEnv* env, jobject object)
 {
 #if defined(__linux__)
-    return (jint)inotify_init();
+    return (jint)inotify_init1(IN_CLOEXEC);
 #else
     return -1;
 #endif
@@ -98,31 +100,45 @@
 #endif
 }
 
-static jint android_os_fileobserver_startWatching(JNIEnv* env, jobject object, jint fd, jstring pathString, jint mask)
+static void android_os_fileobserver_startWatching(JNIEnv* env, jobject object, jint fd,
+                                                       jobjectArray pathStrings, jint mask,
+                                                       jintArray wfdArray)
 {
-    int res = -1;
+    ScopedIntArrayRW wfds(env, wfdArray);
+    if (wfds.get() == nullptr) {
+        jniThrowException(env, "java/lang/IllegalStateException", "Failed to get ScopedIntArrayRW");
+    }
 
 #if defined(__linux__)
 
     if (fd >= 0)
     {
-        const char* path = env->GetStringUTFChars(pathString, NULL);
+        size_t count = wfds.size();
+        for (jsize i = 0; i < count; ++i) {
+            jstring pathString = (jstring) env->GetObjectArrayElement(pathStrings, i);
 
-        res = inotify_add_watch(fd, path, mask);
+            ScopedUtfChars path(env, pathString);
 
-        env->ReleaseStringUTFChars(pathString, path);
+            wfds[i] = inotify_add_watch(fd, path.c_str(), mask);
+        }
     }
 
 #endif
-
-    return res;
 }
 
-static void android_os_fileobserver_stopWatching(JNIEnv* env, jobject object, jint fd, jint wfd)
+static void android_os_fileobserver_stopWatching(JNIEnv* env, jobject object,
+                                                 jint fd, jintArray wfdArray)
 {
 #if defined(__linux__)
 
-    inotify_rm_watch((int)fd, (uint32_t)wfd);
+    ScopedIntArrayRO wfds(env, wfdArray);
+    if (wfds.get() == nullptr) {
+        jniThrowException(env, "java/lang/IllegalStateException", "Failed to get ScopedIntArrayRO");
+    }
+    size_t count = wfds.size();
+    for (size_t i = 0; i < count; ++i) {
+        inotify_rm_watch((int)fd, (uint32_t)wfds[i]);
+    }
 
 #endif
 }
@@ -131,8 +147,8 @@
      /* name, signature, funcPtr */
     { "init", "()I", (void*)android_os_fileobserver_init },
     { "observe", "(I)V", (void*)android_os_fileobserver_observe },
-    { "startWatching", "(ILjava/lang/String;I)I", (void*)android_os_fileobserver_startWatching },
-    { "stopWatching", "(II)V", (void*)android_os_fileobserver_stopWatching }
+    { "startWatching", "(I[Ljava/lang/String;I[I)V", (void*)android_os_fileobserver_startWatching },
+    { "stopWatching", "(I[I)V", (void*)android_os_fileobserver_stopWatching }
 
 };
 
diff --git a/core/jni/android_view_Surface.cpp b/core/jni/android_view_Surface.cpp
index b8139a7..f9407f4 100644
--- a/core/jni/android_view_Surface.cpp
+++ b/core/jni/android_view_Surface.cpp
@@ -131,6 +131,7 @@
     switch(f) {
         case PublicFormat::JPEG:
         case PublicFormat::DEPTH_POINT_CLOUD:
+        case PublicFormat::DEPTH_JPEG:
             return HAL_PIXEL_FORMAT_BLOB;
         case PublicFormat::DEPTH16:
             return HAL_PIXEL_FORMAT_Y16;
@@ -161,6 +162,8 @@
         case PublicFormat::NV21:
         case PublicFormat::YV12:
             return HAL_DATASPACE_V0_JFIF;
+        case PublicFormat::DEPTH_JPEG:
+            return static_cast<android_dataspace> (HAL_DATASPACE_DYNAMIC_DEPTH);
         default:
             // Most formats map to UNKNOWN
             return HAL_DATASPACE_UNKNOWN;
@@ -223,8 +226,12 @@
                 case HAL_DATASPACE_V0_JFIF:
                     return PublicFormat::JPEG;
                 default:
-                    // Assume otherwise-marked blobs are also JPEG
-                    return PublicFormat::JPEG;
+                    if (dataSpace == static_cast<android_dataspace>(HAL_DATASPACE_DYNAMIC_DEPTH)) {
+                        return PublicFormat::DEPTH_JPEG;
+                    } else {
+                        // Assume otherwise-marked blobs are also JPEG
+                        return PublicFormat::JPEG;
+                    }
             }
             break;
         case HAL_PIXEL_FORMAT_BGRA_8888:
diff --git a/core/jni/com_android_internal_content_NativeLibraryHelper.cpp b/core/jni/com_android_internal_content_NativeLibraryHelper.cpp
index 5eefc81..dc536b2 100644
--- a/core/jni/com_android_internal_content_NativeLibraryHelper.cpp
+++ b/core/jni/com_android_internal_content_NativeLibraryHelper.cpp
@@ -125,7 +125,7 @@
         return true;
     }
 
-    int fd = TEMP_FAILURE_RETRY(open(filePath, O_RDONLY));
+    int fd = TEMP_FAILURE_RETRY(open(filePath, O_RDONLY | O_CLOEXEC));
     if (fd < 0) {
         ALOGV("Couldn't open file %s: %s", filePath, strerror(errno));
         return true;
@@ -565,7 +565,7 @@
         return 0;
     }
 
-    int dupedFd = dup(fd);
+    int dupedFd = fcntl(fd, F_DUPFD_CLOEXEC, 0);
     if (dupedFd == -1) {
         jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException",
                              "Failed to dup FileDescriptor: %s", strerror(errno));
diff --git a/core/jni/com_android_internal_net_NetworkStatsFactory.cpp b/core/jni/com_android_internal_net_NetworkStatsFactory.cpp
index 24bafca..8259ffc 100644
--- a/core/jni/com_android_internal_net_NetworkStatsFactory.cpp
+++ b/core/jni/com_android_internal_net_NetworkStatsFactory.cpp
@@ -95,7 +95,7 @@
 static int legacyReadNetworkStatsDetail(std::vector<stats_line>* lines,
                                         const std::vector<std::string>& limitIfaces,
                                         int limitTag, int limitUid, const char* path) {
-    FILE* fp = fopen(path, "r");
+    FILE* fp = fopen(path, "re");
     if (fp == NULL) {
         return -1;
     }
diff --git a/core/jni/com_android_internal_os_AtomicDirectory.cpp b/core/jni/com_android_internal_os_AtomicDirectory.cpp
index 50b2288..76b0fc1 100644
--- a/core/jni/com_android_internal_os_AtomicDirectory.cpp
+++ b/core/jni/com_android_internal_os_AtomicDirectory.cpp
@@ -29,7 +29,7 @@
         return -1;
     }
     int fd;
-    if ((fd = TEMP_FAILURE_RETRY(open(path8.c_str(), O_DIRECTORY | O_RDONLY))) == -1) {
+    if ((fd = TEMP_FAILURE_RETRY(open(path8.c_str(), O_DIRECTORY | O_RDONLY | O_CLOEXEC))) == -1) {
         ALOGE("Cannot open directory %s, error: %s\n", path8.c_str(), strerror(errno));
         return -1;
     }
diff --git a/core/jni/include/android_runtime/android_view_Surface.h b/core/jni/include/android_runtime/android_view_Surface.h
index 36487b3..984e942 100644
--- a/core/jni/include/android_runtime/android_view_Surface.h
+++ b/core/jni/include/android_runtime/android_view_Surface.h
@@ -57,7 +57,8 @@
     YV12              = 0x32315659,
     Y8                = 0x20203859, // @hide
     Y16               = 0x20363159, // @hide
-    DEPTH16           = 0x44363159
+    DEPTH16           = 0x44363159,
+    DEPTH_JPEG        = 0x69656963,
 };
 
 /* Gets the underlying ANativeWindow for a Surface. */
diff --git a/core/proto/Android.bp b/core/proto/Android.bp
index 80cc2d4..3b891d6 100644
--- a/core/proto/Android.bp
+++ b/core/proto/Android.bp
@@ -21,7 +21,10 @@
         type: "lite",
     },
     srcs: [
+        "android/bluetooth/a2dp/enums.proto",
         "android/bluetooth/enums.proto",
         "android/bluetooth/hci/enums.proto",
+        "android/bluetooth/hfp/enums.proto",
+        "android/bluetooth/smp/enums.proto",
     ],
 }
diff --git a/core/proto/android/app/job/enums.proto b/core/proto/android/app/job/enums.proto
index bba8328..f702b3e 100644
--- a/core/proto/android/app/job/enums.proto
+++ b/core/proto/android/app/job/enums.proto
@@ -18,6 +18,9 @@
 
 package android.app.job;
 
+// This file is for JobScheduler enums inside the app directory. If you're
+// adding enums for system-server-side code, use the file in
+// frameworks/base/core/proto/android/server/job.
 option java_outer_classname = "JobProtoEnums";
 option java_multiple_files = true;
 
diff --git a/core/proto/android/bluetooth/a2dp/enums.proto b/core/proto/android/bluetooth/a2dp/enums.proto
new file mode 100644
index 0000000..5a025bd
--- /dev/null
+++ b/core/proto/android/bluetooth/a2dp/enums.proto
@@ -0,0 +1,35 @@
+/*
+ * 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.
+ */
+
+syntax = "proto2";
+package android.bluetooth.a2dp;
+
+option java_outer_classname = "BluetoothA2dpProtoEnums";
+option java_multiple_files = true;
+
+// A2dp playback state enum, defined from:
+// frameworks/base/core/java/android/bluetooth/BluetoothA2dp.java
+enum PlaybackStateEnum {
+    PLAYBACK_STATE_UNKNOWN = 0;
+    PLAYBACK_STATE_PLAYING = 10;
+    PLAYBACK_STATE_NOT_PLAYING = 11;
+}
+
+enum AudioCodingModeEnum {
+    AUDIO_CODING_MODE_UNKNOWN = 0;
+    AUDIO_CODING_MODE_HARDWARE = 1;
+    AUDIO_CODING_MODE_SOFTWARE = 2;
+}
diff --git a/core/proto/android/bluetooth/enums.proto b/core/proto/android/bluetooth/enums.proto
index 76c240e..a88a06c 100644
--- a/core/proto/android/bluetooth/enums.proto
+++ b/core/proto/android/bluetooth/enums.proto
@@ -56,3 +56,57 @@
     LINK_TYPE_ACL = 0x01;
     LINK_TYPE_ESCO = 0x02;
 }
+
+enum DeviceInfoSrcEnum {
+    DEVICE_INFO_SRC_UNKNOWN = 0;
+    // Within Android Bluetooth stack
+    DEVICE_INFO_INTERNAL = 1;
+    // Outside Android Bluetooth stack
+    DEVICE_INFO_EXTERNAL = 2;
+}
+
+enum DeviceTypeEnum {
+    DEVICE_TYPE_UNKNOWN = 0;
+    DEVICE_TYPE_CLASSIC = 1;
+    DEVICE_TYPE_LE = 2;
+    DEVICE_TYPE_DUAL = 3;
+}
+
+// Defined in frameworks/base/core/java/android/bluetooth/BluetoothDevice.java
+enum TransportTypeEnum {
+    TRANSPORT_TYPE_AUTO = 0;
+    TRANSPORT_TYPE_BREDR = 1;
+    TRANSPORT_TYPE_LE = 2;
+}
+
+// Bond state enum
+// Defined in frameworks/base/core/java/android/bluetooth/BluetoothDevice.java
+enum BondStateEnum {
+    BOND_STATE_UNKNOWN = 0;
+    BOND_STATE_NONE = 10;
+    BOND_STATE_BONDING = 11;
+    BOND_STATE_BONDED = 12;
+}
+
+// Sub states within the bonding general state
+enum BondSubStateEnum {
+    BOND_SUB_STATE_UNKNOWN = 0;
+    BOND_SUB_STATE_LOCAL_OOB_DATA_PROVIDED = 1;
+    BOND_SUB_STATE_LOCAL_PIN_REQUESTED = 2;
+    BOND_SUB_STATE_LOCAL_PIN_REPLIED = 3;
+    BOND_SUB_STATE_LOCAL_SSP_REQUESTED = 4;
+    BOND_SUB_STATE_LOCAL_SSP_REPLIED = 5;
+}
+
+enum UnbondReasonEnum {
+    UNBOND_REASON_UNKNOWN = 0;
+    UNBOND_REASON_AUTH_FAILED = 1;
+    UNBOND_REASON_AUTH_REJECTED = 2;
+    UNBOND_REASON_AUTH_CANCELED = 3;
+    UNBOND_REASON_REMOTE_DEVICE_DOWN = 4;
+    UNBOND_REASON_DISCOVERY_IN_PROGRESS = 5;
+    UNBOND_REASON_AUTH_TIMEOUT = 6;
+    UNBOND_REASON_REPEATED_ATTEMPTS = 7;
+    UNBOND_REASON_REMOTE_AUTH_CANCELED = 8;
+    UNBOND_REASON_REMOVED = 9;
+}
diff --git a/core/proto/android/bluetooth/hci/enums.proto b/core/proto/android/bluetooth/hci/enums.proto
index e1d96bb..ef894e5 100644
--- a/core/proto/android/bluetooth/hci/enums.proto
+++ b/core/proto/android/bluetooth/hci/enums.proto
@@ -351,7 +351,7 @@
     EVT_COMMAND_COMPLETE = 0x0E;
     EVT_COMMAND_STATUS = 0x0F;
     EVT_HARDWARE_ERROR = 0x10;
-    EVT_FLUSH_OCCURED = 0x11;
+    EVT_FLUSH_OCCURRED = 0x11;
     EVT_ROLE_CHANGE = 0x12;
     EVT_NUM_COMPL_DATA_PKTS = 0x13;
     EVT_MODE_CHANGE = 0x14;
@@ -517,3 +517,43 @@
     STATUS_CLB_DATA_TOO_BIG = 0x43;
     STATUS_OPERATION_CANCELED_BY_HOST = 0x44; // Not currently used in system/bt
 }
+
+enum BqrIdEnum {
+    BQR_ID_UNKNOWN = 0x00;
+    BQR_ID_MONITOR_MODE = 0x01;
+    BQR_ID_APPROACH_LSTO = 0x02;
+    BQR_ID_A2DP_AUDIO_CHOPPY = 0x03;
+    BQR_ID_SCO_VOICE_CHOPPY = 0x04;
+}
+
+enum BqrPacketTypeEnum {
+    BQR_PACKET_TYPE_UNKNOWN = 0x00;
+    BQR_PACKET_TYPE_ID = 0x01;
+    BQR_PACKET_TYPE_NULL = 0x02;
+    BQR_PACKET_TYPE_POLL = 0x03;
+    BQR_PACKET_TYPE_FHS = 0x04;
+    BQR_PACKET_TYPE_HV1 = 0x05;
+    BQR_PACKET_TYPE_HV2 = 0x06;
+    BQR_PACKET_TYPE_HV3 = 0x07;
+    BQR_PACKET_TYPE_DV = 0x08;
+    BQR_PACKET_TYPE_EV3 = 0x09;
+    BQR_PACKET_TYPE_EV4 = 0x0A;
+    BQR_PACKET_TYPE_EV5 = 0x0B;
+    BQR_PACKET_TYPE_2EV3 = 0x0C;
+    BQR_PACKET_TYPE_2EV5 = 0x0D;
+    BQR_PACKET_TYPE_3EV3 = 0x0E;
+    BQR_PACKET_TYPE_3EV5 = 0x0F;
+    BQR_PACKET_TYPE_DM1 = 0x10;
+    BQR_PACKET_TYPE_DH1 = 0x11;
+    BQR_PACKET_TYPE_DM3 = 0x12;
+    BQR_PACKET_TYPE_DH3 = 0x13;
+    BQR_PACKET_TYPE_DM5 = 0x14;
+    BQR_PACKET_TYPE_DH5 = 0x15;
+    BQR_PACKET_TYPE_AUX1 = 0x16;
+    BQR_PACKET_TYPE_2DH1 = 0x17;
+    BQR_PACKET_TYPE_2DH3 = 0x18;
+    BQR_PACKET_TYPE_2DH5 = 0x19;
+    BQR_PACKET_TYPE_3DH1 = 0x1A;
+    BQR_PACKET_TYPE_3DH3 = 0x1B;
+    BQR_PACKET_TYPE_3DH5 = 0x1C;
+}
diff --git a/core/proto/android/bluetooth/smp/enums.proto b/core/proto/android/bluetooth/smp/enums.proto
new file mode 100644
index 0000000..c6747b7
--- /dev/null
+++ b/core/proto/android/bluetooth/smp/enums.proto
@@ -0,0 +1,58 @@
+/*
+ * 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.
+ */
+
+syntax = "proto2";
+package android.bluetooth.smp;
+
+option java_outer_classname = "BluetoothSmpProtoEnums";
+option java_multiple_files = true;
+
+// SMP Pairing command codes
+enum CommandEnum {
+    CMD_UNKNOWN = 0x00;
+    CMD_PAIRING_REQUEST = 0x01;
+    CMD_PAIRING_RESPONSE = 0x02;
+    CMD_PAIRING_CONFIRM = 0x03;
+    CMD_PAIRING_RANDOM = 0x04;
+    CMD_PAIRING_FAILED = 0x05;
+    CMD_ENCRYPTION_INFON = 0x06;
+    CMD_MASTER_IDENTIFICATION = 0x07;
+    CMD_IDENTITY_INFO = 0x08;
+    CMD_IDENTITY_ADDR_INFO = 0x09;
+    CMD_SIGNING_INFO = 0x0A;
+    CMD_SECURITY_REQUEST = 0x0B;
+    CMD_PAIRING_PUBLIC_KEY = 0x0C;
+    CMD_PAIRING_DHKEY_CHECK = 0x0D;
+    CMD_PAIRING_KEYPRESS_INFO = 0x0E;
+}
+
+enum PairingFailReasonEnum {
+    PAIRING_FAIL_REASON_RESERVED = 0x00;
+    PAIRING_FAIL_REASON_PASSKEY_ENTRY = 0x01;
+    PAIRING_FAIL_REASON_OOB = 0x02;
+    PAIRING_FAIL_REASON_AUTH_REQ = 0x03;
+    PAIRING_FAIL_REASON_CONFIRM_VALUE = 0x04;
+    PAIRING_FAIL_REASON_PAIR_NOT_SUPPORT = 0x05;
+    PAIRING_FAIL_REASON_ENC_KEY_SIZE = 0x06;
+    PAIRING_FAIL_REASON_INVALID_CMD = 0x07;
+    PAIRING_FAIL_REASON_UNSPECIFIED = 0x08;
+    PAIRING_FAIL_REASON_REPEATED_ATTEMPTS = 0x09;
+    PAIRING_FAIL_REASON_INVALID_PARAMETERS = 0x0A;
+    PAIRING_FAIL_REASON_DHKEY_CHK = 0x0B;
+    PAIRING_FAIL_REASON_NUMERIC_COMPARISON = 0x0C;
+    PAIRING_FAIL_REASON_CLASSIC_PAIRING_IN_PROGR = 0x0D;
+    PAIRING_FAIL_REASON_XTRANS_DERIVE_NOT_ALLOW = 0x0E;
+}
\ No newline at end of file
diff --git a/core/proto/android/providers/settings/secure.proto b/core/proto/android/providers/settings/secure.proto
index aaf6c63..f3733fd 100644
--- a/core/proto/android/providers/settings/secure.proto
+++ b/core/proto/android/providers/settings/secure.proto
@@ -72,6 +72,9 @@
         // List of the accessibility services to which the user has granted
         // permission to put the device into touch exploration mode.
         optional SettingProto touch_exploration_granted_accessibility_services = 31;
+        // Settings for accessibility timeout
+        optional SettingProto non_interactive_ui_timeout_ms = 32 [ (android.privacy).dest = DEST_AUTOMATIC ];
+        optional SettingProto interactive_ui_timeout_ms = 33 [ (android.privacy).dest = DEST_AUTOMATIC ];
     }
     optional Accessibility accessibility = 2;
 
diff --git a/core/proto/android/server/job/enums.proto b/core/proto/android/server/job/enums.proto
new file mode 100644
index 0000000..50fc031
--- /dev/null
+++ b/core/proto/android/server/job/enums.proto
@@ -0,0 +1,43 @@
+/*
+ * 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.
+ */
+
+syntax = "proto2";
+
+package com.android.server.job;
+
+// This file is for JobScheduler enums inside the server directory. If you're
+// adding enums for app-side code, use the file in
+// frameworks/base/core/proto/android/app/job.
+option java_outer_classname = "JobServerProtoEnums";
+option java_multiple_files = true;
+
+// Set of constraints that a job potentially needs satisfied before it can run.
+// Defined in
+// frameworks/base/services/core/java/com/android/server/job/controllers/JobStatus.java
+enum ConstraintEnum {
+    CONSTRAINT_UNKNOWN = 0;
+    CONSTRAINT_CHARGING = 1;
+    CONSTRAINT_BATTERY_NOT_LOW = 2;
+    CONSTRAINT_STORAGE_NOT_LOW = 3;
+    CONSTRAINT_TIMING_DELAY = 4;
+    CONSTRAINT_DEADLINE = 5;
+    CONSTRAINT_IDLE = 6;
+    CONSTRAINT_CONNECTIVITY = 7;
+    CONSTRAINT_CONTENT_TRIGGER = 8;
+    CONSTRAINT_DEVICE_NOT_DOZING = 9;
+    CONSTRAINT_WITHIN_QUOTA = 10;
+    CONSTRAINT_BACKGROUND_NOT_RESTRICTED = 11;
+}
diff --git a/core/proto/android/server/jobscheduler.proto b/core/proto/android/server/jobscheduler.proto
index 188769d..6c9d13a 100644
--- a/core/proto/android/server/jobscheduler.proto
+++ b/core/proto/android/server/jobscheduler.proto
@@ -29,6 +29,7 @@
 import "frameworks/base/core/proto/android/os/bundle.proto";
 import "frameworks/base/core/proto/android/os/persistablebundle.proto";
 import "frameworks/base/core/proto/android/server/forceappstandbytracker.proto";
+import "frameworks/base/core/proto/android/server/job/enums.proto";
 import "frameworks/base/libs/incident/proto/android/privacy.proto";
 
 // Next tag: 21
@@ -757,21 +758,9 @@
     }
     optional JobInfo job_info = 6;
 
-    enum Constraint {
-        CONSTRAINT_CHARGING = 1;
-        CONSTRAINT_BATTERY_NOT_LOW = 2;
-        CONSTRAINT_STORAGE_NOT_LOW = 3;
-        CONSTRAINT_TIMING_DELAY = 4;
-        CONSTRAINT_DEADLINE = 5;
-        CONSTRAINT_IDLE = 6;
-        CONSTRAINT_CONNECTIVITY = 7;
-        CONSTRAINT_CONTENT_TRIGGER = 8;
-        CONSTRAINT_DEVICE_NOT_DOZING = 9;
-        CONSTRAINT_WITHIN_QUOTA = 10;
-    }
-    repeated Constraint required_constraints = 7;
-    repeated Constraint satisfied_constraints = 8;
-    repeated Constraint unsatisfied_constraints = 9;
+    repeated ConstraintEnum required_constraints = 7;
+    repeated ConstraintEnum satisfied_constraints = 8;
+    repeated ConstraintEnum unsatisfied_constraints = 9;
     optional bool is_doze_whitelisted = 10;
     optional bool is_uid_active = 26;
 
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 25baa92..7184c7a 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -3528,6 +3528,12 @@
         android:protectionLevel="signature|privileged" />
     <uses-permission android:name="android.permission.CONTROL_VPN" />
 
+    <!-- Allows an application to access and modify always-on VPN configuration.
+         <p>Not for use by third-party or privileged applications.
+         @hide -->
+    <permission android:name="android.permission.CONTROL_ALWAYS_ON_VPN"
+        android:protectionLevel="signature" />
+
     <!-- Allows an application to capture audio output.
          <p>Not for use by third-party applications.</p> -->
     <permission android:name="android.permission.CAPTURE_AUDIO_OUTPUT"
diff --git a/packages/SettingsLib/res/drawable/btn_borderless_rect.xml b/core/res/res/drawable/btn_borderless_rect.xml
similarity index 100%
rename from packages/SettingsLib/res/drawable/btn_borderless_rect.xml
rename to core/res/res/drawable/btn_borderless_rect.xml
diff --git a/packages/SettingsLib/res/drawable/ic_bt_cellphone.xml b/core/res/res/drawable/ic_bt_cellphone.xml
similarity index 100%
rename from packages/SettingsLib/res/drawable/ic_bt_cellphone.xml
rename to core/res/res/drawable/ic_bt_cellphone.xml
diff --git a/packages/SettingsLib/res/drawable/ic_bt_headphones_a2dp.xml b/core/res/res/drawable/ic_bt_headphones_a2dp.xml
similarity index 100%
rename from packages/SettingsLib/res/drawable/ic_bt_headphones_a2dp.xml
rename to core/res/res/drawable/ic_bt_headphones_a2dp.xml
diff --git a/packages/SettingsLib/res/drawable/ic_bt_headset_hfp.xml b/core/res/res/drawable/ic_bt_headset_hfp.xml
similarity index 100%
rename from packages/SettingsLib/res/drawable/ic_bt_headset_hfp.xml
rename to core/res/res/drawable/ic_bt_headset_hfp.xml
diff --git a/packages/SettingsLib/res/drawable/ic_bt_hearing_aid.xml b/core/res/res/drawable/ic_bt_hearing_aid.xml
similarity index 100%
rename from packages/SettingsLib/res/drawable/ic_bt_hearing_aid.xml
rename to core/res/res/drawable/ic_bt_hearing_aid.xml
diff --git a/packages/SettingsLib/res/drawable/ic_bt_laptop.xml b/core/res/res/drawable/ic_bt_laptop.xml
similarity index 100%
rename from packages/SettingsLib/res/drawable/ic_bt_laptop.xml
rename to core/res/res/drawable/ic_bt_laptop.xml
diff --git a/packages/SettingsLib/res/drawable/ic_bt_misc_hid.xml b/core/res/res/drawable/ic_bt_misc_hid.xml
similarity index 100%
rename from packages/SettingsLib/res/drawable/ic_bt_misc_hid.xml
rename to core/res/res/drawable/ic_bt_misc_hid.xml
diff --git a/packages/SettingsLib/res/drawable/ic_bt_network_pan.xml b/core/res/res/drawable/ic_bt_network_pan.xml
similarity index 100%
rename from packages/SettingsLib/res/drawable/ic_bt_network_pan.xml
rename to core/res/res/drawable/ic_bt_network_pan.xml
diff --git a/packages/SettingsLib/res/drawable/ic_bt_pointing_hid.xml b/core/res/res/drawable/ic_bt_pointing_hid.xml
similarity index 100%
rename from packages/SettingsLib/res/drawable/ic_bt_pointing_hid.xml
rename to core/res/res/drawable/ic_bt_pointing_hid.xml
diff --git a/packages/SettingsLib/res/drawable/ic_expand_more.xml b/core/res/res/drawable/ic_expand_more.xml
similarity index 100%
rename from packages/SettingsLib/res/drawable/ic_expand_more.xml
rename to core/res/res/drawable/ic_expand_more.xml
diff --git a/packages/SettingsLib/res/drawable/ic_lockscreen_ime.xml b/core/res/res/drawable/ic_lockscreen_ime.xml
similarity index 100%
rename from packages/SettingsLib/res/drawable/ic_lockscreen_ime.xml
rename to core/res/res/drawable/ic_lockscreen_ime.xml
diff --git a/packages/SettingsLib/res/drawable/ic_menu.xml b/core/res/res/drawable/ic_menu.xml
similarity index 100%
rename from packages/SettingsLib/res/drawable/ic_menu.xml
rename to core/res/res/drawable/ic_menu.xml
diff --git a/packages/SettingsLib/res/drawable/ic_minus.xml b/core/res/res/drawable/ic_minus.xml
similarity index 100%
rename from packages/SettingsLib/res/drawable/ic_minus.xml
rename to core/res/res/drawable/ic_minus.xml
diff --git a/packages/SettingsLib/res/drawable/ic_mode_edit.xml b/core/res/res/drawable/ic_mode_edit.xml
similarity index 100%
rename from packages/SettingsLib/res/drawable/ic_mode_edit.xml
rename to core/res/res/drawable/ic_mode_edit.xml
diff --git a/packages/SettingsLib/res/drawable/ic_plus.xml b/core/res/res/drawable/ic_plus.xml
similarity index 100%
rename from packages/SettingsLib/res/drawable/ic_plus.xml
rename to core/res/res/drawable/ic_plus.xml
diff --git a/packages/SettingsLib/res/drawable/ic_qs_night_display_on.xml b/core/res/res/drawable/ic_qs_night_display_on.xml
similarity index 100%
rename from packages/SettingsLib/res/drawable/ic_qs_night_display_on.xml
rename to core/res/res/drawable/ic_qs_night_display_on.xml
diff --git a/packages/SettingsLib/res/drawable/ic_settings_bluetooth.xml b/core/res/res/drawable/ic_settings_bluetooth.xml
similarity index 100%
rename from packages/SettingsLib/res/drawable/ic_settings_bluetooth.xml
rename to core/res/res/drawable/ic_settings_bluetooth.xml
diff --git a/packages/SettingsLib/res/drawable/ic_settings_print.xml b/core/res/res/drawable/ic_settings_print.xml
similarity index 100%
rename from packages/SettingsLib/res/drawable/ic_settings_print.xml
rename to core/res/res/drawable/ic_settings_print.xml
diff --git a/packages/SettingsLib/res/drawable/ic_signal_location.xml b/core/res/res/drawable/ic_signal_location.xml
similarity index 100%
rename from packages/SettingsLib/res/drawable/ic_signal_location.xml
rename to core/res/res/drawable/ic_signal_location.xml
diff --git a/core/res/res/values-night/themes_device_defaults.xml b/core/res/res/values-night/themes_device_defaults.xml
index 43b3552..949c12e 100644
--- a/core/res/res/values-night/themes_device_defaults.xml
+++ b/core/res/res/values-night/themes_device_defaults.xml
@@ -51,6 +51,10 @@
           -->
     <!-- DeviceDefault theme for a window that should look like the Settings app.  -->
     <style name="Theme.DeviceDefault.Settings" parent="Theme.DeviceDefault">
+        <item name="windowLightStatusBar">false</item>
+        <item name="navigationBarColor">@android:color/black</item>
+        <item name="windowLightNavigationBar">false</item>
+
         <item name="colorPrimaryDark">@color/primary_dark_device_default_settings</item>
         <item name="colorBackground">@color/primary_dark_device_default_settings</item>
 
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 9f15321..aefa9df 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -1423,6 +1423,27 @@
   <java-symbol type="drawable" name="ic_sim_card_multi_48px_clr" />
   <java-symbol type="drawable" name="ic_signal_cellular_alt_24px" />
 
+  <java-symbol type="drawable" name="btn_borderless_rect" />
+  <java-symbol type="drawable" name="ic_bt_cellphone" />
+  <java-symbol type="drawable" name="ic_bt_headphones_a2dp" />
+  <java-symbol type="drawable" name="ic_bt_headset_hfp" />
+  <java-symbol type="drawable" name="ic_bt_hearing_aid" />
+  <java-symbol type="drawable" name="ic_bt_laptop" />
+  <java-symbol type="drawable" name="ic_bt_misc_hid" />
+  <java-symbol type="drawable" name="ic_bt_network_pan" />
+  <java-symbol type="drawable" name="ic_bt_pointing_hid" />
+  <java-symbol type="drawable" name="ic_expand_more" />
+  <java-symbol type="drawable" name="ic_lockscreen_ime" />
+  <java-symbol type="drawable" name="ic_menu" />
+  <java-symbol type="drawable" name="ic_minus" />
+  <java-symbol type="drawable" name="ic_mode_edit" />
+  <java-symbol type="drawable" name="ic_plus" />
+  <java-symbol type="drawable" name="ic_qs_night_display_on" />
+  <java-symbol type="drawable" name="ic_settings_bluetooth" />
+  <java-symbol type="drawable" name="ic_settings_print" />
+  <java-symbol type="drawable" name="ic_signal_location" />
+  <java-symbol type="drawable" name="ic_info_outline_24" />
+
   <java-symbol type="drawable" name="stat_notify_mmcc_indication_icn" />
   <java-symbol type="drawable" name="autofilled_highlight"/>
   <java-symbol type="drawable" name="ic_camera" />
diff --git a/core/tests/coretests/Android.mk b/core/tests/coretests/Android.mk
index 8e8b07a..9d04e63 100644
--- a/core/tests/coretests/Android.mk
+++ b/core/tests/coretests/Android.mk
@@ -53,7 +53,6 @@
     org.apache.http.legacy \
     android.test.base \
     android.test.mock \
-    framework-oahl-backward-compatibility \
     framework-atb-backward-compatibility \
 
 LOCAL_PACKAGE_NAME := FrameworksCoreTests
diff --git a/core/tests/coretests/src/android/provider/SettingsBackupTest.java b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
index bd7f852..605c219 100644
--- a/core/tests/coretests/src/android/provider/SettingsBackupTest.java
+++ b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
@@ -132,6 +132,9 @@
                     Settings.Global.AUTOMATIC_POWER_SAVER_MODE,
                     Settings.Global.BACKGROUND_ACTIVITY_STARTS_ENABLED,
                     Settings.Global.BATTERY_CHARGING_STATE_UPDATE_DELAY,
+                    Settings.Global.BROADCAST_BG_CONSTANTS,
+                    Settings.Global.BROADCAST_FG_CONSTANTS,
+                    Settings.Global.BROADCAST_OFFLOAD_CONSTANTS,
                     Settings.Global.BATTERY_DISCHARGE_DURATION_THRESHOLD,
                     Settings.Global.BATTERY_DISCHARGE_THRESHOLD,
                     Settings.Global.BATTERY_SAVER_DEVICE_SPECIFIC_CONSTANTS,
@@ -575,6 +578,7 @@
                  Settings.Secure.ALLOWED_GEOLOCATION_ORIGINS,
                  Settings.Secure.ALWAYS_ON_VPN_APP,
                  Settings.Secure.ALWAYS_ON_VPN_LOCKDOWN,
+                 Settings.Secure.ALWAYS_ON_VPN_LOCKDOWN_WHITELIST,
                  Settings.Secure.ANDROID_ID,
                  Settings.Secure.ANR_SHOW_BACKGROUND,
                  Settings.Secure.ASSISTANT,
diff --git a/core/tests/coretests/src/android/service/notification/StatusBarNotificationTest.java b/core/tests/coretests/src/android/service/notification/StatusBarNotificationTest.java
index 4aa1000..c99777b 100644
--- a/core/tests/coretests/src/android/service/notification/StatusBarNotificationTest.java
+++ b/core/tests/coretests/src/android/service/notification/StatusBarNotificationTest.java
@@ -77,7 +77,6 @@
     @Test
     public void testLogMaker() {
         final LogMaker logMaker = getNotification(PKG, GROUP_ID_1, CHANNEL_ID).getLogMaker();
-
         assertEquals(CHANNEL_ID,
                 (String) logMaker.getTaggedData(MetricsEvent.FIELD_NOTIFICATION_CHANNEL_ID));
         assertEquals(PKG, logMaker.getPackageName());
@@ -85,6 +84,18 @@
         assertEquals(TAG, logMaker.getTaggedData(MetricsEvent.NOTIFICATION_TAG));
         assertEquals(GROUP_ID_1,
                 logMaker.getTaggedData(MetricsEvent.FIELD_NOTIFICATION_GROUP_ID));
+        assertEquals(0,
+                logMaker.getTaggedData(MetricsEvent.FIELD_NOTIFICATION_GROUP_SUMMARY));
+        assertNull(logMaker.getTaggedData(MetricsEvent.FIELD_NOTIFICATION_CATEGORY));
+    }
+
+    @Test
+    public void testLogMakerWithCategory() {
+        Notification.Builder builder = getNotificationBuilder(GROUP_ID_1, CHANNEL_ID)
+                        .setCategory(Notification.CATEGORY_MESSAGE);
+        final LogMaker logMaker = getNotification(PKG, builder).getLogMaker();
+        assertEquals(Notification.CATEGORY_MESSAGE,
+                logMaker.getTaggedData(MetricsEvent.FIELD_NOTIFICATION_CATEGORY));
     }
 
     @Test
@@ -138,6 +149,10 @@
     }
 
     private StatusBarNotification getNotification(String pkg, String group, String channelId) {
+        return getNotification(pkg, getNotificationBuilder(group, channelId));
+    }
+
+    private Notification.Builder getNotificationBuilder(String group, String channelId) {
         final Notification.Builder builder = new Notification.Builder(mMockContext, channelId)
                 .setContentTitle("foo")
                 .setSmallIcon(android.R.drawable.sym_def_app_icon);
@@ -145,10 +160,13 @@
         if (group != null) {
             builder.setGroup(group);
         }
+        return builder;
+    }
 
-        Notification n = builder.build();
+    private StatusBarNotification getNotification(String pkg, Notification.Builder builder) {
+
         return new StatusBarNotification(
-                pkg, pkg, ID, TAG, UID, UID, n, USER, null, UID);
+                pkg, pkg, ID, TAG, UID, UID, builder.build(), USER, null, UID);
     }
 
 }
diff --git a/core/tests/coretests/src/android/view/ImeInsetsSourceConsumerTest.java b/core/tests/coretests/src/android/view/ImeInsetsSourceConsumerTest.java
new file mode 100644
index 0000000..b07cb99
--- /dev/null
+++ b/core/tests/coretests/src/android/view/ImeInsetsSourceConsumerTest.java
@@ -0,0 +1,145 @@
+/*
+ * 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 android.view;
+
+import static android.view.ImeInsetsSourceConsumer.areEditorsSimilar;
+import static android.view.InsetsState.TYPE_IME;
+
+import static junit.framework.Assert.assertFalse;
+import static junit.framework.Assert.assertTrue;
+
+import android.content.Context;
+import android.graphics.Insets;
+import android.graphics.Rect;
+import android.os.Bundle;
+import android.platform.test.annotations.Presubmit;
+import android.view.SurfaceControl.Transaction;
+import android.view.WindowManager.BadTokenException;
+import android.view.WindowManager.LayoutParams;
+import android.view.inputmethod.EditorInfo;
+import android.widget.TextView;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.FlakyTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.ArrayList;
+
+@Presubmit
+@FlakyTest(detail = "Promote once confirmed non-flaky")
+@RunWith(AndroidJUnit4.class)
+public class ImeInsetsSourceConsumerTest {
+
+    Context mContext = InstrumentationRegistry.getTargetContext();
+    ImeInsetsSourceConsumer mImeConsumer;
+    InsetsController mController;
+    SurfaceControl mLeash;
+
+    @Before
+    public void setup() {
+        mLeash = new SurfaceControl.Builder(new SurfaceSession())
+                .setName("testSurface")
+                .build();
+        InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
+            ViewRootImpl viewRootImpl = new ViewRootImpl(mContext, mContext.getDisplay());
+            try {
+                viewRootImpl.setView(new TextView(mContext), new LayoutParams(), null);
+            } catch (BadTokenException e) {
+                // activity isn't running, we will ignore BadTokenException.
+            }
+            mController = new InsetsController(viewRootImpl);
+            final Rect rect = new Rect(5, 5, 5, 5);
+            mController.calculateInsets(
+                    false,
+                    false,
+                    new DisplayCutout(
+                            Insets.of(10, 10, 10, 10), rect, rect, rect, rect),
+                    rect, rect);
+            mImeConsumer = new ImeInsetsSourceConsumer(
+                    new InsetsState(), Transaction::new, mController);
+        });
+    }
+
+    @Test
+    public void testImeVisibility() {
+        final InsetsSourceControl ime = new InsetsSourceControl(TYPE_IME, mLeash);
+        mController.onControlsChanged(new InsetsSourceControl[] { ime });
+
+        InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
+            // test if setVisibility can show IME
+            mImeConsumer.onWindowFocusGained();
+            mImeConsumer.applyImeVisibility(true);
+            mController.cancelExistingAnimation();
+            assertTrue(mController.getSourceConsumer(ime.getType()).isVisible());
+
+            // test if setVisibility can hide IME
+            mImeConsumer.applyImeVisibility(false);
+            mController.cancelExistingAnimation();
+            assertFalse(mController.getSourceConsumer(ime.getType()).isVisible());
+        });
+    }
+
+    @Test
+    public void testAreEditorsSimilar() {
+        EditorInfo info1 = new EditorInfo();
+        info1.privateImeOptions = "dummy";
+        EditorInfo info2 = new EditorInfo();
+
+        assertFalse(areEditorsSimilar(info1, info2));
+
+        info1.privateImeOptions = null;
+        assertTrue(areEditorsSimilar(info1, info2));
+
+        info1.inputType = info2.inputType = 3;
+        info1.imeOptions = info2.imeOptions = 0x4;
+        info1.packageName = info2.packageName = "dummy.package";
+        assertTrue(areEditorsSimilar(info1, info2));
+
+        Bundle extras1 = new Bundle();
+        extras1.putByteArray("key1", "value1".getBytes());
+        extras1.putChar("key2", 'c');
+        Bundle extras2 = new Bundle();
+        extras2.putByteArray("key1", "value1".getBytes());
+        extras2.putChar("key2", 'c');
+        info1.extras = extras1;
+        info2.extras = extras2;
+        assertTrue(areEditorsSimilar(info1, info2));
+
+        Bundle extraBundle = new Bundle();
+        ArrayList<Integer> list = new ArrayList<>();
+        list.add(2);
+        list.add(5);
+        extraBundle.putByteArray("key1", "value1".getBytes());
+        extraBundle.putChar("key2", 'c');
+        extraBundle.putIntegerArrayList("key3", list);
+
+        extras1.putAll(extraBundle);
+        extras2.putAll(extraBundle);
+        assertTrue(areEditorsSimilar(info1, info2));
+
+        extras2.putChar("key2", 'd');
+        assertFalse(areEditorsSimilar(info1, info2));
+
+        extras2.putChar("key2", 'c');
+        extras2.putInt("key4", 1);
+        assertFalse(areEditorsSimilar(info1, info2));
+    }
+}
diff --git a/core/tests/coretests/src/android/view/InsetsStateTest.java b/core/tests/coretests/src/android/view/InsetsStateTest.java
index 2db2f5f..03af67d 100644
--- a/core/tests/coretests/src/android/view/InsetsStateTest.java
+++ b/core/tests/coretests/src/android/view/InsetsStateTest.java
@@ -155,10 +155,10 @@
 
     @Test
     public void testGetDefaultVisibility() {
-        assertTrue(InsetsState.getDefaultVisibly(TYPE_TOP_BAR));
-        assertTrue(InsetsState.getDefaultVisibly(TYPE_SIDE_BAR_1));
-        assertTrue(InsetsState.getDefaultVisibly(TYPE_SIDE_BAR_2));
-        assertTrue(InsetsState.getDefaultVisibly(TYPE_SIDE_BAR_3));
-        assertFalse(InsetsState.getDefaultVisibly(TYPE_IME));
+        assertTrue(InsetsState.getDefaultVisibility(TYPE_TOP_BAR));
+        assertTrue(InsetsState.getDefaultVisibility(TYPE_SIDE_BAR_1));
+        assertTrue(InsetsState.getDefaultVisibility(TYPE_SIDE_BAR_2));
+        assertTrue(InsetsState.getDefaultVisibility(TYPE_SIDE_BAR_3));
+        assertFalse(InsetsState.getDefaultVisibility(TYPE_IME));
     }
 }
diff --git a/core/tests/coretests/src/android/view/inputmethod/EditorInfoTest.java b/core/tests/coretests/src/android/view/inputmethod/EditorInfoTest.java
new file mode 100644
index 0000000..68099fe
--- /dev/null
+++ b/core/tests/coretests/src/android/view/inputmethod/EditorInfoTest.java
@@ -0,0 +1,74 @@
+/*
+ * 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.inputmethod;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+
+import android.os.Parcel;
+import android.os.UserHandle;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Supplemental tests that cannot be covered by CTS (e.g. due to hidden API dependencies).
+ */
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class EditorInfoTest {
+    private static final int TEST_USER_ID = 42;
+
+    /**
+     * Makes sure that {@code null} {@link EditorInfo#targetInputMethodUser} can be copied via
+     * {@link Parcel}.
+     */
+    @Test
+    public void testNullTargetInputMethodUserParcelable() throws Exception {
+        final EditorInfo editorInfo = new EditorInfo();
+        editorInfo.targetInputMethodUser = null;
+        assertNull(cloneViaParcel(editorInfo).targetInputMethodUser);
+    }
+
+    /**
+     * Makes sure that non-{@code null} {@link EditorInfo#targetInputMethodUser} can be copied via
+     * {@link Parcel}.
+     */
+    @Test
+    public void testNonNullTargetInputMethodUserParcelable() throws Exception {
+        final EditorInfo editorInfo = new EditorInfo();
+        editorInfo.targetInputMethodUser = UserHandle.of(TEST_USER_ID);
+        assertEquals(UserHandle.of(TEST_USER_ID), cloneViaParcel(editorInfo).targetInputMethodUser);
+    }
+
+    private static EditorInfo cloneViaParcel(EditorInfo original) {
+        Parcel parcel = null;
+        try {
+            parcel = Parcel.obtain();
+            original.writeToParcel(parcel, 0);
+            parcel.setDataPosition(0);
+            return EditorInfo.CREATOR.createFromParcel(parcel);
+        } finally {
+            if (parcel != null) {
+                parcel.recycle();
+            }
+        }
+    }
+}
diff --git a/core/tests/coretests/src/android/view/textclassifier/TextClassificationConstantsTest.java b/core/tests/coretests/src/android/view/textclassifier/TextClassificationConstantsTest.java
index 9662182..32bafec 100644
--- a/core/tests/coretests/src/android/view/textclassifier/TextClassificationConstantsTest.java
+++ b/core/tests/coretests/src/android/view/textclassifier/TextClassificationConstantsTest.java
@@ -16,9 +16,7 @@
 
 package android.view.textclassifier;
 
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
+import static com.google.common.truth.Truth.assertWithMessage;
 
 import androidx.test.filters.SmallTest;
 import androidx.test.runner.AndroidJUnit4;
@@ -30,6 +28,8 @@
 @RunWith(AndroidJUnit4.class)
 public class TextClassificationConstantsTest {
 
+    private static final float EPSILON = 0.0001f;
+
     @Test
     public void testLoadFromString() {
         final String s = "local_textclassifier_enabled=true,"
@@ -42,26 +42,55 @@
                 + "suggest_selection_max_range_length=10,"
                 + "classify_text_max_range_length=11,"
                 + "generate_links_max_text_length=12,"
-                + "generate_links_log_sample_rate=13";
+                + "generate_links_log_sample_rate=13,"
+                + "entity_list_default=phone,"
+                + "entity_list_not_editable=address:flight,"
+                + "entity_list_editable=date:datetime,"
+                + "in_app_conversation_action_types_default=text_reply,"
+                + "notification_conversation_action_types_default=send_email:call_phone,"
+                + "lang_id_threshold_override=0.3";
         final TextClassificationConstants constants =
                 TextClassificationConstants.loadFromString(s);
-        assertTrue("local_textclassifier_enabled",
-                constants.isLocalTextClassifierEnabled());
-        assertTrue("system_textclassifier_enabled",
-                constants.isSystemTextClassifierEnabled());
-        assertTrue("model_dark_launch_enabled", constants.isModelDarkLaunchEnabled());
-        assertTrue("smart_selection_enabled", constants.isSmartSelectionEnabled());
-        assertTrue("smart_text_share_enabled", constants.isSmartTextShareEnabled());
-        assertTrue("smart_linkify_enabled", constants.isSmartLinkifyEnabled());
-        assertTrue("smart_select_animation_enabled", constants.isSmartSelectionAnimationEnabled());
-        assertEquals("suggest_selection_max_range_length",
-                10, constants.getSuggestSelectionMaxRangeLength());
-        assertEquals("classify_text_max_range_length",
-                11, constants.getClassifyTextMaxRangeLength());
-        assertEquals("generate_links_max_text_length",
-                12, constants.getGenerateLinksMaxTextLength());
-        assertEquals("generate_links_log_sample_rate",
-                13, constants.getGenerateLinksLogSampleRate());
+
+        assertWithMessage("local_textclassifier_enabled")
+                .that(constants.isLocalTextClassifierEnabled()).isTrue();
+        assertWithMessage("system_textclassifier_enabled")
+                .that(constants.isSystemTextClassifierEnabled()).isTrue();
+        assertWithMessage("model_dark_launch_enabled")
+                .that(constants.isModelDarkLaunchEnabled()).isTrue();
+        assertWithMessage("smart_selection_enabled")
+                .that(constants.isSmartSelectionEnabled()).isTrue();
+        assertWithMessage("smart_text_share_enabled")
+                .that(constants.isSmartTextShareEnabled()).isTrue();
+        assertWithMessage("smart_linkify_enabled")
+                .that(constants.isSmartLinkifyEnabled()).isTrue();
+        assertWithMessage("smart_select_animation_enabled")
+                .that(constants.isSmartSelectionAnimationEnabled()).isTrue();
+        assertWithMessage("suggest_selection_max_range_length")
+                .that(constants.getSuggestSelectionMaxRangeLength()).isEqualTo(10);
+        assertWithMessage("classify_text_max_range_length")
+                .that(constants.getClassifyTextMaxRangeLength()).isEqualTo(11);
+        assertWithMessage("generate_links_max_text_length")
+                .that(constants.getGenerateLinksMaxTextLength()).isEqualTo(12);
+        assertWithMessage("generate_links_log_sample_rate")
+                .that(constants.getGenerateLinksLogSampleRate()).isEqualTo(13);
+        assertWithMessage("entity_list_default")
+                .that(constants.getEntityListDefault())
+                .containsExactly("phone");
+        assertWithMessage("entity_list_not_editable")
+                .that(constants.getEntityListNotEditable())
+                .containsExactly("address", "flight");
+        assertWithMessage("entity_list_editable")
+                .that(constants.getEntityListEditable())
+                .containsExactly("date", "datetime");
+        assertWithMessage("in_app_conversation_action_types_default")
+                .that(constants.getInAppConversationActionTypes())
+                .containsExactly("text_reply");
+        assertWithMessage("notification_conversation_action_types_default")
+                .that(constants.getNotificationConversationActionTypes())
+                .containsExactly("send_email", "call_phone");
+        assertWithMessage("lang_id_threshold_override")
+                .that(constants.getLangIdThresholdOverride()).isWithin(EPSILON).of(0.3f);
     }
 
     @Test
@@ -76,42 +105,102 @@
                 + "suggest_selection_max_range_length=8,"
                 + "classify_text_max_range_length=7,"
                 + "generate_links_max_text_length=6,"
-                + "generate_links_log_sample_rate=5";
+                + "generate_links_log_sample_rate=5,"
+                + "entity_list_default=email:url,"
+                + "entity_list_not_editable=date,"
+                + "entity_list_editable=flight,"
+                + "in_app_conversation_action_types_default=view_map:track_flight,"
+                + "notification_conversation_action_types_default=share_location,"
+                + "lang_id_threshold_override=2";
         final TextClassificationConstants constants =
                 TextClassificationConstants.loadFromString(s);
-        assertFalse("local_textclassifier_enabled",
-                constants.isLocalTextClassifierEnabled());
-        assertFalse("system_textclassifier_enabled",
-                constants.isSystemTextClassifierEnabled());
-        assertFalse("model_dark_launch_enabled", constants.isModelDarkLaunchEnabled());
-        assertFalse("smart_selection_enabled", constants.isSmartSelectionEnabled());
-        assertFalse("smart_text_share_enabled", constants.isSmartTextShareEnabled());
-        assertFalse("smart_linkify_enabled", constants.isSmartLinkifyEnabled());
-        assertFalse("smart_select_animation_enabled",
-                constants.isSmartSelectionAnimationEnabled());
-        assertEquals("suggest_selection_max_range_length",
-                8, constants.getSuggestSelectionMaxRangeLength());
-        assertEquals("classify_text_max_range_length",
-                7, constants.getClassifyTextMaxRangeLength());
-        assertEquals("generate_links_max_text_length",
-                6, constants.getGenerateLinksMaxTextLength());
-        assertEquals("generate_links_log_sample_rate",
-                5, constants.getGenerateLinksLogSampleRate());
+
+        assertWithMessage("local_textclassifier_enabled")
+                .that(constants.isLocalTextClassifierEnabled()).isFalse();
+        assertWithMessage("system_textclassifier_enabled")
+                .that(constants.isSystemTextClassifierEnabled()).isFalse();
+        assertWithMessage("model_dark_launch_enabled")
+                .that(constants.isModelDarkLaunchEnabled()).isFalse();
+        assertWithMessage("smart_selection_enabled")
+                .that(constants.isSmartSelectionEnabled()).isFalse();
+        assertWithMessage("smart_text_share_enabled")
+                .that(constants.isSmartTextShareEnabled()).isFalse();
+        assertWithMessage("smart_linkify_enabled")
+                .that(constants.isSmartLinkifyEnabled()).isFalse();
+        assertWithMessage("smart_select_animation_enabled")
+                .that(constants.isSmartSelectionAnimationEnabled()).isFalse();
+        assertWithMessage("suggest_selection_max_range_length")
+                .that(constants.getSuggestSelectionMaxRangeLength()).isEqualTo(8);
+        assertWithMessage("classify_text_max_range_length")
+                .that(constants.getClassifyTextMaxRangeLength()).isEqualTo(7);
+        assertWithMessage("generate_links_max_text_length")
+                .that(constants.getGenerateLinksMaxTextLength()).isEqualTo(6);
+        assertWithMessage("generate_links_log_sample_rate")
+                .that(constants.getGenerateLinksLogSampleRate()).isEqualTo(5);
+        assertWithMessage("entity_list_default")
+                .that(constants.getEntityListDefault())
+                .containsExactly("email", "url");
+        assertWithMessage("entity_list_not_editable")
+                .that(constants.getEntityListNotEditable())
+                .containsExactly("date");
+        assertWithMessage("entity_list_editable")
+                .that(constants.getEntityListEditable())
+                .containsExactly("flight");
+        assertWithMessage("in_app_conversation_action_types_default")
+                .that(constants.getInAppConversationActionTypes())
+                .containsExactly("view_map", "track_flight");
+        assertWithMessage("notification_conversation_action_types_default")
+                .that(constants.getNotificationConversationActionTypes())
+                .containsExactly("share_location");
+        assertWithMessage("lang_id_threshold_override")
+                .that(constants.getLangIdThresholdOverride()).isWithin(EPSILON).of(2f);
     }
 
     @Test
-    public void testEntityListParsing() {
-        final TextClassificationConstants constants = TextClassificationConstants.loadFromString(
-                "entity_list_default=phone,"
-                        + "entity_list_not_editable=address:flight,"
-                        + "entity_list_editable=date:datetime");
-        assertEquals(1, constants.getEntityListDefault().size());
-        assertEquals("phone", constants.getEntityListDefault().get(0));
-        assertEquals(2, constants.getEntityListNotEditable().size());
-        assertEquals("address", constants.getEntityListNotEditable().get(0));
-        assertEquals("flight", constants.getEntityListNotEditable().get(1));
-        assertEquals(2, constants.getEntityListEditable().size());
-        assertEquals("date", constants.getEntityListEditable().get(0));
-        assertEquals("datetime", constants.getEntityListEditable().get(1));
+    public void testLoadFromString_defaultValues() {
+        final TextClassificationConstants constants =
+                TextClassificationConstants.loadFromString("");
+
+        assertWithMessage("local_textclassifier_enabled")
+                .that(constants.isLocalTextClassifierEnabled()).isTrue();
+        assertWithMessage("system_textclassifier_enabled")
+                .that(constants.isSystemTextClassifierEnabled()).isTrue();
+        assertWithMessage("model_dark_launch_enabled")
+                .that(constants.isModelDarkLaunchEnabled()).isFalse();
+        assertWithMessage("smart_selection_enabled")
+                .that(constants.isSmartSelectionEnabled()).isTrue();
+        assertWithMessage("smart_text_share_enabled")
+                .that(constants.isSmartTextShareEnabled()).isTrue();
+        assertWithMessage("smart_linkify_enabled")
+                .that(constants.isSmartLinkifyEnabled()).isTrue();
+        assertWithMessage("smart_select_animation_enabled")
+                .that(constants.isSmartSelectionAnimationEnabled()).isTrue();
+        assertWithMessage("suggest_selection_max_range_length")
+                .that(constants.getSuggestSelectionMaxRangeLength()).isEqualTo(10 * 1000);
+        assertWithMessage("classify_text_max_range_length")
+                .that(constants.getClassifyTextMaxRangeLength()).isEqualTo(10 * 1000);
+        assertWithMessage("generate_links_max_text_length")
+                .that(constants.getGenerateLinksMaxTextLength()).isEqualTo(100 * 1000);
+        assertWithMessage("generate_links_log_sample_rate")
+                .that(constants.getGenerateLinksLogSampleRate()).isEqualTo(100);
+        assertWithMessage("entity_list_default")
+                .that(constants.getEntityListDefault())
+                .containsExactly("address", "email", "url", "phone", "date", "datetime", "flight");
+        assertWithMessage("entity_list_not_editable")
+                .that(constants.getEntityListNotEditable())
+                .containsExactly("address", "email", "url", "phone", "date", "datetime", "flight");
+        assertWithMessage("entity_list_editable")
+                .that(constants.getEntityListEditable())
+                .containsExactly("address", "email", "url", "phone", "date", "datetime", "flight");
+        assertWithMessage("in_app_conversation_action_types_default")
+                .that(constants.getInAppConversationActionTypes())
+                .containsExactly("text_reply", "create_reminder", "call_phone", "open_url",
+                        "send_email", "send_sms", "track_flight", "view_calendar", "view_map");
+        assertWithMessage("notification_conversation_action_types_default")
+                .that(constants.getNotificationConversationActionTypes())
+                .containsExactly("text_reply", "create_reminder", "call_phone", "open_url",
+                        "send_email", "send_sms", "track_flight", "view_calendar", "view_map");
+        assertWithMessage("lang_id_threshold_override")
+                .that(constants.getLangIdThresholdOverride()).isWithin(EPSILON).of(-1f);
     }
 }
diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml
index 904c3fb..1684138 100644
--- a/data/etc/privapp-permissions-platform.xml
+++ b/data/etc/privapp-permissions-platform.xml
@@ -87,6 +87,7 @@
         <permission name="android.permission.MASTER_CLEAR"/>
         <permission name="android.permission.NETWORK_MANAGED_PROVISIONING"/>
         <permission name="android.permission.PERFORM_CDMA_PROVISIONING"/>
+        <permission name="android.permission.READ_PRIVILEGED_PHONE_STATE"/>
         <permission name="android.permission.SET_TIME"/>
         <permission name="android.permission.SET_TIME_ZONE"/>
         <permission name="android.permission.SHUTDOWN"/>
diff --git a/graphics/java/android/graphics/Bitmap.java b/graphics/java/android/graphics/Bitmap.java
index 8636949..f0e2361 100644
--- a/graphics/java/android/graphics/Bitmap.java
+++ b/graphics/java/android/graphics/Bitmap.java
@@ -1751,6 +1751,50 @@
     }
 
     /**
+     * <p>Modifies the bitmap to have the specified {@link ColorSpace}, without
+     * affecting the underlying allocation backing the bitmap.</p>
+     *
+     * @throws IllegalArgumentException If the specified color space is {@code null}, not
+     *         {@link ColorSpace.Model#RGB RGB}, has a transfer function that is not an
+     *         {@link ColorSpace.Rgb.TransferParameters ICC parametric curve}, or whose
+     *         components min/max values reduce the numerical range compared to the
+     *         previously assigned color space.
+     *
+     * @param colorSpace to assign to the bitmap
+     * @hide
+     */
+    @TestApi
+    public void setColorSpace(@NonNull ColorSpace colorSpace) {
+        checkRecycled("setColorSpace called on a recycled bitmap");
+        if (colorSpace == null) {
+            throw new IllegalArgumentException("The colorSpace cannot be set to null");
+        }
+        if (getColorSpace() != null) {
+            if (mColorSpace.getComponentCount() != colorSpace.getComponentCount()) {
+                throw new IllegalArgumentException("The new ColorSpace must have the same "
+                        + "component count as the current ColorSpace");
+            }
+            for (int i = 0; i < mColorSpace.getComponentCount(); i++) {
+                if (mColorSpace.getMinValue(i) < colorSpace.getMinValue(i)) {
+                    throw new IllegalArgumentException("The new ColorSpace cannot increase the "
+                            + "minimum value for any of the components compared to the current "
+                            + "ColorSpace. To perform this type of conversion create a new Bitmap "
+                            + "in the desired ColorSpace and draw this Bitmap into it.");
+                }
+                if (mColorSpace.getMaxValue(i) > colorSpace.getMaxValue(i)) {
+                    throw new IllegalArgumentException("The new ColorSpace cannot decrease the "
+                            + "maximum value for any of the components compared to the current "
+                            + "ColorSpace/ To perform this type of conversion create a new Bitmap"
+                            + "in the desired ColorSpace and draw this Bitmap into it.");
+                }
+            }
+        }
+
+        nativeSetColorSpace(mNativePtr, colorSpace.getNativeInstance());
+        mColorSpace = colorSpace;
+    }
+
+    /**
      * Fills the bitmap's pixels with the specified {@link Color}.
      *
      * @throws IllegalStateException if the bitmap is not mutable.
@@ -2174,6 +2218,7 @@
                                                                 long nativeColorSpace);
     private static native GraphicBuffer nativeCreateGraphicBufferHandle(long nativeBitmap);
     private static native boolean nativeGetColorSpace(long nativePtr, float[] xyz, float[] params);
+    private static native void nativeSetColorSpace(long nativePtr, long nativeColorSpace);
     private static native boolean nativeIsSRGB(long nativePtr);
     private static native boolean nativeIsSRGBLinear(long nativePtr);
     private static native void nativeCopyColorSpace(long srcBitmap, long dstBitmap);
diff --git a/graphics/java/android/graphics/ImageFormat.java b/graphics/java/android/graphics/ImageFormat.java
index c580c46..0787d85 100644
--- a/graphics/java/android/graphics/ImageFormat.java
+++ b/graphics/java/android/graphics/ImageFormat.java
@@ -183,6 +183,14 @@
     public static final int JPEG = 0x100;
 
     /**
+     * Depth augmented compressed JPEG format.
+     *
+     * <p>JPEG compressed main image along with XMP embedded depth metadata
+     * following ISO 16684-1:2011(E).</p>
+     */
+    public static final int DEPTH_JPEG = 0x69656963;
+
+    /**
      * <p>Multi-plane Android YUV 420 format</p>
      *
      * <p>This format is a generic YCbCr format, capable of describing any 4:2:0
@@ -787,6 +795,7 @@
             case PRIVATE:
             case RAW_DEPTH:
             case Y8:
+            case DEPTH_JPEG:
                 return true;
         }
 
diff --git a/graphics/java/android/graphics/Typeface.java b/graphics/java/android/graphics/Typeface.java
index 25f6775..cb1f69c 100644
--- a/graphics/java/android/graphics/Typeface.java
+++ b/graphics/java/android/graphics/Typeface.java
@@ -33,6 +33,7 @@
 import android.graphics.fonts.FontVariationAxis;
 import android.graphics.fonts.SystemFonts;
 import android.os.Build;
+import android.os.Build.VERSION_CODES;
 import android.provider.FontRequest;
 import android.provider.FontsContract;
 import android.text.FontConfig;
@@ -46,6 +47,7 @@
 import com.android.internal.util.Preconditions;
 
 import dalvik.annotation.optimization.CriticalNative;
+import dalvik.system.VMRuntime;
 
 import libcore.util.NativeAllocationRegistry;
 
@@ -243,7 +245,16 @@
                 if (familyBuilder == null) {
                     familyBuilder = new FontFamily.Builder(fontBuilder.build());
                 } else {
-                    familyBuilder.addFont(fontBuilder.build());
+                    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;
+                    }
                 }
             }
             if (familyBuilder == null) {
diff --git a/keystore/java/android/security/Credentials.java b/keystore/java/android/security/Credentials.java
index 072fe73..2ae28f5 100644
--- a/keystore/java/android/security/Credentials.java
+++ b/keystore/java/android/security/Credentials.java
@@ -16,12 +16,6 @@
 
 package android.security;
 
-import android.annotation.UnsupportedAppUsage;
-import android.content.ActivityNotFoundException;
-import android.content.Context;
-import android.content.Intent;
-import android.util.Log;
-
 import com.android.org.bouncycastle.util.io.pem.PemObject;
 import com.android.org.bouncycastle.util.io.pem.PemReader;
 import com.android.org.bouncycastle.util.io.pem.PemWriter;
@@ -34,7 +28,6 @@
 import java.io.Reader;
 import java.io.Writer;
 import java.nio.charset.StandardCharsets;
-import java.security.KeyPair;
 import java.security.cert.Certificate;
 import java.security.cert.CertificateEncodingException;
 import java.security.cert.CertificateException;
@@ -53,8 +46,6 @@
 
     public static final String INSTALL_AS_USER_ACTION = "android.credentials.INSTALL_AS_USER";
 
-    public static final String UNLOCK_ACTION = "com.android.credentials.UNLOCK";
-
     /** Key prefix for CA certificates. */
     public static final String CA_CERTIFICATE = "CACERT_";
 
@@ -171,58 +162,6 @@
         }
     }
 
-    private static Credentials singleton;
-
-    @UnsupportedAppUsage
-    public static Credentials getInstance() {
-        if (singleton == null) {
-            singleton = new Credentials();
-        }
-        return singleton;
-    }
-
-    @UnsupportedAppUsage
-    public void unlock(Context context) {
-        try {
-            Intent intent = new Intent(UNLOCK_ACTION);
-            context.startActivity(intent);
-        } catch (ActivityNotFoundException e) {
-            Log.w(LOGTAG, e.toString());
-        }
-    }
-
-    public void install(Context context) {
-        try {
-            Intent intent = KeyChain.createInstallIntent();
-            context.startActivity(intent);
-        } catch (ActivityNotFoundException e) {
-            Log.w(LOGTAG, e.toString());
-        }
-    }
-
-    @UnsupportedAppUsage
-    public void install(Context context, KeyPair pair) {
-        try {
-            Intent intent = KeyChain.createInstallIntent();
-            intent.putExtra(EXTRA_PRIVATE_KEY, pair.getPrivate().getEncoded());
-            intent.putExtra(EXTRA_PUBLIC_KEY, pair.getPublic().getEncoded());
-            context.startActivity(intent);
-        } catch (ActivityNotFoundException e) {
-            Log.w(LOGTAG, e.toString());
-        }
-    }
-
-    @UnsupportedAppUsage
-    public void install(Context context, String type, byte[] value) {
-        try {
-            Intent intent = KeyChain.createInstallIntent();
-            intent.putExtra(type, value);
-            context.startActivity(intent);
-        } catch (ActivityNotFoundException e) {
-            Log.w(LOGTAG, e.toString());
-        }
-    }
-
     /**
      * Delete all types (private key, user certificate, CA certificate) for a
      * particular {@code alias}. All three can exist for any given alias.
diff --git a/media/Android.bp b/media/Android.bp
index 0675a36..753f4b7 100644
--- a/media/Android.bp
+++ b/media/Android.bp
@@ -25,9 +25,10 @@
 }
 
 java_library {
-    name: "updatable-mediasession2",
+    name: "updatable-media",
 
     srcs: [
+        ":mediaplayer2-srcs",
         ":mediasession2-srcs",
         ":framework-media-annotation-srcs",
     ],
@@ -37,26 +38,12 @@
             "apex/java",
         ],
 
-        // TODO: find out a way to include only the necessary aidl files instead of dirs.
         include_dirs: [
+            // For the usage of android.os.Bundle and android.os.ResultReceiver in aidl files
             "frameworks/base/core/java",
         ],
     },
 
-    installable: true,
-
-    // Make sure that the implementaion only relies on SDK or system APIs.
-    sdk_version: "system_current",
-}
-
-java_library {
-    name: "updatable-media",
-
-    srcs: [
-        ":mediaplayer2-srcs",
-        ":framework-media-annotation-srcs",
-    ],
-
     static_libs: [
         "mediaplayer2-protos",
     ],
diff --git a/media/apex/java/android/media/MediaPlayer2.java b/media/apex/java/android/media/MediaPlayer2.java
index a2feec2..1a1f6fb 100644
--- a/media/apex/java/android/media/MediaPlayer2.java
+++ b/media/apex/java/android/media/MediaPlayer2.java
@@ -4482,6 +4482,7 @@
     };
 
     // Modular DRM
+    private final Map<UUID, MediaDrm> mDrmObjs = new HashMap<>();
     private class DrmHandle {
 
         static final int PROVISION_TIMEOUT_MS = 60000;
@@ -4594,7 +4595,13 @@
             Log.v(TAG, "prepareDrm_createDrmStep: UUID: " + uuid);
 
             try {
-                mDrmObj = new MediaDrm(uuid);
+                mDrmObj = mDrmObjs.computeIfAbsent(uuid, scheme -> {
+                    try {
+                        return new MediaDrm(scheme);
+                    } catch (UnsupportedSchemeException e) {
+                        throw new IllegalArgumentException(e);
+                    }
+                });
                 Log.v(TAG, "prepareDrm_createDrmStep: Created mDrmObj=" + mDrmObj);
             } catch (Exception e) { // UnsupportedSchemeException
                 Log.e(TAG, "prepareDrm_createDrmStep: MediaDrm failed with " + e);
@@ -4837,7 +4844,12 @@
                 msg = mTaskHandler.obtainMessage(
                         MEDIA_ERROR, status, MEDIA_ERROR_UNKNOWN, null);
             }
-            mTaskHandler.sendMessage(msg);
+            mTaskHandler.post(new Runnable() {
+                @Override
+                public void run() {
+                    mTaskHandler.handleMessage(msg, mSrcId);
+                }
+            });
 
             sendDrmEvent(new DrmEventNotifier() {
                 @Override
diff --git a/media/apex/java/android/media/MediaSession2Service.java b/media/apex/java/android/media/MediaSession2Service.java
index f18cd31..54d0ed2 100644
--- a/media/apex/java/android/media/MediaSession2Service.java
+++ b/media/apex/java/android/media/MediaSession2Service.java
@@ -16,8 +16,6 @@
 
 package android.media;
 
-import static android.media.Session2Token.SESSION_SERVICE_INTERFACE;
-
 import android.annotation.CallSuper;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
@@ -47,6 +45,10 @@
  * for consistent behavior across all devices.
  */
 public abstract class MediaSession2Service extends Service {
+    /**
+     * The {@link Intent} that must be declared as handled by the service.
+     */
+    public static final String SERVICE_INTERFACE = Session2Token.SESSION_SERVICE_INTERFACE;
 
     private static final String TAG = "MediaSession2Service";
     private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
@@ -98,7 +100,7 @@
     @Override
     @Nullable
     public IBinder onBind(@NonNull Intent intent) {
-        if (SESSION_SERVICE_INTERFACE.equals(intent.getAction())) {
+        if (SERVICE_INTERFACE.equals(intent.getAction())) {
             synchronized (mLock) {
                 return mStub;
             }
diff --git a/media/apex/java/android/media/session/MediaController.java b/media/apex/java/android/media/session/MediaController.java
index d43acf4..79389a8 100644
--- a/media/apex/java/android/media/session/MediaController.java
+++ b/media/apex/java/android/media/session/MediaController.java
@@ -18,6 +18,7 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.SystemApi;
 import android.annotation.UnsupportedAppUsage;
 import android.app.PendingIntent;
 import android.content.Context;
@@ -82,42 +83,26 @@
     private final TransportControls mTransportControls;
 
     /**
-     * Call for creating a MediaController directly from a controller link. Should only
-     * be used by framework code.
-     * @hide
-     */
-    public MediaController(Context context, ControllerLink sessionBinder) {
-        if (sessionBinder == null) {
-            throw new IllegalArgumentException("Session token cannot be null");
-        }
-        if (context == null) {
-            throw new IllegalArgumentException("Context cannot be null");
-        }
-        mSessionBinder = sessionBinder;
-        mTransportControls = new TransportControls();
-        mToken = new MediaSession.Token(sessionBinder);
-        mContext = context;
-        mCbStub = new ControllerCallbackLink(context, new CallbackStub(this));
-    }
-
-    /**
-     * Call for creating a MediaController directly from a binder. Should only
-     * be used by framework code.
-     * @hide
-     * TODO: remove this constructor
-     */
-    public MediaController(Context context, ISessionController sessionBinder) {
-        this(context, new ControllerLink(sessionBinder.asBinder()));
-    }
-
-    /**
      * Create a new MediaController from a session's token.
      *
      * @param context The caller's context.
      * @param token The token for the session.
      */
     public MediaController(@NonNull Context context, @NonNull MediaSession.Token token) {
-        this(context, token.getControllerLink());
+        if (context == null) {
+            throw new IllegalArgumentException("context shouldn't be null");
+        }
+        if (token == null) {
+            throw new IllegalArgumentException("token shouldn't be null");
+        }
+        if (token.getControllerLink() == null) {
+            throw new IllegalArgumentException("token.getControllerLink() shouldn't be null");
+        }
+        mSessionBinder = token.getControllerLink();
+        mTransportControls = new TransportControls();
+        mToken = token;
+        mContext = context;
+        mCbStub = new ControllerCallbackLink(context, new CallbackStub(this));
     }
 
     /**
@@ -501,7 +486,6 @@
      * Get the session's tag for debugging purposes.
      *
      * @return The session's tag.
-     * @hide
      */
     public String getTag() {
         if (mTag == null) {
@@ -1011,6 +995,7 @@
         /**
          * @hide
          */
+        @SystemApi
         public PlaybackInfo(int type, int control, int max, int current, AudioAttributes attrs) {
             mVolumeType = type;
             mVolumeControl = control;
diff --git a/media/apex/java/android/media/session/MediaSessionEngine.java b/media/apex/java/android/media/session/MediaSessionEngine.java
index 1f5fa5f..edf283e 100644
--- a/media/apex/java/android/media/session/MediaSessionEngine.java
+++ b/media/apex/java/android/media/session/MediaSessionEngine.java
@@ -451,12 +451,24 @@
     }
 
     /**
+     * Returns the name of the package that sent the last media button, transport control, or
+     * command from controllers and the system. This is only valid while in a request callback, such
+     * as {@link MediaSession.Callback#onPlay}.
+     */
+    public String getCallingPackage() {
+        if (mCallbackHandler != null && mCallbackHandler.mCurrentControllerInfo != null) {
+            return mCallbackHandler.mCurrentControllerInfo.getPackageName();
+        }
+        return null;
+    }
+
+
+    /**
      * Notify the system that the remote volume changed.
      *
      * @param provider The provider that is handling volume changes.
-     * @hide
      */
-    public void notifyRemoteVolumeChanged(VolumeProvider provider) {
+    private void notifyRemoteVolumeChanged(VolumeProvider provider) {
         synchronized (mLock) {
             if (provider == null || provider != mVolumeProvider) {
                 Log.w(TAG, "Received update from stale volume provider");
@@ -470,18 +482,6 @@
         }
     }
 
-    /**
-     * Returns the name of the package that sent the last media button, transport control, or
-     * command from controllers and the system. This is only valid while in a request callback, such
-     * as {@link MediaSession.Callback#onPlay}.
-     */
-    public String getCallingPackage() {
-        if (mCallbackHandler != null && mCallbackHandler.mCurrentControllerInfo != null) {
-            return mCallbackHandler.mCurrentControllerInfo.getPackageName();
-        }
-        return null;
-    }
-
     private void dispatchPrepare(RemoteUserInfo caller) {
         postToCallback(caller, CallbackMessageHandler.MSG_PREPARE, null, null);
     }
diff --git a/media/java/android/media/AudioTrack.java b/media/java/android/media/AudioTrack.java
index 5e77fdf..3440cde 100644
--- a/media/java/android/media/AudioTrack.java
+++ b/media/java/android/media/AudioTrack.java
@@ -996,6 +996,50 @@
     }
 
     /**
+     * Configures the delay and padding values for the current compressed stream playing
+     * in offload mode.
+     * This can only be used on a track successfully initialized with
+     * {@link AudioTrack.Builder#setOffloadedPlayback(boolean)}. The unit is frames, where a
+     * 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.
+     */
+    public void setOffloadDelayPadding(int delayInFrames, int paddingInFrames) {
+        if (paddingInFrames < 0) {
+            throw new IllegalArgumentException("Illegal negative padding");
+        }
+        if (delayInFrames < 0) {
+            throw new IllegalArgumentException("Illegal negative delay");
+        }
+        if (!mOffloaded) {
+            throw new IllegalStateException("Illegal use of delay/padding on non-offloaded track");
+        }
+        if (mState == STATE_UNINITIALIZED) {
+            throw new IllegalStateException("Uninitialized track");
+        }
+        native_set_delay_padding(delayInFrames, paddingInFrames);
+    }
+
+    /**
+     * Declares that the last write() operation on this track provided the last buffer of this
+     * stream.
+     * After the end of stream, previously set padding and delay values are ignored.
+     * Use this method in the same thread as any write() operation.
+     */
+    public void setOffloadEndOfStream() {
+        if (!mOffloaded) {
+            throw new IllegalStateException("EOS not supported on non-offloaded track");
+        }
+        if (mState == STATE_UNINITIALIZED) {
+            throw new IllegalStateException("Uninitialized track");
+        }
+        native_set_eos();
+    }
+
+    /**
      * Returns whether direct playback of an audio format with the provided attributes is
      * currently supported on the system.
      * <p>Direct playback means that the audio stream is not resampled or downmixed
@@ -3457,6 +3501,9 @@
 
     private native int native_getPortId();
 
+    private native void native_set_delay_padding(int delayInFrames, int paddingInFrames);
+    private native void native_set_eos();
+
     //---------------------------------------------------------
     // Utility methods
     //------------------
diff --git a/media/java/android/media/ImageReader.java b/media/java/android/media/ImageReader.java
index 9ac147b..60ef1d9 100644
--- a/media/java/android/media/ImageReader.java
+++ b/media/java/android/media/ImageReader.java
@@ -17,12 +17,10 @@
 package android.media;
 
 import android.graphics.ImageFormat;
-import android.graphics.PixelFormat;
 import android.hardware.HardwareBuffer;
 import android.os.Handler;
 import android.os.Looper;
 import android.os.Message;
-import android.util.Log;
 import android.view.Surface;
 
 import dalvik.system.VMRuntime;
@@ -74,12 +72,6 @@
     private static final int ACQUIRE_MAX_IMAGES = 2;
 
     /**
-     * Invalid consumer buffer usage flag. This usage flag will be ignored
-     * by the {@code ImageReader} instance is constructed with this value.
-     */
-    private static final long BUFFER_USAGE_UNKNOWN = 0;
-
-    /**
      * <p>
      * Create a new reader for images of the desired size and format.
      * </p>
@@ -129,7 +121,10 @@
      * @see Image
      */
     public static ImageReader newInstance(int width, int height, int format, int maxImages) {
-        return new ImageReader(width, height, format, maxImages, BUFFER_USAGE_UNKNOWN);
+        // If the format is private don't default to USAGE_CPU_READ_OFTEN since it may not
+        // work, and is inscrutable anyway
+        return new ImageReader(width, height, format, maxImages,
+                format == ImageFormat.PRIVATE ? 0 : HardwareBuffer.USAGE_CPU_READ_OFTEN);
     }
 
     /**
@@ -207,18 +202,23 @@
      *            obtained by the user, one of them has to be released before a new Image will
      *            become available for access through {@link #acquireLatestImage()} or
      *            {@link #acquireNextImage()}. Must be greater than 0.
-     * @param usage The intended usage of the images produced by this ImageReader. It needs
-     *            to be one of the Usage defined by {@link HardwareBuffer}, or an
-     *            {@link IllegalArgumentException} will be thrown.
+     * @param usage The intended usage of the images produced by this ImageReader. See the usages
+     *              on {@link HardwareBuffer} for a list of valid usage bits. See also
+     *              {@link HardwareBuffer#isSupported(int, int, int, int, long)} for checking
+     *              if a combination is supported. If it's not supported this will throw
+     *              an {@link IllegalArgumentException}.
      * @see Image
      * @see HardwareBuffer
      */
     public static ImageReader newInstance(int width, int height, int format, int maxImages,
             long usage) {
-        if (!isFormatUsageCombinationAllowed(format, usage)) {
-            throw new IllegalArgumentException("Format usage combination is not supported:"
-                    + " format = " + format + ", usage = " + usage);
-        }
+        // TODO: Check this - can't do it just yet because format support is different
+        // Unify formats! The only reliable way to validate usage is to just try it and see.
+
+//        if (!HardwareBuffer.isSupported(width, height, format, 1, usage)) {
+//            throw new IllegalArgumentException("The given format=" + Integer.toHexString(format)
+//                + " & usage=" + Long.toHexString(usage) + " is not supported");
+//        }
         return new ImageReader(width, height, format, maxImages, usage);
     }
 
@@ -716,19 +716,6 @@
         return si.getReader() == this;
     }
 
-    private static boolean isFormatUsageCombinationAllowed(int format, long usage) {
-        if (!ImageFormat.isPublicFormat(format) && !PixelFormat.isPublicFormat(format)) {
-            return false;
-        }
-
-        // Valid usage needs to be provided.
-        if (usage == BUFFER_USAGE_UNKNOWN) {
-            return false;
-        }
-
-        return true;
-    }
-
     /**
      * Called from Native code when an Event happens.
      *
@@ -833,6 +820,7 @@
                 case ImageFormat.JPEG:
                 case ImageFormat.DEPTH_POINT_CLOUD:
                 case ImageFormat.RAW_PRIVATE:
+                case ImageFormat.DEPTH_JPEG:
                     width = ImageReader.this.getWidth();
                     break;
                 default:
@@ -849,6 +837,7 @@
                 case ImageFormat.JPEG:
                 case ImageFormat.DEPTH_POINT_CLOUD:
                 case ImageFormat.RAW_PRIVATE:
+                case ImageFormat.DEPTH_JPEG:
                     height = ImageReader.this.getHeight();
                     break;
                 default:
diff --git a/media/java/android/media/ImageUtils.java b/media/java/android/media/ImageUtils.java
index 2a0e04e..b77a884 100644
--- a/media/java/android/media/ImageUtils.java
+++ b/media/java/android/media/ImageUtils.java
@@ -63,6 +63,7 @@
             case ImageFormat.DEPTH16:
             case ImageFormat.DEPTH_POINT_CLOUD:
             case ImageFormat.RAW_DEPTH:
+            case ImageFormat.DEPTH_JPEG:
                 return 1;
             case ImageFormat.PRIVATE:
                 return 0;
@@ -192,6 +193,7 @@
             // 10x compression from RGB_888
             case ImageFormat.JPEG:
             case ImageFormat.DEPTH_POINT_CLOUD:
+            case ImageFormat.DEPTH_JPEG:
                 estimatedBytePerPixel = 0.3;
                 break;
             case ImageFormat.Y8:
diff --git a/media/java/android/media/MediaMetadataRetriever.java b/media/java/android/media/MediaMetadataRetriever.java
index 33b8c42..112ce1d 100644
--- a/media/java/android/media/MediaMetadataRetriever.java
+++ b/media/java/android/media/MediaMetadataRetriever.java
@@ -920,12 +920,14 @@
     public static final int METADATA_KEY_VIDEO_FRAME_COUNT = 32;
 
     /**
-     * @hide
+     * If the media contains EXIF data, this key retrieves the offset value
+     * of the data.
      */
     public static final int METADATA_KEY_EXIF_OFFSET = 33;
 
     /**
-     * @hide
+     * If the media contains EXIF data, this key retrieves the length of the
+     * data.
      */
     public static final int METADATA_KEY_EXIF_LENGTH = 34;
 
diff --git a/media/java/android/media/MediaRouter.java b/media/java/android/media/MediaRouter.java
index ffeff4d..3444e92 100644
--- a/media/java/android/media/MediaRouter.java
+++ b/media/java/android/media/MediaRouter.java
@@ -2357,8 +2357,7 @@
                 return;
             }
             if (mPlaybackType == RemoteControlClient.PLAYBACK_TYPE_REMOTE) {
-                @VolumeProvider.ControlType int volumeControl =
-                        VolumeProvider.VOLUME_CONTROL_FIXED;
+                int volumeControl = VolumeProvider.VOLUME_CONTROL_FIXED;
                 switch (mVolumeHandling) {
                     case RemoteControlClient.PLAYBACK_VOLUME_VARIABLE:
                         volumeControl = VolumeProvider.VOLUME_CONTROL_ABSOLUTE;
@@ -2384,8 +2383,7 @@
 
         class SessionVolumeProvider extends VolumeProvider {
 
-            public SessionVolumeProvider(@VolumeProvider.ControlType int volumeControl,
-                    int maxVolume, int currentVolume) {
+            SessionVolumeProvider(int volumeControl, int maxVolume, int currentVolume) {
                 super(volumeControl, maxVolume, currentVolume);
             }
 
diff --git a/media/java/android/media/MediaScanner.java b/media/java/android/media/MediaScanner.java
index 33e7d8e..30719fd 100644
--- a/media/java/android/media/MediaScanner.java
+++ b/media/java/android/media/MediaScanner.java
@@ -1277,7 +1277,8 @@
                 // we need to query the database in small batches, to avoid problems
                 // with CursorWindow positioning.
                 long lastId = Long.MIN_VALUE;
-                Uri limitUri = mFilesUri.buildUpon().appendQueryParameter("limit", "1000").build();
+                Uri limitUri = mFilesUri.buildUpon()
+                        .appendQueryParameter(MediaStore.PARAM_LIMIT, "1000").build();
 
                 while (true) {
                     selectionArgs[0] = "" + lastId;
diff --git a/media/java/android/media/session/ISessionManager.aidl b/media/java/android/media/session/ISessionManager.aidl
index fa6e034..e360808 100644
--- a/media/java/android/media/session/ISessionManager.aidl
+++ b/media/java/android/media/session/ISessionManager.aidl
@@ -18,12 +18,12 @@
 import android.content.ComponentName;
 import android.media.IRemoteVolumeController;
 import android.media.Session2Token;
-import android.media.session.ControllerLink;
 import android.media.session.IActiveSessionsListener;
 import android.media.session.ICallback;
 import android.media.session.IOnMediaKeyListener;
 import android.media.session.IOnVolumeKeyLongPressListener;
 import android.media.session.ISession2TokensListener;
+import android.media.session.MediaSession;
 import android.media.session.SessionCallbackLink;
 import android.media.session.SessionLink;
 import android.os.Bundle;
@@ -38,7 +38,7 @@
             int userId);
     void notifySession2Created(in Session2Token sessionToken);
     void notifySession2Destroyed(in Session2Token sessionToken);
-    List<ControllerLink> getSessions(in ComponentName compName, int userId);
+    List<MediaSession.Token> getSessions(in ComponentName compName, int userId);
     List<Session2Token> getSession2Tokens(int userId);
     void dispatchMediaKeyEvent(String packageName, boolean asSystemService, in KeyEvent keyEvent,
             boolean needWakeLock);
diff --git a/media/java/android/media/session/MediaSession.java b/media/java/android/media/session/MediaSession.java
index 1a185e9..682e79a 100644
--- a/media/java/android/media/session/MediaSession.java
+++ b/media/java/android/media/session/MediaSession.java
@@ -392,16 +392,6 @@
     }
 
     /**
-     * Notify the system that the remote volume changed.
-     *
-     * @param provider The provider that is handling volume changes.
-     * @hide
-     */
-    public void notifyRemoteVolumeChanged(VolumeProvider provider) {
-        mImpl.notifyRemoteVolumeChanged(provider);
-    }
-
-    /**
      * Returns the name of the package that sent the last media button, transport control, or
      * command from controllers and the system. This is only valid while in a request callback, such
      * as {@link Callback#onPlay}.
diff --git a/media/java/android/media/session/MediaSessionManager.java b/media/java/android/media/session/MediaSessionManager.java
index cae4d17..7563867 100644
--- a/media/java/android/media/session/MediaSessionManager.java
+++ b/media/java/android/media/session/MediaSessionManager.java
@@ -202,10 +202,10 @@
             @Nullable ComponentName notificationListener, int userId) {
         ArrayList<MediaController> controllers = new ArrayList<MediaController>();
         try {
-            List<ControllerLink> binders = mService.getSessions(notificationListener, userId);
-            int size = binders.size();
+            List<MediaSession.Token> tokens = mService.getSessions(notificationListener, userId);
+            int size = tokens.size();
             for (int i = 0; i < size; i++) {
-                MediaController controller = new MediaController(mContext, binders.get(i));
+                MediaController controller = new MediaController(mContext, tokens.get(i));
                 controllers.add(controller);
             }
         } catch (RemoteException e) {
diff --git a/media/java/android/media/tv/TvContract.java b/media/java/android/media/tv/TvContract.java
index 21c58b3..09b7559 100644
--- a/media/java/android/media/tv/TvContract.java
+++ b/media/java/android/media/tv/TvContract.java
@@ -20,9 +20,9 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.SdkConstant;
+import android.annotation.SdkConstant.SdkConstantType;
 import android.annotation.StringDef;
 import android.annotation.SystemApi;
-import android.annotation.SdkConstant.SdkConstantType;
 import android.app.Activity;
 import android.content.ComponentName;
 import android.content.ContentResolver;
@@ -1680,6 +1680,7 @@
                 TYPE_ISDB_T,
                 TYPE_ISDB_TB,
                 TYPE_ISDB_S,
+                TYPE_ISDB_S3,
                 TYPE_ISDB_C,
                 TYPE_1SEG,
                 TYPE_DTMB,
@@ -1821,6 +1822,13 @@
         public static final String TYPE_ISDB_S = "TYPE_ISDB_S";
 
         /**
+         * The channel type for ISDB-S3 (satellite).
+         *
+         * @see #COLUMN_TYPE
+         */
+        public static final String TYPE_ISDB_S3 = "TYPE_ISDB_S3";
+
+        /**
          * The channel type for ISDB-C (cable).
          *
          * @see #COLUMN_TYPE
@@ -2026,6 +2034,7 @@
          * {@link #TYPE_DVB_T2},
          * {@link #TYPE_ISDB_C},
          * {@link #TYPE_ISDB_S},
+         * {@link #TYPE_ISDB_S3},
          * {@link #TYPE_ISDB_T},
          * {@link #TYPE_ISDB_TB},
          * {@link #TYPE_NTSC},
diff --git a/media/jni/Android.bp b/media/jni/Android.bp
index 852d296..0fb4d2a 100644
--- a/media/jni/Android.bp
+++ b/media/jni/Android.bp
@@ -94,26 +94,14 @@
     ],
 
     shared_libs: [
-        // MediaCas
-        "android.hardware.cas@1.0",
-        "android.hardware.cas.native@1.0",
-        "android.hidl.allocator@1.0",
-        "libhidlbase",
-        "libhidlmemory",
-
-        "libmediametrics",
-        "libbinder",  // Used by JWakeLock and MediaMetrics.
-
-        "libutils",  // Have to use shared lib to make libandroid_runtime behave correctly.
-                     // Otherwise, AndroidRuntime::getJNIEnv() will return NULL.
-
-        // NDK or NDK-compliant
+        // NDK or LLNDK or NDK-compliant
         "libandroid",
         "libbinder_ndk",
         "libmediandk",
+        "libmediametrics",
         "libnativehelper_compat_libc++",
         "liblog",
-        "libz",
+        "libvndksupport",
     ],
 
     header_libs: [
@@ -122,6 +110,16 @@
     ],
 
     static_libs: [
+        // MediaCas
+        "android.hidl.allocator@1.0",
+        "android.hidl.memory@1.0",
+        "libhidlbase",
+        "libhidlmemory",
+        "libhidltransport",
+        "libhwbinder",
+        "libbinderthreadstate",
+
+        // MediaPlayer2 implementation
         "libbase",
         "libcrypto",
         "libcutils",
@@ -131,10 +129,11 @@
         "libmediaplayer2-protos",
         "libmediandk_utils",
         "libmediautils",
+        "libprocessgroup",
         "libprotobuf-cpp-lite",
         "libstagefright",
         "libstagefright_esds",
-        "libstagefright_foundation",
+        "libstagefright_foundation_without_imemory",
         "libstagefright_httplive",
         "libstagefright_id3",
         "libstagefright_mpeg2support",
@@ -142,6 +141,7 @@
         "libstagefright_player2",
         "libstagefright_rtsp_player2",
         "libstagefright_timedtext2",
+        "libutils",
         "libmedia2_jni_core",
     ],
 
@@ -161,6 +161,7 @@
         "-Wno-error=deprecated-declarations",
         "-Wunused",
         "-Wunreachable-code",
+        "-fvisibility=hidden",
     ],
 
     ldflags: ["-Wl,--exclude-libs=ALL,-error-limit=0"],
diff --git a/media/jni/android_media_ImageReader.cpp b/media/jni/android_media_ImageReader.cpp
index 417a427..7168b2d 100644
--- a/media/jni/android_media_ImageReader.cpp
+++ b/media/jni/android_media_ImageReader.cpp
@@ -379,24 +379,9 @@
     String8 consumerName = String8::format("ImageReader-%dx%df%xm%d-%d-%d",
             width, height, format, maxImages, getpid(),
             createProcessUniqueId());
-    uint32_t consumerUsage = GRALLOC_USAGE_SW_READ_OFTEN;
-    bool needUsageOverride = ndkUsage != CONSUMER_BUFFER_USAGE_UNKNOWN;
-    uint64_t outProducerUsage = 0;
-    uint64_t outConsumerUsage = 0;
-    android_hardware_HardwareBuffer_convertToGrallocUsageBits(&outProducerUsage, &outConsumerUsage,
-            ndkUsage, 0);
+    uint64_t consumerUsage =
+            android_hardware_HardwareBuffer_convertToGrallocUsageBits(ndkUsage);
 
-    if (isFormatOpaque(nativeFormat)) {
-        // Use the SW_READ_NEVER usage to tell producer that this format is not for preview or video
-        // encoding. The only possibility will be ZSL output.
-        consumerUsage = GRALLOC_USAGE_SW_READ_NEVER;
-        if (needUsageOverride) {
-            consumerUsage = android_convertGralloc1To0Usage(0, outConsumerUsage);
-        }
-    } else if (needUsageOverride) {
-        ALOGW("Consumer usage override for non-opaque format is not implemented yet, "
-                "ignore the provided usage from the application");
-    }
     bufferConsumer = new BufferItemConsumer(gbConsumer, consumerUsage, maxImages,
             /*controlledByApp*/true);
     if (bufferConsumer == nullptr) {
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/helpers/CameraTestUtils.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/helpers/CameraTestUtils.java
index 5ab5092..0340cec 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/helpers/CameraTestUtils.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/helpers/CameraTestUtils.java
@@ -857,7 +857,7 @@
         // JPEG doesn't have pixelstride and rowstride, treat it as 1D buffer.
         // Same goes for DEPTH_POINT_CLOUD
         if (format == ImageFormat.JPEG || format == ImageFormat.DEPTH_POINT_CLOUD ||
-                format == ImageFormat.RAW_PRIVATE) {
+                format == ImageFormat.DEPTH_JPEG || format == ImageFormat.RAW_PRIVATE) {
             buffer = planes[0].getBuffer();
             assertNotNull("Fail to get jpeg or depth ByteBuffer", buffer);
             data = new byte[buffer.remaining()];
@@ -940,6 +940,7 @@
             case ImageFormat.RAW_PRIVATE:
             case ImageFormat.DEPTH16:
             case ImageFormat.DEPTH_POINT_CLOUD:
+            case ImageFormat.DEPTH_JPEG:
                 assertEquals("JPEG/RAW/depth Images should have one plane", 1, planes.length);
                 break;
             default:
@@ -1363,6 +1364,9 @@
             case ImageFormat.RAW_PRIVATE:
                 validateRawPrivateData(data, width, height, image.getTimestamp(), filePath);
                 break;
+            case ImageFormat.DEPTH_JPEG:
+                validateDepthJpegData(data, width, height, format, image.getTimestamp(), filePath);
+                break;
             default:
                 throw new UnsupportedOperationException("Unsupported format for validation: "
                         + format);
@@ -1528,6 +1532,23 @@
 
     }
 
+    private static void validateDepthJpegData(byte[] depthData, int width, int height, int format,
+            long ts, String filePath) {
+
+        if (VERBOSE) Log.v(TAG, "Validating depth jpeg data");
+
+        // Can't validate size since it is variable
+
+        if (DEBUG && filePath != null) {
+            String fileName =
+                    filePath + "/" + width + "x" + height + "_" + ts / 1e6 + ".jpg";
+            dumpFile(fileName, depthData);
+        }
+
+        return;
+
+    }
+
     public static <T> T getValueNotNull(CaptureResult result, CaptureResult.Key<T> key) {
         if (result == null) {
             throw new IllegalArgumentException("Result must not be null");
diff --git a/packages/CaptivePortalLogin/src/com/android/captiveportallogin/CaptivePortalLoginActivity.java b/packages/CaptivePortalLogin/src/com/android/captiveportallogin/CaptivePortalLoginActivity.java
index 83084c5..7eaf04b 100644
--- a/packages/CaptivePortalLogin/src/com/android/captiveportallogin/CaptivePortalLoginActivity.java
+++ b/packages/CaptivePortalLogin/src/com/android/captiveportallogin/CaptivePortalLoginActivity.java
@@ -17,7 +17,6 @@
 package com.android.captiveportallogin;
 
 import static android.net.ConnectivityManager.EXTRA_CAPTIVE_PORTAL_PROBE_SPEC;
-import static android.net.captiveportal.CaptivePortalProbeSpec.HTTP_LOCATION_HEADER_NAME;
 
 import android.app.Activity;
 import android.app.AlertDialog;
@@ -40,8 +39,6 @@
 import android.net.wifi.WifiInfo;
 import android.os.Build;
 import android.os.Bundle;
-import android.provider.Settings;
-import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
 import android.text.TextUtils;
 import android.util.ArrayMap;
 import android.util.Log;
@@ -61,16 +58,17 @@
 import android.widget.ProgressBar;
 import android.widget.TextView;
 
+import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
+
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 
 import java.io.IOException;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
 import java.net.HttpURLConnection;
 import java.net.MalformedURLException;
 import java.net.URL;
-import java.lang.InterruptedException;
-import java.lang.reflect.Field;
-import java.lang.reflect.Method;
 import java.util.Objects;
 import java.util.Random;
 import java.util.concurrent.atomic.AtomicBoolean;
@@ -81,6 +79,7 @@
     private static final boolean VDBG = false;
 
     private static final int SOCKET_TIMEOUT_MS = 10000;
+    public static final String HTTP_LOCATION_HEADER_NAME = "Location";
 
     private enum Result {
         DISMISSED(MetricsEvent.ACTION_CAPTIVE_PORTAL_LOGIN_RESULT_DISMISSED),
diff --git a/packages/ExtServices/src/android/ext/services/notification/Assistant.java b/packages/ExtServices/src/android/ext/services/notification/Assistant.java
index f346b00..ce58d4e 100644
--- a/packages/ExtServices/src/android/ext/services/notification/Assistant.java
+++ b/packages/ExtServices/src/android/ext/services/notification/Assistant.java
@@ -230,10 +230,10 @@
         Bundle signals = new Bundle();
 
         if (!smartActions.isEmpty()) {
-            signals.putParcelableArrayList(Adjustment.KEY_SMART_ACTIONS, smartActions);
+            signals.putParcelableArrayList(Adjustment.KEY_CONTEXTUAL_ACTIONS, smartActions);
         }
         if (!smartReplies.isEmpty()) {
-            signals.putCharSequenceArrayList(Adjustment.KEY_SMART_REPLIES, smartReplies);
+            signals.putCharSequenceArrayList(Adjustment.KEY_TEXT_REPLIES, smartReplies);
         }
         if (mSettings.mNewInterruptionModel) {
             if (mNotificationCategorizer.shouldSilence(entry)) {
diff --git a/packages/NetworkStack/Android.bp b/packages/NetworkStack/Android.bp
index a2da0a0..9b0d896 100644
--- a/packages/NetworkStack/Android.bp
+++ b/packages/NetworkStack/Android.bp
@@ -21,6 +21,7 @@
     installable: true,
     srcs: [
         "src/**/*.java",
+        ":framework-networkstack-shared-srcs",
         ":services-networkstack-shared-srcs",
     ],
     static_libs: [
diff --git a/packages/NetworkStack/TEST_MAPPING b/packages/NetworkStack/TEST_MAPPING
new file mode 100644
index 0000000..55ba591
--- /dev/null
+++ b/packages/NetworkStack/TEST_MAPPING
@@ -0,0 +1,7 @@
+{
+  "postsubmit": [
+    {
+      "name": "NetworkStackTests"
+    }
+  ]
+}
\ No newline at end of file
diff --git a/packages/NetworkStack/src/android/net/apf/ApfFilter.java b/packages/NetworkStack/src/android/net/apf/ApfFilter.java
index 50c4dfc..08452bb 100644
--- a/packages/NetworkStack/src/android/net/apf/ApfFilter.java
+++ b/packages/NetworkStack/src/android/net/apf/ApfFilter.java
@@ -26,11 +26,6 @@
 import static android.system.OsConstants.IPPROTO_UDP;
 import static android.system.OsConstants.SOCK_RAW;
 
-import static com.android.internal.util.BitUtils.bytesToBEInt;
-import static com.android.internal.util.BitUtils.getUint16;
-import static com.android.internal.util.BitUtils.getUint32;
-import static com.android.internal.util.BitUtils.getUint8;
-import static com.android.internal.util.BitUtils.uint32;
 import static com.android.server.util.NetworkStackConstants.ICMPV6_ECHO_REQUEST_TYPE;
 import static com.android.server.util.NetworkStackConstants.ICMPV6_NEIGHBOR_ADVERTISEMENT;
 import static com.android.server.util.NetworkStackConstants.ICMPV6_ROUTER_ADVERTISEMENT;
@@ -1586,6 +1581,29 @@
     // TODO: move to android.net.NetworkUtils
     @VisibleForTesting
     public static int ipv4BroadcastAddress(byte[] addrBytes, int prefixLength) {
-        return bytesToBEInt(addrBytes) | (int) (uint32(-1) >>> prefixLength);
+        return bytesToBEInt(addrBytes) | (int) (Integer.toUnsignedLong(-1) >>> prefixLength);
+    }
+
+    private static int uint8(byte b) {
+        return b & 0xff;
+    }
+
+    private static int getUint16(ByteBuffer buffer, int position) {
+        return buffer.getShort(position) & 0xffff;
+    }
+
+    private static long getUint32(ByteBuffer buffer, int position) {
+        return Integer.toUnsignedLong(buffer.getInt(position));
+    }
+
+    private static int getUint8(ByteBuffer buffer, int position) {
+        return uint8(buffer.get(position));
+    }
+
+    private static int bytesToBEInt(byte[] bytes) {
+        return (uint8(bytes[0]) << 24)
+                + (uint8(bytes[1]) << 16)
+                + (uint8(bytes[2]) << 8)
+                + (uint8(bytes[3]));
     }
 }
diff --git a/packages/NetworkStack/src/android/net/dhcp/DhcpClient.java b/packages/NetworkStack/src/android/net/dhcp/DhcpClient.java
index 04ac9a3..12eecc0 100644
--- a/packages/NetworkStack/src/android/net/dhcp/DhcpClient.java
+++ b/packages/NetworkStack/src/android/net/dhcp/DhcpClient.java
@@ -40,6 +40,8 @@
 import static android.system.OsConstants.SO_RCVBUF;
 import static android.system.OsConstants.SO_REUSEADDR;
 
+import static com.android.server.util.NetworkStackConstants.IPV4_ADDR_ANY;
+
 import android.content.Context;
 import android.net.DhcpResults;
 import android.net.NetworkUtils;
@@ -328,7 +330,7 @@
             Os.setsockoptInt(mUdpSock, SOL_SOCKET, SO_REUSEADDR, 1);
             Os.setsockoptInt(mUdpSock, SOL_SOCKET, SO_BROADCAST, 1);
             Os.setsockoptInt(mUdpSock, SOL_SOCKET, SO_RCVBUF, 0);
-            Os.bind(mUdpSock, Inet4Address.ANY, DhcpPacket.DHCP_CLIENT);
+            Os.bind(mUdpSock, IPV4_ADDR_ANY, DhcpPacket.DHCP_CLIENT);
         } catch(SocketException|ErrnoException e) {
             Log.e(TAG, "Error creating UDP socket", e);
             return false;
diff --git a/packages/NetworkStack/src/android/net/dhcp/DhcpLeaseRepository.java b/packages/NetworkStack/src/android/net/dhcp/DhcpLeaseRepository.java
index 0d298de..0a15cd7 100644
--- a/packages/NetworkStack/src/android/net/dhcp/DhcpLeaseRepository.java
+++ b/packages/NetworkStack/src/android/net/dhcp/DhcpLeaseRepository.java
@@ -16,12 +16,13 @@
 
 package android.net.dhcp;
 
-import static android.net.NetworkUtils.inet4AddressToIntHTH;
-import static android.net.NetworkUtils.intToInet4AddressHTH;
-import static android.net.NetworkUtils.prefixLengthToV4NetmaskIntHTH;
 import static android.net.dhcp.DhcpLease.EXPIRATION_NEVER;
 import static android.net.dhcp.DhcpLease.inet4AddrToString;
+import static android.net.shared.Inet4AddressUtils.inet4AddressToIntHTH;
+import static android.net.shared.Inet4AddressUtils.intToInet4AddressHTH;
+import static android.net.shared.Inet4AddressUtils.prefixLengthToV4NetmaskIntHTH;
 
+import static com.android.server.util.NetworkStackConstants.IPV4_ADDR_ANY;
 import static com.android.server.util.NetworkStackConstants.IPV4_ADDR_BITS;
 
 import static java.lang.Math.min;
@@ -201,7 +202,7 @@
 
     private static boolean isIpAddrOutsidePrefix(@NonNull IpPrefix prefix,
             @Nullable Inet4Address addr) {
-        return addr != null && !addr.equals(Inet4Address.ANY) && !prefix.contains(addr);
+        return addr != null && !addr.equals(IPV4_ADDR_ANY) && !prefix.contains(addr);
     }
 
     @Nullable
diff --git a/packages/NetworkStack/src/android/net/dhcp/DhcpPacket.java b/packages/NetworkStack/src/android/net/dhcp/DhcpPacket.java
index ce8b7e7..d7ff98b1 100644
--- a/packages/NetworkStack/src/android/net/dhcp/DhcpPacket.java
+++ b/packages/NetworkStack/src/android/net/dhcp/DhcpPacket.java
@@ -1,10 +1,13 @@
 package android.net.dhcp;
 
+import static com.android.server.util.NetworkStackConstants.IPV4_ADDR_ALL;
+import static com.android.server.util.NetworkStackConstants.IPV4_ADDR_ANY;
+
 import android.annotation.Nullable;
 import android.net.DhcpResults;
 import android.net.LinkAddress;
-import android.net.NetworkUtils;
 import android.net.metrics.DhcpErrorEvent;
+import android.net.shared.Inet4AddressUtils;
 import android.os.Build;
 import android.os.SystemProperties;
 import android.system.OsConstants;
@@ -43,8 +46,8 @@
     public static final int MINIMUM_LEASE = 60;
     public static final int INFINITE_LEASE = (int) 0xffffffff;
 
-    public static final Inet4Address INADDR_ANY = (Inet4Address) Inet4Address.ANY;
-    public static final Inet4Address INADDR_BROADCAST = (Inet4Address) Inet4Address.ALL;
+    public static final Inet4Address INADDR_ANY = IPV4_ADDR_ANY;
+    public static final Inet4Address INADDR_BROADCAST = IPV4_ADDR_ALL;
     public static final byte[] ETHER_BROADCAST = new byte[] {
             (byte) 0xff, (byte) 0xff, (byte) 0xff,
             (byte) 0xff, (byte) 0xff, (byte) 0xff,
@@ -1212,9 +1215,9 @@
      */
     public DhcpResults toDhcpResults() {
         Inet4Address ipAddress = mYourIp;
-        if (ipAddress.equals(Inet4Address.ANY)) {
+        if (ipAddress.equals(IPV4_ADDR_ANY)) {
             ipAddress = mClientIp;
-            if (ipAddress.equals(Inet4Address.ANY)) {
+            if (ipAddress.equals(IPV4_ADDR_ANY)) {
                 return null;
             }
         }
@@ -1222,13 +1225,13 @@
         int prefixLength;
         if (mSubnetMask != null) {
             try {
-                prefixLength = NetworkUtils.netmaskToPrefixLength(mSubnetMask);
+                prefixLength = Inet4AddressUtils.netmaskToPrefixLength(mSubnetMask);
             } catch (IllegalArgumentException e) {
                 // Non-contiguous netmask.
                 return null;
             }
         } else {
-            prefixLength = NetworkUtils.getImplicitNetmask(ipAddress);
+            prefixLength = Inet4AddressUtils.getImplicitNetmask(ipAddress);
         }
 
         DhcpResults results = new DhcpResults();
diff --git a/packages/NetworkStack/src/android/net/dhcp/DhcpServer.java b/packages/NetworkStack/src/android/net/dhcp/DhcpServer.java
index 7b112df..beabd3e 100644
--- a/packages/NetworkStack/src/android/net/dhcp/DhcpServer.java
+++ b/packages/NetworkStack/src/android/net/dhcp/DhcpServer.java
@@ -16,8 +16,6 @@
 
 package android.net.dhcp;
 
-import static android.net.NetworkUtils.getBroadcastAddress;
-import static android.net.NetworkUtils.getPrefixMaskAsInet4Address;
 import static android.net.TrafficStats.TAG_SYSTEM_DHCP_SERVER;
 import static android.net.dhcp.DhcpPacket.DHCP_CLIENT;
 import static android.net.dhcp.DhcpPacket.DHCP_HOST_NAME;
@@ -25,6 +23,8 @@
 import static android.net.dhcp.DhcpPacket.ENCAP_BOOTP;
 import static android.net.dhcp.IDhcpServer.STATUS_INVALID_ARGUMENT;
 import static android.net.dhcp.IDhcpServer.STATUS_SUCCESS;
+import static android.net.shared.Inet4AddressUtils.getBroadcastAddress;
+import static android.net.shared.Inet4AddressUtils.getPrefixMaskAsInet4Address;
 import static android.system.OsConstants.AF_INET;
 import static android.system.OsConstants.IPPROTO_UDP;
 import static android.system.OsConstants.SOCK_DGRAM;
@@ -33,6 +33,8 @@
 import static android.system.OsConstants.SO_REUSEADDR;
 
 import static com.android.server.util.NetworkStackConstants.INFINITE_LEASE;
+import static com.android.server.util.NetworkStackConstants.IPV4_ADDR_ALL;
+import static com.android.server.util.NetworkStackConstants.IPV4_ADDR_ANY;
 import static com.android.server.util.PermissionUtil.checkNetworkStackCallingPermission;
 
 import static java.lang.Integer.toUnsignedLong;
@@ -434,7 +436,7 @@
         if (!isEmpty(request.mRelayIp)) {
             return request.mRelayIp;
         } else if (broadcastFlag) {
-            return (Inet4Address) Inet4Address.ALL;
+            return IPV4_ADDR_ALL;
         } else if (!isEmpty(request.mClientIp)) {
             return request.mClientIp;
         } else {
@@ -517,7 +519,7 @@
                 request.mRelayIp, request.mClientMac, true /* broadcast */, message);
 
         final Inet4Address dst = isEmpty(request.mRelayIp)
-                ? (Inet4Address) Inet4Address.ALL
+                ? IPV4_ADDR_ALL
                 : request.mRelayIp;
         return transmitPacket(nakPacket, DhcpNakPacket.class.getSimpleName(), dst);
     }
@@ -598,7 +600,7 @@
     }
 
     private static boolean isEmpty(@Nullable Inet4Address address) {
-        return address == null || Inet4Address.ANY.equals(address);
+        return address == null || IPV4_ADDR_ANY.equals(address);
     }
 
     private class PacketListener extends DhcpPacketListener {
@@ -632,7 +634,7 @@
                 SocketUtils.bindSocketToInterface(mSocket, mIfName);
                 Os.setsockoptInt(mSocket, SOL_SOCKET, SO_REUSEADDR, 1);
                 Os.setsockoptInt(mSocket, SOL_SOCKET, SO_BROADCAST, 1);
-                Os.bind(mSocket, Inet4Address.ANY, DHCP_SERVER);
+                Os.bind(mSocket, IPV4_ADDR_ANY, DHCP_SERVER);
 
                 return mSocket;
             } catch (IOException | ErrnoException e) {
diff --git a/packages/NetworkStack/src/android/net/dhcp/DhcpServingParams.java b/packages/NetworkStack/src/android/net/dhcp/DhcpServingParams.java
index 868f3be..31ce95b 100644
--- a/packages/NetworkStack/src/android/net/dhcp/DhcpServingParams.java
+++ b/packages/NetworkStack/src/android/net/dhcp/DhcpServingParams.java
@@ -16,8 +16,8 @@
 
 package android.net.dhcp;
 
-import static android.net.NetworkUtils.getPrefixMaskAsInet4Address;
-import static android.net.NetworkUtils.intToInet4AddressHTH;
+import static android.net.shared.Inet4AddressUtils.getPrefixMaskAsInet4Address;
+import static android.net.shared.Inet4AddressUtils.intToInet4AddressHTH;
 
 import static com.android.server.util.NetworkStackConstants.INFINITE_LEASE;
 import static com.android.server.util.NetworkStackConstants.IPV4_MAX_MTU;
@@ -29,7 +29,7 @@
 import android.annotation.Nullable;
 import android.net.IpPrefix;
 import android.net.LinkAddress;
-import android.net.NetworkUtils;
+import android.net.shared.Inet4AddressUtils;
 import android.util.ArraySet;
 
 import java.net.Inet4Address;
@@ -164,7 +164,8 @@
      */
     @NonNull
     public Inet4Address getBroadcastAddress() {
-        return NetworkUtils.getBroadcastAddress(getServerInet4Addr(), serverAddr.getPrefixLength());
+        return Inet4AddressUtils.getBroadcastAddress(
+                getServerInet4Addr(), serverAddr.getPrefixLength());
     }
 
     /**
diff --git a/packages/NetworkStack/src/android/net/ip/IpClient.java b/packages/NetworkStack/src/android/net/ip/IpClient.java
index ad7f85d..612ebf7 100644
--- a/packages/NetworkStack/src/android/net/ip/IpClient.java
+++ b/packages/NetworkStack/src/android/net/ip/IpClient.java
@@ -29,7 +29,6 @@
 import android.net.IpPrefix;
 import android.net.LinkAddress;
 import android.net.LinkProperties;
-import android.net.Network;
 import android.net.ProvisioningConfigurationParcelable;
 import android.net.ProxyInfo;
 import android.net.ProxyInfoParcelable;
@@ -41,15 +40,12 @@
 import android.net.metrics.IpConnectivityLog;
 import android.net.metrics.IpManagerEvent;
 import android.net.shared.InitialConfiguration;
-import android.net.shared.NetdService;
 import android.net.shared.ProvisioningConfiguration;
 import android.net.util.InterfaceParams;
 import android.net.util.SharedLog;
 import android.os.ConditionVariable;
-import android.os.INetworkManagementService;
 import android.os.Message;
 import android.os.RemoteException;
-import android.os.ServiceManager;
 import android.os.SystemClock;
 import android.text.TextUtils;
 import android.util.LocalLog;
@@ -65,7 +61,7 @@
 import com.android.internal.util.State;
 import com.android.internal.util.StateMachine;
 import com.android.internal.util.WakeupMessage;
-import com.android.server.net.NetlinkTracker;
+import com.android.server.NetworkObserverRegistry;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
@@ -339,8 +335,9 @@
     private final Dependencies mDependencies;
     private final CountDownLatch mShutdownLatch;
     private final ConnectivityManager mCm;
-    private final INetworkManagementService mNwService;
-    private final NetlinkTracker mNetlinkTracker;
+    private final INetd mNetd;
+    private final NetworkObserverRegistry mObserverRegistry;
+    private final IpClientLinkObserver mLinkObserver;
     private final WakeupMessage mProvisioningTimeoutAlarm;
     private final WakeupMessage mDhcpActionTimeoutAlarm;
     private final SharedLog mLog;
@@ -374,15 +371,6 @@
     private final ConditionVariable mApfDataSnapshotComplete = new ConditionVariable();
 
     public static class Dependencies {
-        public INetworkManagementService getNMS() {
-            return INetworkManagementService.Stub.asInterface(
-                    ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE));
-        }
-
-        public INetd getNetd() {
-            return NetdService.getInstance();
-        }
-
         /**
          * Get interface parameters for the specified interface.
          */
@@ -391,26 +379,14 @@
         }
     }
 
-    public IpClient(Context context, String ifName, IIpClientCallbacks callback) {
-        this(context, ifName, callback, new Dependencies());
-    }
-
-    /**
-     * An expanded constructor, useful for dependency injection.
-     * TODO: migrate all test users to mock IpClient directly and remove this ctor.
-     */
     public IpClient(Context context, String ifName, IIpClientCallbacks callback,
-            INetworkManagementService nwService) {
-        this(context, ifName, callback, new Dependencies() {
-            @Override
-            public INetworkManagementService getNMS() {
-                return nwService;
-            }
-        });
+            NetworkObserverRegistry observerRegistry) {
+        this(context, ifName, callback, observerRegistry, new Dependencies());
     }
 
     @VisibleForTesting
-    IpClient(Context context, String ifName, IIpClientCallbacks callback, Dependencies deps) {
+    IpClient(Context context, String ifName, IIpClientCallbacks callback,
+            NetworkObserverRegistry observerRegistry, Dependencies deps) {
         super(IpClient.class.getSimpleName() + "." + ifName);
         Preconditions.checkNotNull(ifName);
         Preconditions.checkNotNull(callback);
@@ -423,7 +399,7 @@
         mDependencies = deps;
         mShutdownLatch = new CountDownLatch(1);
         mCm = mContext.getSystemService(ConnectivityManager.class);
-        mNwService = deps.getNMS();
+        mObserverRegistry = observerRegistry;
 
         sSmLogs.putIfAbsent(mInterfaceName, new SharedLog(MAX_LOG_RECORDS, mTag));
         mLog = sSmLogs.get(mInterfaceName);
@@ -434,19 +410,15 @@
 
         // TODO: Consider creating, constructing, and passing in some kind of
         // InterfaceController.Dependencies class.
-        mInterfaceCtrl = new InterfaceController(mInterfaceName, deps.getNetd(), mLog);
+        mNetd = mContext.getSystemService(INetd.class);
+        mInterfaceCtrl = new InterfaceController(mInterfaceName, mNetd, mLog);
 
-        mNetlinkTracker = new NetlinkTracker(
+        mLinkObserver = new IpClientLinkObserver(
                 mInterfaceName,
-                new NetlinkTracker.Callback() {
-                    @Override
-                    public void update() {
-                        sendMessage(EVENT_NETLINK_LINKPROPERTIES_CHANGED);
-                    }
-                }) {
+                () -> sendMessage(EVENT_NETLINK_LINKPROPERTIES_CHANGED)) {
             @Override
-            public void interfaceAdded(String iface) {
-                super.interfaceAdded(iface);
+            public void onInterfaceAdded(String iface) {
+                super.onInterfaceAdded(iface);
                 if (mClatInterfaceName.equals(iface)) {
                     mCallback.setNeighborDiscoveryOffload(false);
                 } else if (!mInterfaceName.equals(iface)) {
@@ -458,8 +430,8 @@
             }
 
             @Override
-            public void interfaceRemoved(String iface) {
-                super.interfaceRemoved(iface);
+            public void onInterfaceRemoved(String iface) {
+                super.onInterfaceRemoved(iface);
                 // TODO: Also observe mInterfaceName going down and take some
                 // kind of appropriate action.
                 if (mClatInterfaceName.equals(iface)) {
@@ -571,19 +543,11 @@
     }
 
     private void startStateMachineUpdaters() {
-        try {
-            mNwService.registerObserver(mNetlinkTracker);
-        } catch (RemoteException e) {
-            logError("Couldn't register NetlinkTracker: %s", e);
-        }
+        mObserverRegistry.registerObserver(mLinkObserver, getHandler());
     }
 
     private void stopStateMachineUpdaters() {
-        try {
-            mNwService.unregisterObserver(mNetlinkTracker);
-        } catch (RemoteException e) {
-            logError("Couldn't unregister NetlinkTracker: %s", e);
-        }
+        mObserverRegistry.unregisterObserver(mLinkObserver);
     }
 
     @Override
@@ -806,7 +770,7 @@
     // we should only call this if we know for sure that there are no IP addresses
     // assigned to the interface, etc.
     private void resetLinkProperties() {
-        mNetlinkTracker.clearLinkProperties();
+        mLinkObserver.clearLinkProperties();
         mConfiguration = null;
         mDhcpResults = null;
         mTcpBufferSizes = "";
@@ -985,10 +949,10 @@
         //         - IPv6 DNS servers
         //
         // N.B.: this is fundamentally race-prone and should be fixed by
-        // changing NetlinkTracker from a hybrid edge/level model to an
+        // changing IpClientLinkObserver from a hybrid edge/level model to an
         // edge-only model, or by giving IpClient its own netlink socket(s)
         // so as to track all required information directly.
-        LinkProperties netlinkLinkProperties = mNetlinkTracker.getLinkProperties();
+        LinkProperties netlinkLinkProperties = mLinkObserver.getLinkProperties();
         newLp.setLinkAddresses(netlinkLinkProperties.getLinkAddresses());
         for (RouteInfo route : netlinkLinkProperties.getRoutes()) {
             newLp.addRoute(route);
@@ -1000,7 +964,9 @@
         // mDhcpResults is never shared with any other owner so we don't have
         // to worry about concurrent modification.
         if (mDhcpResults != null) {
-            for (RouteInfo route : mDhcpResults.getRoutes(mInterfaceName)) {
+            final List<RouteInfo> routes =
+                    mDhcpResults.toStaticIpConfiguration().getRoutes(mInterfaceName);
+            for (RouteInfo route : routes) {
                 newLp.addRoute(route);
             }
             addAllReachableDnsServers(newLp, mDhcpResults.dnsServers);
@@ -1165,8 +1131,7 @@
             // necessary or does reading from settings at startup suffice?).
             final int numSolicits = 5;
             final int interSolicitIntervalMs = 750;
-            setNeighborParameters(mDependencies.getNetd(), mInterfaceName,
-                    numSolicits, interSolicitIntervalMs);
+            setNeighborParameters(mNetd, mInterfaceName, numSolicits, interSolicitIntervalMs);
         } catch (Exception e) {
             mLog.e("Failed to adjust neighbor parameters", e);
             // Carry on using the system defaults (currently: 3, 1000);
diff --git a/packages/NetworkStack/src/android/net/ip/IpClientLinkObserver.java b/packages/NetworkStack/src/android/net/ip/IpClientLinkObserver.java
new file mode 100644
index 0000000..8ad99aa0
--- /dev/null
+++ b/packages/NetworkStack/src/android/net/ip/IpClientLinkObserver.java
@@ -0,0 +1,378 @@
+/*
+ * Copyright (C) 2014 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.ip;
+
+import android.net.InetAddresses;
+import android.net.LinkAddress;
+import android.net.LinkProperties;
+import android.net.RouteInfo;
+import android.util.Log;
+
+import com.android.server.NetworkObserver;
+
+import java.net.InetAddress;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * Keeps track of link configuration received from Netd.
+ *
+ * An instance of this class is constructed by passing in an interface name and a callback. The
+ * owner is then responsible for registering the tracker with NetworkObserverRegistry. When the
+ * class receives update notifications, it applies the update to its local LinkProperties, and if
+ * something has changed, notifies its owner of the update via the callback.
+ *
+ * The owner can then call {@code getLinkProperties()} in order to find out
+ * what changed. If in the meantime the LinkProperties stored here have changed,
+ * this class will return the current LinkProperties. Because each change
+ * triggers an update callback after the change is made, the owner may get more
+ * callbacks than strictly necessary (some of which may be no-ops), but will not
+ * be out of sync once all callbacks have been processed.
+ *
+ * Threading model:
+ *
+ * - The owner of this class is expected to create it, register it, and call
+ *   getLinkProperties or clearLinkProperties on its thread.
+ * - Most of the methods in the class are implementing NetworkObserver and are called
+ *   on the handler used to register the observer.
+ * - All accesses to mLinkProperties must be synchronized(this). All the other
+ *   member variables are immutable once the object is constructed.
+ *
+ * @hide
+ */
+public class IpClientLinkObserver implements NetworkObserver {
+    private final String mTag;
+
+    /**
+     * Callback used by {@link IpClientLinkObserver} to send update notifications.
+     */
+    public interface Callback {
+        /**
+         * Called when some properties of the link were updated.
+         */
+        void update();
+    }
+
+    private final String mInterfaceName;
+    private final Callback mCallback;
+    private final LinkProperties mLinkProperties;
+    private DnsServerRepository mDnsServerRepository;
+
+    private static final boolean DBG = false;
+
+    public IpClientLinkObserver(String iface, Callback callback) {
+        mTag = "NetlinkTracker/" + iface;
+        mInterfaceName = iface;
+        mCallback = callback;
+        mLinkProperties = new LinkProperties();
+        mLinkProperties.setInterfaceName(mInterfaceName);
+        mDnsServerRepository = new DnsServerRepository();
+    }
+
+    private void maybeLog(String operation, String iface, LinkAddress address) {
+        if (DBG) {
+            Log.d(mTag, operation + ": " + address + " on " + iface
+                    + " flags " + address.getFlags() + " scope " + address.getScope());
+        }
+    }
+
+    private void maybeLog(String operation, Object o) {
+        if (DBG) {
+            Log.d(mTag, operation + ": " + o.toString());
+        }
+    }
+
+    @Override
+    public void onInterfaceRemoved(String iface) {
+        maybeLog("interfaceRemoved", iface);
+        if (mInterfaceName.equals(iface)) {
+            // Our interface was removed. Clear our LinkProperties and tell our owner that they are
+            // now empty. Note that from the moment that the interface is removed, any further
+            // interface-specific messages (e.g., RTM_DELADDR) will not reach us, because the netd
+            // code that parses them will not be able to resolve the ifindex to an interface name.
+            clearLinkProperties();
+            mCallback.update();
+        }
+    }
+
+    @Override
+    public void onInterfaceAddressUpdated(LinkAddress address, String iface) {
+        if (mInterfaceName.equals(iface)) {
+            maybeLog("addressUpdated", iface, address);
+            boolean changed;
+            synchronized (this) {
+                changed = mLinkProperties.addLinkAddress(address);
+            }
+            if (changed) {
+                mCallback.update();
+            }
+        }
+    }
+
+    @Override
+    public void onInterfaceAddressRemoved(LinkAddress address, String iface) {
+        if (mInterfaceName.equals(iface)) {
+            maybeLog("addressRemoved", iface, address);
+            boolean changed;
+            synchronized (this) {
+                changed = mLinkProperties.removeLinkAddress(address);
+            }
+            if (changed) {
+                mCallback.update();
+            }
+        }
+    }
+
+    @Override
+    public void onRouteUpdated(RouteInfo route) {
+        if (mInterfaceName.equals(route.getInterface())) {
+            maybeLog("routeUpdated", route);
+            boolean changed;
+            synchronized (this) {
+                changed = mLinkProperties.addRoute(route);
+            }
+            if (changed) {
+                mCallback.update();
+            }
+        }
+    }
+
+    @Override
+    public void onRouteRemoved(RouteInfo route) {
+        if (mInterfaceName.equals(route.getInterface())) {
+            maybeLog("routeRemoved", route);
+            boolean changed;
+            synchronized (this) {
+                changed = mLinkProperties.removeRoute(route);
+            }
+            if (changed) {
+                mCallback.update();
+            }
+        }
+    }
+
+    @Override
+    public void onInterfaceDnsServerInfo(String iface, long lifetime, String[] addresses) {
+        if (mInterfaceName.equals(iface)) {
+            maybeLog("interfaceDnsServerInfo", Arrays.toString(addresses));
+            boolean changed = mDnsServerRepository.addServers(lifetime, addresses);
+            if (changed) {
+                synchronized (this) {
+                    mDnsServerRepository.setDnsServersOn(mLinkProperties);
+                }
+                mCallback.update();
+            }
+        }
+    }
+
+    /**
+     * Returns a copy of this object's LinkProperties.
+     */
+    public synchronized LinkProperties getLinkProperties() {
+        return new LinkProperties(mLinkProperties);
+    }
+
+    /**
+     * Reset this object's LinkProperties.
+     */
+    public synchronized void clearLinkProperties() {
+        // Clear the repository before clearing mLinkProperties. That way, if a clear() happens
+        // while interfaceDnsServerInfo() is being called, we'll end up with no DNS servers in
+        // mLinkProperties, as desired.
+        mDnsServerRepository = new DnsServerRepository();
+        mLinkProperties.clear();
+        mLinkProperties.setInterfaceName(mInterfaceName);
+    }
+
+    /**
+     * Tracks DNS server updates received from Netlink.
+     *
+     * The network may announce an arbitrary number of DNS servers in Router Advertisements at any
+     * time. Each announcement has a lifetime; when the lifetime expires, the servers should not be
+     * used any more. In this way, the network can gracefully migrate clients from one set of DNS
+     * servers to another. Announcements can both raise and lower the lifetime, and an announcement
+     * can expire servers by announcing them with a lifetime of zero.
+     *
+     * Typically the system will only use a small number (2 or 3; {@code NUM_CURRENT_SERVERS}) of
+     * DNS servers at any given time. These are referred to as the current servers. In case all the
+     * current servers expire, the class also keeps track of a larger (but limited) number of
+     * servers that are promoted to current servers when the current ones expire. In order to
+     * minimize updates to the rest of the system (and potentially expensive cache flushes) this
+     * class attempts to keep the list of current servers constant where possible. More
+     * specifically, the list of current servers is only updated if a new server is learned and
+     * there are not yet {@code NUM_CURRENT_SERVERS} current servers, or if one or more of the
+     * current servers expires or is pushed out of the set. Therefore, the current servers will not
+     * necessarily be the ones with the highest lifetime, but the ones learned first.
+     *
+     * This is by design: if instead the class always preferred the servers with the highest
+     * lifetime, a (misconfigured?) network where two or more routers announce more than
+     * {@code NUM_CURRENT_SERVERS} unique servers would cause persistent oscillations.
+     *
+     * TODO: Currently servers are only expired when a new DNS update is received.
+     * Update them using timers, or possibly on every notification received by NetlinkTracker.
+     *
+     * Threading model: run by NetlinkTracker. Methods are synchronized(this) just in case netlink
+     * notifications are sent by multiple threads. If future threads use alarms to expire, those
+     * alarms must also be synchronized(this).
+     *
+     */
+    private static class DnsServerRepository {
+
+        /** How many DNS servers we will use. 3 is suggested by RFC 6106. */
+        static final int NUM_CURRENT_SERVERS = 3;
+
+        /** How many DNS servers we'll keep track of, in total. */
+        static final int NUM_SERVERS = 12;
+
+        /** Stores up to {@code NUM_CURRENT_SERVERS} DNS servers we're currently using. */
+        private Set<InetAddress> mCurrentServers;
+
+        public static final String TAG = "DnsServerRepository";
+
+        /**
+         * Stores all the DNS servers we know about, for use when the current servers expire.
+         * Always sorted in order of decreasing expiry. The elements in this list are also the
+         * values of mIndex, and may be elements in mCurrentServers.
+         */
+        private ArrayList<DnsServerEntry> mAllServers;
+
+        /**
+         * Indexes the servers so we can update their lifetimes more quickly in the common case
+         * where servers are not being added, but only being refreshed.
+         */
+        private HashMap<InetAddress, DnsServerEntry> mIndex;
+
+        DnsServerRepository() {
+            mCurrentServers = new HashSet<>();
+            mAllServers = new ArrayList<>(NUM_SERVERS);
+            mIndex = new HashMap<>(NUM_SERVERS);
+        }
+
+        /** Sets the DNS servers of the provided LinkProperties object to the current servers. */
+        public synchronized void setDnsServersOn(LinkProperties lp) {
+            lp.setDnsServers(mCurrentServers);
+        }
+
+        /**
+         * Notifies the class of new DNS server information.
+         * @param lifetime the time in seconds that the DNS servers are valid.
+         * @param addresses the string representations of the IP addresses of DNS servers to use.
+         */
+        public synchronized boolean addServers(long lifetime, String[] addresses) {
+            // The lifetime is actually an unsigned 32-bit number, but Java doesn't have unsigned.
+            // Technically 0xffffffff (the maximum) is special and means "forever", but 2^32 seconds
+            // (136 years) is close enough.
+            long now = System.currentTimeMillis();
+            long expiry = now + 1000 * lifetime;
+
+            // Go through the list of servers. For each one, update the entry if one exists, and
+            // create one if it doesn't.
+            for (String addressString : addresses) {
+                InetAddress address;
+                try {
+                    address = InetAddresses.parseNumericAddress(addressString);
+                } catch (IllegalArgumentException ex) {
+                    continue;
+                }
+
+                if (!updateExistingEntry(address, expiry)) {
+                    // There was no entry for this server. Create one, unless it's already expired
+                    // (i.e., if the lifetime is zero; it cannot be < 0 because it's unsigned).
+                    if (expiry > now) {
+                        DnsServerEntry entry = new DnsServerEntry(address, expiry);
+                        mAllServers.add(entry);
+                        mIndex.put(address, entry);
+                    }
+                }
+            }
+
+            // Sort the servers by expiry.
+            Collections.sort(mAllServers);
+
+            // Prune excess entries and update the current server list.
+            return updateCurrentServers();
+        }
+
+        private synchronized boolean updateExistingEntry(InetAddress address, long expiry) {
+            DnsServerEntry existing = mIndex.get(address);
+            if (existing != null) {
+                existing.expiry = expiry;
+                return true;
+            }
+            return false;
+        }
+
+        private synchronized boolean updateCurrentServers() {
+            long now = System.currentTimeMillis();
+            boolean changed = false;
+
+            // Prune excess or expired entries.
+            for (int i = mAllServers.size() - 1; i >= 0; i--) {
+                if (i >= NUM_SERVERS || mAllServers.get(i).expiry < now) {
+                    DnsServerEntry removed = mAllServers.remove(i);
+                    mIndex.remove(removed.address);
+                    changed |= mCurrentServers.remove(removed.address);
+                } else {
+                    break;
+                }
+            }
+
+            // Add servers to the current set, in order of decreasing lifetime, until it has enough.
+            // Prefer existing servers over new servers in order to minimize updates to the rest of
+            // the system and avoid persistent oscillations.
+            for (DnsServerEntry entry : mAllServers) {
+                if (mCurrentServers.size() < NUM_CURRENT_SERVERS) {
+                    changed |= mCurrentServers.add(entry.address);
+                } else {
+                    break;
+                }
+            }
+            return changed;
+        }
+    }
+
+    /**
+     * Represents a DNS server entry with an expiry time.
+     *
+     * Implements Comparable so DNS server entries can be sorted by lifetime, longest-lived first.
+     * The ordering of entries with the same lifetime is unspecified, because given two servers with
+     * identical lifetimes, we don't care which one we use, and only comparing the lifetime is much
+     * faster than comparing the IP address as well.
+     *
+     * Note: this class has a natural ordering that is inconsistent with equals.
+     */
+    private static class DnsServerEntry implements Comparable<DnsServerEntry> {
+        /** The IP address of the DNS server. */
+        public final InetAddress address;
+        /** The time until which the DNS server may be used. A Java millisecond time as might be
+         * returned by currentTimeMillis(). */
+        public long expiry;
+
+        DnsServerEntry(InetAddress address, long expiry) throws IllegalArgumentException {
+            this.address = address;
+            this.expiry = expiry;
+        }
+
+        public int compareTo(DnsServerEntry other) {
+            return Long.compare(other.expiry, this.expiry);
+        }
+    }
+}
diff --git a/packages/NetworkStack/src/android/net/ip/IpNeighborMonitor.java b/packages/NetworkStack/src/android/net/ip/IpNeighborMonitor.java
index eb993a4..2e6ff24 100644
--- a/packages/NetworkStack/src/android/net/ip/IpNeighborMonitor.java
+++ b/packages/NetworkStack/src/android/net/ip/IpNeighborMonitor.java
@@ -36,8 +36,6 @@
 import android.system.OsConstants;
 import android.util.Log;
 
-import com.android.internal.util.BitUtils;
-
 import libcore.io.IoUtils;
 
 import java.io.FileDescriptor;
@@ -186,7 +184,7 @@
 
             final int srcPortId = nlMsg.getHeader().nlmsg_pid;
             if (srcPortId !=  0) {
-                mLog.e("non-kernel source portId: " + BitUtils.uint32(srcPortId));
+                mLog.e("non-kernel source portId: " + Integer.toUnsignedLong(srcPortId));
                 break;
             }
 
diff --git a/packages/NetworkStack/src/android/net/ip/IpReachabilityMonitor.java b/packages/NetworkStack/src/android/net/ip/IpReachabilityMonitor.java
index 761db68..76a0338 100644
--- a/packages/NetworkStack/src/android/net/ip/IpReachabilityMonitor.java
+++ b/packages/NetworkStack/src/android/net/ip/IpReachabilityMonitor.java
@@ -31,15 +31,15 @@
 import android.net.netlink.StructNdMsg;
 import android.net.util.InterfaceParams;
 import android.net.util.SharedLog;
+import android.os.ConditionVariable;
 import android.os.Handler;
+import android.os.Looper;
 import android.os.PowerManager;
 import android.os.PowerManager.WakeLock;
 import android.os.SystemClock;
 import android.util.Log;
 
 import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.util.DumpUtils;
-import com.android.internal.util.DumpUtils.Dump;
 
 import java.io.PrintWriter;
 import java.net.Inet6Address;
@@ -215,15 +215,20 @@
     }
 
     public void dump(PrintWriter pw) {
-        DumpUtils.dumpAsync(
-                mIpNeighborMonitor.getHandler(),
-                new Dump() {
-                    @Override
-                    public void dump(PrintWriter pw, String prefix) {
-                        pw.println(describeWatchList("\n"));
-                    }
-                },
-                pw, "", 1000);
+        if (Looper.myLooper() == mIpNeighborMonitor.getHandler().getLooper()) {
+            pw.println(describeWatchList("\n"));
+            return;
+        }
+
+        final ConditionVariable cv = new ConditionVariable(false);
+        mIpNeighborMonitor.getHandler().post(() -> {
+            pw.println(describeWatchList("\n"));
+            cv.open();
+        });
+
+        if (!cv.block(1000)) {
+            pw.println("Timed out waiting for IpReachabilityMonitor dump");
+        }
     }
 
     private String describeWatchList() { return describeWatchList(" "); }
diff --git a/packages/NetworkStack/src/android/net/util/NetworkStackUtils.java b/packages/NetworkStack/src/android/net/util/NetworkStackUtils.java
new file mode 100644
index 0000000..6dcf0c0
--- /dev/null
+++ b/packages/NetworkStack/src/android/net/util/NetworkStackUtils.java
@@ -0,0 +1,30 @@
+/*
+ * 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.util;
+
+/**
+ * Collection of utilities for the network stack.
+ */
+public class NetworkStackUtils {
+
+    /**
+     * @return True if the array is null or 0-length.
+     */
+    public static <T> boolean isEmpty(T[] array) {
+        return array == null || array.length == 0;
+    }
+}
diff --git a/packages/NetworkStack/src/com/android/server/NetworkObserver.java b/packages/NetworkStack/src/com/android/server/NetworkObserver.java
new file mode 100644
index 0000000..cccec0b
--- /dev/null
+++ b/packages/NetworkStack/src/com/android/server/NetworkObserver.java
@@ -0,0 +1,88 @@
+/*
+ * 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;
+
+import android.net.LinkAddress;
+import android.net.RouteInfo;
+
+/**
+ * Observer for network events, to use with {@link NetworkObserverRegistry}.
+ */
+public interface NetworkObserver {
+
+    /**
+     * @see android.net.INetdUnsolicitedEventListener#onInterfaceChanged(java.lang.String, boolean)
+     */
+    default void onInterfaceChanged(String ifName, boolean up) {}
+
+    /**
+     * @see android.net.INetdUnsolicitedEventListener#onInterfaceRemoved(String)
+     */
+    default void onInterfaceRemoved(String ifName) {}
+
+    /**
+     * @see android.net.INetdUnsolicitedEventListener
+     *          #onInterfaceAddressUpdated(String, String, int, int)
+     */
+    default void onInterfaceAddressUpdated(LinkAddress address, String ifName) {}
+
+    /**
+     * @see android.net.INetdUnsolicitedEventListener
+     *          #onInterfaceAddressRemoved(String, String, int, int)
+     */
+    default void onInterfaceAddressRemoved(LinkAddress address, String ifName) {}
+
+    /**
+     * @see android.net.INetdUnsolicitedEventListener#onInterfaceLinkStateChanged(String, boolean)
+     */
+    default void onInterfaceLinkStateChanged(String ifName, boolean up) {}
+
+    /**
+     * @see android.net.INetdUnsolicitedEventListener#onInterfaceAdded(String)
+     */
+    default void onInterfaceAdded(String ifName) {}
+
+    /**
+     * @see android.net.INetdUnsolicitedEventListener
+     *          #onInterfaceClassActivityChanged(boolean, int, long, int)
+     */
+    default void onInterfaceClassActivityChanged(
+            boolean isActive, int label, long timestamp, int uid) {}
+
+    /**
+     * @see android.net.INetdUnsolicitedEventListener#onQuotaLimitReached(String, String)
+     */
+    default void onQuotaLimitReached(String alertName, String ifName) {}
+
+    /**
+     * @see android.net.INetdUnsolicitedEventListener
+     *          #onInterfaceDnsServerInfo(String, long, String[])
+     */
+    default void onInterfaceDnsServerInfo(String ifName, long lifetime, String[] servers) {}
+
+    /**
+     * @see android.net.INetdUnsolicitedEventListener
+     *          #onRouteChanged(boolean, String, String, String)
+     */
+    default void onRouteUpdated(RouteInfo route) {}
+
+    /**
+     * @see android.net.INetdUnsolicitedEventListener
+     *          #onRouteChanged(boolean, String, String, String)
+     */
+    default void onRouteRemoved(RouteInfo route) {}
+}
diff --git a/packages/NetworkStack/src/com/android/server/NetworkObserverRegistry.java b/packages/NetworkStack/src/com/android/server/NetworkObserverRegistry.java
new file mode 100644
index 0000000..86e5e14
--- /dev/null
+++ b/packages/NetworkStack/src/com/android/server/NetworkObserverRegistry.java
@@ -0,0 +1,156 @@
+/*
+ * 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;
+
+import android.annotation.NonNull;
+import android.net.INetd;
+import android.net.INetdUnsolicitedEventListener;
+import android.net.InetAddresses;
+import android.net.IpPrefix;
+import android.net.LinkAddress;
+import android.net.RouteInfo;
+import android.os.Handler;
+import android.os.RemoteException;
+
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * A class for reporting network events to clients.
+ *
+ * Implements INetdUnsolicitedEventListener and registers with netd, and relays those events to
+ * all INetworkManagementEventObserver objects that have registered with it.
+ */
+public class NetworkObserverRegistry extends INetdUnsolicitedEventListener.Stub {
+
+    /**
+     * Constructs a new NetworkObserverRegistry.
+     *
+     * <p>Only one registry should be used per process since netd will silently ignore multiple
+     * registrations from the same process.
+     */
+    NetworkObserverRegistry() {}
+
+    /**
+     * Start listening for Netd events.
+     *
+     * <p>This should be called before allowing any observer to be registered.
+     */
+    void register(@NonNull INetd netd) throws RemoteException {
+        netd.registerUnsolicitedEventListener(this);
+    }
+
+    private final ConcurrentHashMap<NetworkObserver, Handler> mObservers =
+            new ConcurrentHashMap<>();
+
+    /**
+     * Registers the specified observer and start sending callbacks to it.
+     * This method may be called on any thread.
+     */
+    public void registerObserver(@NonNull NetworkObserver observer, @NonNull Handler handler) {
+        mObservers.put(observer, handler);
+    }
+
+    /**
+     * Unregisters the specified observer and stop sending callbacks to it.
+     * This method may be called on any thread.
+     */
+    public void unregisterObserver(@NonNull NetworkObserver observer) {
+        mObservers.remove(observer);
+    }
+
+    @FunctionalInterface
+    private interface NetworkObserverEventCallback {
+        void sendCallback(NetworkObserver o);
+    }
+
+    private void invokeForAllObservers(@NonNull final NetworkObserverEventCallback callback) {
+        // ConcurrentHashMap#entrySet is weakly consistent: observers that were in the map before
+        // creation will be processed, those added during traversal may or may not.
+        for (Map.Entry<NetworkObserver, Handler> entry : mObservers.entrySet()) {
+            final NetworkObserver observer = entry.getKey();
+            entry.getValue().post(() -> callback.sendCallback(observer));
+        }
+    }
+
+    @Override
+    public void onInterfaceClassActivityChanged(boolean isActive,
+            int label, long timestamp, int uid) {
+        invokeForAllObservers(o -> o.onInterfaceClassActivityChanged(
+                isActive, label, timestamp, uid));
+    }
+
+    /**
+     * Notify our observers of a limit reached.
+     */
+    @Override
+    public void onQuotaLimitReached(String alertName, String ifName) {
+        invokeForAllObservers(o -> o.onQuotaLimitReached(alertName, ifName));
+    }
+
+    @Override
+    public void onInterfaceDnsServerInfo(String ifName, long lifetime, String[] servers) {
+        invokeForAllObservers(o -> o.onInterfaceDnsServerInfo(ifName, lifetime, servers));
+    }
+
+    @Override
+    public void onInterfaceAddressUpdated(String addr, String ifName, int flags, int scope) {
+        final LinkAddress address = new LinkAddress(addr, flags, scope);
+        invokeForAllObservers(o -> o.onInterfaceAddressUpdated(address, ifName));
+    }
+
+    @Override
+    public void onInterfaceAddressRemoved(String addr,
+            String ifName, int flags, int scope) {
+        final LinkAddress address = new LinkAddress(addr, flags, scope);
+        invokeForAllObservers(o -> o.onInterfaceAddressRemoved(address, ifName));
+    }
+
+    @Override
+    public void onInterfaceAdded(String ifName) {
+        invokeForAllObservers(o -> o.onInterfaceAdded(ifName));
+    }
+
+    @Override
+    public void onInterfaceRemoved(String ifName) {
+        invokeForAllObservers(o -> o.onInterfaceRemoved(ifName));
+    }
+
+    @Override
+    public void onInterfaceChanged(String ifName, boolean up) {
+        invokeForAllObservers(o -> o.onInterfaceChanged(ifName, up));
+    }
+
+    @Override
+    public void onInterfaceLinkStateChanged(String ifName, boolean up) {
+        invokeForAllObservers(o -> o.onInterfaceLinkStateChanged(ifName, up));
+    }
+
+    @Override
+    public void onRouteChanged(boolean updated, String route, String gateway, String ifName) {
+        final RouteInfo processRoute = new RouteInfo(new IpPrefix(route),
+                ("".equals(gateway)) ? null : InetAddresses.parseNumericAddress(gateway),
+                ifName);
+        if (updated) {
+            invokeForAllObservers(o -> o.onRouteUpdated(processRoute));
+        } else {
+            invokeForAllObservers(o -> o.onRouteRemoved(processRoute));
+        }
+    }
+
+    @Override
+    public void onStrictCleartextDetected(int uid, String hex) {}
+}
diff --git a/packages/NetworkStack/src/com/android/server/NetworkStackService.java b/packages/NetworkStack/src/com/android/server/NetworkStackService.java
index 4080ddf..7405c47 100644
--- a/packages/NetworkStack/src/com/android/server/NetworkStackService.java
+++ b/packages/NetworkStack/src/com/android/server/NetworkStackService.java
@@ -29,6 +29,7 @@
 import android.content.Context;
 import android.content.Intent;
 import android.net.ConnectivityManager;
+import android.net.INetd;
 import android.net.INetworkMonitor;
 import android.net.INetworkMonitorCallbacks;
 import android.net.INetworkStackConnector;
@@ -65,6 +66,7 @@
  */
 public class NetworkStackService extends Service {
     private static final String TAG = NetworkStackService.class.getSimpleName();
+    private static NetworkStackConnector sConnector;
 
     /**
      * Create a binder connector for the system server to communicate with the network stack.
@@ -72,8 +74,11 @@
      * <p>On platforms where the network stack runs in the system server process, this method may
      * be called directly instead of obtaining the connector by binding to the service.
      */
-    public static IBinder makeConnector(Context context) {
-        return new NetworkStackConnector(context);
+    public static synchronized IBinder makeConnector(Context context) {
+        if (sConnector == null) {
+            sConnector = new NetworkStackConnector(context);
+        }
+        return sConnector;
     }
 
     @NonNull
@@ -85,6 +90,8 @@
     private static class NetworkStackConnector extends INetworkStackConnector.Stub {
         private static final int NUM_VALIDATION_LOG_LINES = 20;
         private final Context mContext;
+        private final INetd mNetd;
+        private final NetworkObserverRegistry mObserverRegistry;
         private final ConnectivityManager mCm;
         @GuardedBy("mIpClients")
         private final ArrayList<WeakReference<IpClient>> mIpClients = new ArrayList<>();
@@ -106,7 +113,15 @@
 
         NetworkStackConnector(Context context) {
             mContext = context;
+            mNetd = (INetd) context.getSystemService(Context.NETD_SERVICE);
+            mObserverRegistry = new NetworkObserverRegistry();
             mCm = context.getSystemService(ConnectivityManager.class);
+
+            try {
+                mObserverRegistry.register(mNetd);
+            } catch (RemoteException e) {
+                mLog.e("Error registering observer on Netd", e);
+            }
         }
 
         @NonNull
@@ -147,7 +162,7 @@
 
         @Override
         public void makeIpClient(String ifName, IIpClientCallbacks cb) throws RemoteException {
-            final IpClient ipClient = new IpClient(mContext, ifName, cb);
+            final IpClient ipClient = new IpClient(mContext, ifName, cb, mObserverRegistry);
 
             synchronized (mIpClients) {
                 final Iterator<WeakReference<IpClient>> it = mIpClients.iterator();
diff --git a/packages/NetworkStack/src/com/android/server/connectivity/NetworkMonitor.java b/packages/NetworkStack/src/com/android/server/connectivity/NetworkMonitor.java
index 6b31b82..96eaa50 100644
--- a/packages/NetworkStack/src/com/android/server/connectivity/NetworkMonitor.java
+++ b/packages/NetworkStack/src/com/android/server/connectivity/NetworkMonitor.java
@@ -31,6 +31,7 @@
 import static android.net.metrics.ValidationProbeEvent.DNS_SUCCESS;
 import static android.net.metrics.ValidationProbeEvent.PROBE_FALLBACK;
 import static android.net.metrics.ValidationProbeEvent.PROBE_PRIVDNS;
+import static android.net.util.NetworkStackUtils.isEmpty;
 
 import android.annotation.Nullable;
 import android.app.PendingIntent;
@@ -80,7 +81,6 @@
 import android.util.Log;
 
 import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.RingBufferIndices;
 import com.android.internal.util.State;
 import com.android.internal.util.StateMachine;
@@ -93,6 +93,7 @@
 import java.net.UnknownHostException;
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Collection;
 import java.util.Collections;
 import java.util.LinkedHashMap;
 import java.util.List;
@@ -1146,7 +1147,10 @@
                 return null;
             }
 
-            return CaptivePortalProbeSpec.parseCaptivePortalProbeSpecs(settingsValue);
+            final Collection<CaptivePortalProbeSpec> specs =
+                    CaptivePortalProbeSpec.parseCaptivePortalProbeSpecs(settingsValue);
+            final CaptivePortalProbeSpec[] specsArray = new CaptivePortalProbeSpec[specs.size()];
+            return specs.toArray(specsArray);
         } catch (Exception e) {
             // Don't let a misconfiguration bootloop the system.
             Log.e(TAG, "Error parsing configured fallback probe specs", e);
@@ -1169,7 +1173,7 @@
     }
 
     private CaptivePortalProbeSpec nextFallbackSpec() {
-        if (ArrayUtils.isEmpty(mCaptivePortalFallbackSpecs)) {
+        if (isEmpty(mCaptivePortalFallbackSpecs)) {
             return null;
         }
         // Randomly change spec without memory. Also randomize the first attempt.
diff --git a/packages/NetworkStack/src/com/android/server/util/NetworkStackConstants.java b/packages/NetworkStack/src/com/android/server/util/NetworkStackConstants.java
index eedaf30..804765e 100644
--- a/packages/NetworkStack/src/com/android/server/util/NetworkStackConstants.java
+++ b/packages/NetworkStack/src/com/android/server/util/NetworkStackConstants.java
@@ -16,6 +16,10 @@
 
 package com.android.server.util;
 
+import static android.net.shared.Inet4AddressUtils.intToInet4AddressHTH;
+
+import java.net.Inet4Address;
+
 /**
  * Network constants used by the network stack.
  */
@@ -79,6 +83,8 @@
     public static final int IPV4_SRC_ADDR_OFFSET = 12;
     public static final int IPV4_DST_ADDR_OFFSET = 16;
     public static final int IPV4_ADDR_LEN = 4;
+    public static final Inet4Address IPV4_ADDR_ALL = intToInet4AddressHTH(0xffffffff);
+    public static final Inet4Address IPV4_ADDR_ANY = intToInet4AddressHTH(0x0);
 
     /**
      * IPv6 constants.
diff --git a/packages/NetworkStack/tests/src/android/net/dhcp/DhcpLeaseRepositoryTest.java b/packages/NetworkStack/tests/src/android/net/dhcp/DhcpLeaseRepositoryTest.java
index 51d50d9..4abd77e 100644
--- a/packages/NetworkStack/tests/src/android/net/dhcp/DhcpLeaseRepositoryTest.java
+++ b/packages/NetworkStack/tests/src/android/net/dhcp/DhcpLeaseRepositoryTest.java
@@ -21,6 +21,8 @@
 import static android.net.dhcp.DhcpLeaseRepository.CLIENTID_UNSPEC;
 import static android.net.dhcp.DhcpLeaseRepository.INETADDR_UNSPEC;
 
+import static com.android.server.util.NetworkStackConstants.IPV4_ADDR_ANY;
+
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotEquals;
@@ -55,7 +57,6 @@
 @RunWith(AndroidJUnit4.class)
 @SmallTest
 public class DhcpLeaseRepositoryTest {
-    private static final Inet4Address INET4_ANY = (Inet4Address) Inet4Address.ANY;
     private static final Inet4Address TEST_DEF_ROUTER = parseAddr4("192.168.42.247");
     private static final Inet4Address TEST_SERVER_ADDR = parseAddr4("192.168.42.241");
     private static final Inet4Address TEST_RESERVED_ADDR = parseAddr4("192.168.42.243");
@@ -108,7 +109,7 @@
             MacAddress newMac = MacAddress.fromBytes(hwAddrBytes);
             final String hostname = "host_" + i;
             final DhcpLease lease = mRepo.getOffer(CLIENTID_UNSPEC, newMac,
-                    INET4_ANY /* relayAddr */, INETADDR_UNSPEC /* reqAddr */, hostname);
+                    IPV4_ADDR_ANY /* relayAddr */, INETADDR_UNSPEC /* reqAddr */, hostname);
 
             assertNotNull(lease);
             assertEquals(newMac, lease.getHwAddr());
@@ -130,7 +131,7 @@
 
         try {
             mRepo.getOffer(null, TEST_MAC_2,
-                    INET4_ANY /* relayAddr */, INETADDR_UNSPEC /* reqAddr */, HOSTNAME_NONE);
+                    IPV4_ADDR_ANY /* relayAddr */, INETADDR_UNSPEC /* reqAddr */, HOSTNAME_NONE);
             fail("Should be out of addresses");
         } catch (DhcpLeaseRepository.OutOfAddressesException e) {
             // Expected
@@ -181,11 +182,11 @@
     public void testGetOffer_StableAddress() throws Exception {
         for (final MacAddress macAddr : new MacAddress[] { TEST_MAC_1, TEST_MAC_2, TEST_MAC_3 }) {
             final DhcpLease lease = mRepo.getOffer(CLIENTID_UNSPEC, macAddr,
-                    INET4_ANY /* relayAddr */, INETADDR_UNSPEC /* reqAddr */, HOSTNAME_NONE);
+                    IPV4_ADDR_ANY /* relayAddr */, INETADDR_UNSPEC /* reqAddr */, HOSTNAME_NONE);
 
             // Same lease is offered twice
             final DhcpLease newLease = mRepo.getOffer(CLIENTID_UNSPEC, macAddr,
-                    INET4_ANY /* relayAddr */, INETADDR_UNSPEC /* reqAddr */, HOSTNAME_NONE);
+                    IPV4_ADDR_ANY /* relayAddr */, INETADDR_UNSPEC /* reqAddr */, HOSTNAME_NONE);
             assertEquals(lease, newLease);
         }
     }
@@ -196,7 +197,7 @@
         mRepo.updateParams(newPrefix, TEST_EXCL_SET, TEST_LEASE_TIME_MS);
 
         DhcpLease lease = mRepo.getOffer(CLIENTID_UNSPEC, TEST_MAC_1,
-                INET4_ANY /* relayAddr */, INETADDR_UNSPEC /* reqAddr */, HOSTNAME_NONE);
+                IPV4_ADDR_ANY /* relayAddr */, INETADDR_UNSPEC /* reqAddr */, HOSTNAME_NONE);
         assertTrue(newPrefix.contains(lease.getNetAddr()));
     }
 
@@ -205,7 +206,7 @@
         requestLeaseSelecting(TEST_MAC_1, TEST_INETADDR_1, TEST_HOSTNAME_1);
 
         DhcpLease offer = mRepo.getOffer(CLIENTID_UNSPEC, TEST_MAC_1,
-                INET4_ANY /* relayAddr */, INETADDR_UNSPEC /* reqAddr */, HOSTNAME_NONE);
+                IPV4_ADDR_ANY /* relayAddr */, INETADDR_UNSPEC /* reqAddr */, HOSTNAME_NONE);
         assertEquals(TEST_INETADDR_1, offer.getNetAddr());
         assertEquals(TEST_HOSTNAME_1, offer.getHostname());
     }
@@ -213,12 +214,13 @@
     @Test
     public void testGetOffer_ClientIdHasExistingLease() throws Exception {
         final byte[] clientId = new byte[] { 1, 2 };
-        mRepo.requestLease(clientId, TEST_MAC_1, INET4_ANY /* clientAddr */,
-                INET4_ANY /* relayAddr */, TEST_INETADDR_1 /* reqAddr */, false, TEST_HOSTNAME_1);
+        mRepo.requestLease(clientId, TEST_MAC_1, IPV4_ADDR_ANY /* clientAddr */,
+                IPV4_ADDR_ANY /* relayAddr */, TEST_INETADDR_1 /* reqAddr */, false,
+                TEST_HOSTNAME_1);
 
         // Different MAC, but same clientId
         DhcpLease offer = mRepo.getOffer(clientId, TEST_MAC_2,
-                INET4_ANY /* relayAddr */, INETADDR_UNSPEC /* reqAddr */, HOSTNAME_NONE);
+                IPV4_ADDR_ANY /* relayAddr */, INETADDR_UNSPEC /* reqAddr */, HOSTNAME_NONE);
         assertEquals(TEST_INETADDR_1, offer.getNetAddr());
         assertEquals(TEST_HOSTNAME_1, offer.getHostname());
     }
@@ -227,12 +229,13 @@
     public void testGetOffer_DifferentClientId() throws Exception {
         final byte[] clientId1 = new byte[] { 1, 2 };
         final byte[] clientId2 = new byte[] { 3, 4 };
-        mRepo.requestLease(clientId1, TEST_MAC_1, INET4_ANY /* clientAddr */,
-                INET4_ANY /* relayAddr */, TEST_INETADDR_1 /* reqAddr */, false, TEST_HOSTNAME_1);
+        mRepo.requestLease(clientId1, TEST_MAC_1, IPV4_ADDR_ANY /* clientAddr */,
+                IPV4_ADDR_ANY /* relayAddr */, TEST_INETADDR_1 /* reqAddr */, false,
+                TEST_HOSTNAME_1);
 
         // Same MAC, different client ID
         DhcpLease offer = mRepo.getOffer(clientId2, TEST_MAC_1,
-                INET4_ANY /* relayAddr */, INETADDR_UNSPEC /* reqAddr */, HOSTNAME_NONE);
+                IPV4_ADDR_ANY /* relayAddr */, INETADDR_UNSPEC /* reqAddr */, HOSTNAME_NONE);
         // Obtains a different address
         assertNotEquals(TEST_INETADDR_1, offer.getNetAddr());
         assertEquals(HOSTNAME_NONE, offer.getHostname());
@@ -241,7 +244,7 @@
 
     @Test
     public void testGetOffer_RequestedAddress() throws Exception {
-        DhcpLease offer = mRepo.getOffer(CLIENTID_UNSPEC, TEST_MAC_1, INET4_ANY /* relayAddr */,
+        DhcpLease offer = mRepo.getOffer(CLIENTID_UNSPEC, TEST_MAC_1, IPV4_ADDR_ANY /* relayAddr */,
                 TEST_INETADDR_1 /* reqAddr */, TEST_HOSTNAME_1);
         assertEquals(TEST_INETADDR_1, offer.getNetAddr());
         assertEquals(TEST_HOSTNAME_1, offer.getHostname());
@@ -250,14 +253,14 @@
     @Test
     public void testGetOffer_RequestedAddressInUse() throws Exception {
         requestLeaseSelecting(TEST_MAC_1, TEST_INETADDR_1);
-        DhcpLease offer = mRepo.getOffer(CLIENTID_UNSPEC, TEST_MAC_2, INET4_ANY /* relayAddr */,
+        DhcpLease offer = mRepo.getOffer(CLIENTID_UNSPEC, TEST_MAC_2, IPV4_ADDR_ANY /* relayAddr */,
                 TEST_INETADDR_1 /* reqAddr */, HOSTNAME_NONE);
         assertNotEquals(TEST_INETADDR_1, offer.getNetAddr());
     }
 
     @Test
     public void testGetOffer_RequestedAddressReserved() throws Exception {
-        DhcpLease offer = mRepo.getOffer(CLIENTID_UNSPEC, TEST_MAC_1, INET4_ANY /* relayAddr */,
+        DhcpLease offer = mRepo.getOffer(CLIENTID_UNSPEC, TEST_MAC_1, IPV4_ADDR_ANY /* relayAddr */,
                 TEST_RESERVED_ADDR /* reqAddr */, HOSTNAME_NONE);
         assertNotEquals(TEST_RESERVED_ADDR, offer.getNetAddr());
     }
@@ -265,7 +268,7 @@
     @Test
     public void testGetOffer_RequestedAddressInvalid() throws Exception {
         final Inet4Address invalidAddr = parseAddr4("192.168.42.0");
-        DhcpLease offer = mRepo.getOffer(CLIENTID_UNSPEC, TEST_MAC_1, INET4_ANY /* relayAddr */,
+        DhcpLease offer = mRepo.getOffer(CLIENTID_UNSPEC, TEST_MAC_1, IPV4_ADDR_ANY /* relayAddr */,
                 invalidAddr /* reqAddr */, HOSTNAME_NONE);
         assertNotEquals(invalidAddr, offer.getNetAddr());
     }
@@ -273,7 +276,7 @@
     @Test
     public void testGetOffer_RequestedAddressOutsideSubnet() throws Exception {
         final Inet4Address invalidAddr = parseAddr4("192.168.254.2");
-        DhcpLease offer = mRepo.getOffer(CLIENTID_UNSPEC, TEST_MAC_1, INET4_ANY /* relayAddr */,
+        DhcpLease offer = mRepo.getOffer(CLIENTID_UNSPEC, TEST_MAC_1, IPV4_ADDR_ANY /* relayAddr */,
                 invalidAddr /* reqAddr */, HOSTNAME_NONE);
         assertNotEquals(invalidAddr, offer.getNetAddr());
     }
@@ -322,7 +325,7 @@
 
     @Test(expected = DhcpLeaseRepository.InvalidSubnetException.class)
     public void testRequestLease_SelectingRelayInInvalidSubnet() throws  Exception {
-        mRepo.requestLease(CLIENTID_UNSPEC, TEST_MAC_1, INET4_ANY /* clientAddr */,
+        mRepo.requestLease(CLIENTID_UNSPEC, TEST_MAC_1, IPV4_ADDR_ANY /* clientAddr */,
                 parseAddr4("192.168.128.1") /* relayAddr */, TEST_INETADDR_1 /* reqAddr */,
                 true /* sidSet */, HOSTNAME_NONE);
     }
@@ -419,14 +422,14 @@
     public void testReleaseLease_StableOffer() throws Exception {
         for (MacAddress mac : new MacAddress[] { TEST_MAC_1, TEST_MAC_2, TEST_MAC_3 }) {
             final DhcpLease lease = mRepo.getOffer(CLIENTID_UNSPEC, mac,
-                    INET4_ANY /* relayAddr */, INETADDR_UNSPEC /* reqAddr */, HOSTNAME_NONE);
+                    IPV4_ADDR_ANY /* relayAddr */, INETADDR_UNSPEC /* reqAddr */, HOSTNAME_NONE);
 
             requestLeaseSelecting(mac, lease.getNetAddr());
             mRepo.releaseLease(CLIENTID_UNSPEC, mac, lease.getNetAddr());
 
             // Same lease is offered after it was released
             final DhcpLease newLease = mRepo.getOffer(CLIENTID_UNSPEC, mac,
-                    INET4_ANY /* relayAddr */, INETADDR_UNSPEC /* reqAddr */, HOSTNAME_NONE);
+                    IPV4_ADDR_ANY /* relayAddr */, INETADDR_UNSPEC /* reqAddr */, HOSTNAME_NONE);
             assertEquals(lease.getNetAddr(), newLease.getNetAddr());
         }
     }
@@ -434,13 +437,13 @@
     @Test
     public void testMarkLeaseDeclined() throws Exception {
         final DhcpLease lease = mRepo.getOffer(CLIENTID_UNSPEC, TEST_MAC_1,
-                INET4_ANY /* relayAddr */, INETADDR_UNSPEC /* reqAddr */, HOSTNAME_NONE);
+                IPV4_ADDR_ANY /* relayAddr */, INETADDR_UNSPEC /* reqAddr */, HOSTNAME_NONE);
 
         mRepo.markLeaseDeclined(lease.getNetAddr());
 
         // Same lease is not offered again
         final DhcpLease newLease = mRepo.getOffer(CLIENTID_UNSPEC, TEST_MAC_1,
-                INET4_ANY /* relayAddr */, INETADDR_UNSPEC /* reqAddr */, HOSTNAME_NONE);
+                IPV4_ADDR_ANY /* relayAddr */, INETADDR_UNSPEC /* reqAddr */, HOSTNAME_NONE);
         assertNotEquals(lease.getNetAddr(), newLease.getNetAddr());
     }
 
@@ -457,16 +460,16 @@
 
         // Last 2 addresses: addresses marked declined should be used
         final DhcpLease firstLease = mRepo.getOffer(CLIENTID_UNSPEC, TEST_MAC_1,
-                INET4_ANY /* relayAddr */, INETADDR_UNSPEC /* reqAddr */, TEST_HOSTNAME_1);
+                IPV4_ADDR_ANY /* relayAddr */, INETADDR_UNSPEC /* reqAddr */, TEST_HOSTNAME_1);
         requestLeaseSelecting(TEST_MAC_1, firstLease.getNetAddr());
 
         final DhcpLease secondLease = mRepo.getOffer(CLIENTID_UNSPEC, TEST_MAC_2,
-                INET4_ANY /* relayAddr */, INETADDR_UNSPEC /* reqAddr */, TEST_HOSTNAME_2);
+                IPV4_ADDR_ANY /* relayAddr */, INETADDR_UNSPEC /* reqAddr */, TEST_HOSTNAME_2);
         requestLeaseSelecting(TEST_MAC_2, secondLease.getNetAddr());
 
         // Now out of addresses
         try {
-            mRepo.getOffer(CLIENTID_UNSPEC, TEST_MAC_3, INET4_ANY /* relayAddr */,
+            mRepo.getOffer(CLIENTID_UNSPEC, TEST_MAC_3, IPV4_ADDR_ANY /* relayAddr */,
                     INETADDR_UNSPEC /* reqAddr */, HOSTNAME_NONE);
             fail("Repository should be out of addresses and throw");
         } catch (DhcpLeaseRepository.OutOfAddressesException e) { /* expected */ }
@@ -480,7 +483,8 @@
     private DhcpLease requestLease(@NonNull MacAddress macAddr, @NonNull Inet4Address clientAddr,
             @Nullable Inet4Address reqAddr, @Nullable String hostname, boolean sidSet)
             throws DhcpLeaseRepository.DhcpLeaseException {
-        return mRepo.requestLease(CLIENTID_UNSPEC, macAddr, clientAddr, INET4_ANY /* relayAddr */,
+        return mRepo.requestLease(CLIENTID_UNSPEC, macAddr, clientAddr,
+                IPV4_ADDR_ANY /* relayAddr */,
                 reqAddr, sidSet, hostname);
     }
 
@@ -490,7 +494,7 @@
     private DhcpLease requestLeaseSelecting(@NonNull MacAddress macAddr,
             @NonNull Inet4Address reqAddr, @Nullable String hostname)
             throws DhcpLeaseRepository.DhcpLeaseException {
-        return requestLease(macAddr, INET4_ANY /* clientAddr */, reqAddr, hostname,
+        return requestLease(macAddr, IPV4_ADDR_ANY /* clientAddr */, reqAddr, hostname,
                 true /* sidSet */);
     }
 
@@ -507,7 +511,7 @@
      */
     private DhcpLease requestLeaseInitReboot(@NonNull MacAddress macAddr,
             @NonNull Inet4Address reqAddr) throws DhcpLeaseRepository.DhcpLeaseException {
-        return requestLease(macAddr, INET4_ANY /* clientAddr */, reqAddr, HOSTNAME_NONE,
+        return requestLease(macAddr, IPV4_ADDR_ANY /* clientAddr */, reqAddr, HOSTNAME_NONE,
                 false /* sidSet */);
     }
 
diff --git a/packages/NetworkStack/tests/src/android/net/dhcp/DhcpPacketTest.java b/packages/NetworkStack/tests/src/android/net/dhcp/DhcpPacketTest.java
index a592809..7544e72 100644
--- a/packages/NetworkStack/tests/src/android/net/dhcp/DhcpPacketTest.java
+++ b/packages/NetworkStack/tests/src/android/net/dhcp/DhcpPacketTest.java
@@ -16,9 +16,27 @@
 
 package android.net.dhcp;
 
-import static android.net.NetworkUtils.getBroadcastAddress;
-import static android.net.NetworkUtils.getPrefixMaskAsInet4Address;
-import static android.net.dhcp.DhcpPacket.*;
+import static android.net.dhcp.DhcpPacket.DHCP_BROADCAST_ADDRESS;
+import static android.net.dhcp.DhcpPacket.DHCP_DNS_SERVER;
+import static android.net.dhcp.DhcpPacket.DHCP_DOMAIN_NAME;
+import static android.net.dhcp.DhcpPacket.DHCP_LEASE_TIME;
+import static android.net.dhcp.DhcpPacket.DHCP_MESSAGE_TYPE_ACK;
+import static android.net.dhcp.DhcpPacket.DHCP_MESSAGE_TYPE_OFFER;
+import static android.net.dhcp.DhcpPacket.DHCP_MTU;
+import static android.net.dhcp.DhcpPacket.DHCP_REBINDING_TIME;
+import static android.net.dhcp.DhcpPacket.DHCP_RENEWAL_TIME;
+import static android.net.dhcp.DhcpPacket.DHCP_ROUTER;
+import static android.net.dhcp.DhcpPacket.DHCP_SUBNET_MASK;
+import static android.net.dhcp.DhcpPacket.DHCP_VENDOR_INFO;
+import static android.net.dhcp.DhcpPacket.ENCAP_BOOTP;
+import static android.net.dhcp.DhcpPacket.ENCAP_L2;
+import static android.net.dhcp.DhcpPacket.ENCAP_L3;
+import static android.net.dhcp.DhcpPacket.INADDR_ANY;
+import static android.net.dhcp.DhcpPacket.INFINITE_LEASE;
+import static android.net.dhcp.DhcpPacket.ParseException;
+import static android.net.shared.Inet4AddressUtils.getBroadcastAddress;
+import static android.net.shared.Inet4AddressUtils.getPrefixMaskAsInet4Address;
+
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
@@ -30,11 +48,15 @@
 import android.net.LinkAddress;
 import android.net.NetworkUtils;
 import android.net.metrics.DhcpErrorEvent;
-import android.support.test.runner.AndroidJUnit4;
 import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 
 import com.android.internal.util.HexDump;
 
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
 import java.io.ByteArrayOutputStream;
 import java.net.Inet4Address;
 import java.nio.ByteBuffer;
@@ -44,10 +66,6 @@
 import java.util.Collections;
 import java.util.Random;
 
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
 @RunWith(AndroidJUnit4.class)
 @SmallTest
 public class DhcpPacketTest {
@@ -60,9 +78,9 @@
             SERVER_ADDR, PREFIX_LENGTH);
     private static final String HOSTNAME = "testhostname";
     private static final short MTU = 1500;
-    // Use our own empty address instead of Inet4Address.ANY or INADDR_ANY to ensure that the code
+    // Use our own empty address instead of IPV4_ADDR_ANY or INADDR_ANY to ensure that the code
     // doesn't use == instead of equals when comparing addresses.
-    private static final Inet4Address ANY = (Inet4Address) v4Address("0.0.0.0");
+    private static final Inet4Address ANY = v4Address("0.0.0.0");
 
     private static final byte[] CLIENT_MAC = new byte[] { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05 };
 
diff --git a/packages/NetworkStack/tests/src/android/net/dhcp/DhcpServingParamsTest.java b/packages/NetworkStack/tests/src/android/net/dhcp/DhcpServingParamsTest.java
index 3ca0564..1004382 100644
--- a/packages/NetworkStack/tests/src/android/net/dhcp/DhcpServingParamsTest.java
+++ b/packages/NetworkStack/tests/src/android/net/dhcp/DhcpServingParamsTest.java
@@ -17,8 +17,8 @@
 package android.net.dhcp;
 
 import static android.net.InetAddresses.parseNumericAddress;
-import static android.net.NetworkUtils.inet4AddressToIntHTH;
 import static android.net.dhcp.DhcpServingParams.MTU_UNSET;
+import static android.net.shared.Inet4AddressUtils.inet4AddressToIntHTH;
 
 import static junit.framework.Assert.assertEquals;
 import static junit.framework.Assert.assertFalse;
@@ -27,8 +27,8 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.net.LinkAddress;
-import android.net.NetworkUtils;
 import android.net.dhcp.DhcpServingParams.InvalidParameterException;
+import android.net.shared.Inet4AddressUtils;
 import android.support.test.filters.SmallTest;
 import android.support.test.runner.AndroidJUnit4;
 
@@ -200,7 +200,7 @@
     }
 
     private static int[] toIntArray(Collection<Inet4Address> addrs) {
-        return addrs.stream().mapToInt(NetworkUtils::inet4AddressToIntHTH).toArray();
+        return addrs.stream().mapToInt(Inet4AddressUtils::inet4AddressToIntHTH).toArray();
     }
 
     private static <T> void assertContains(@NonNull Set<T> set, @NonNull Set<T> subset) {
diff --git a/packages/NetworkStack/tests/src/android/net/ip/IpClientTest.java b/packages/NetworkStack/tests/src/android/net/ip/IpClientTest.java
index 4ae044de..40d510a 100644
--- a/packages/NetworkStack/tests/src/android/net/ip/IpClientTest.java
+++ b/packages/NetworkStack/tests/src/android/net/ip/IpClientTest.java
@@ -46,7 +46,6 @@
 import android.net.shared.InitialConfiguration;
 import android.net.shared.ProvisioningConfiguration;
 import android.net.util.InterfaceParams;
-import android.os.INetworkManagementService;
 import android.provider.Settings;
 import android.support.test.filters.SmallTest;
 import android.support.test.runner.AndroidJUnit4;
@@ -54,7 +53,8 @@
 
 import com.android.internal.R;
 import com.android.internal.util.test.FakeSettingsProvider;
-import com.android.server.net.BaseNetworkObserver;
+import com.android.server.NetworkObserver;
+import com.android.server.NetworkObserverRegistry;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -87,15 +87,15 @@
 
     @Mock private Context mContext;
     @Mock private ConnectivityManager mCm;
-    @Mock private INetworkManagementService mNMService;
+    @Mock private NetworkObserverRegistry mObserverRegistry;
     @Mock private INetd mNetd;
     @Mock private Resources mResources;
     @Mock private IIpClientCallbacks mCb;
     @Mock private AlarmManager mAlarm;
-    @Mock private IpClient.Dependencies mDependecies;
+    @Mock private IpClient.Dependencies mDependencies;
     private MockContentResolver mContentResolver;
 
-    private BaseNetworkObserver mObserver;
+    private NetworkObserver mObserver;
     private InterfaceParams mIfParams;
 
     @Before
@@ -104,6 +104,7 @@
 
         when(mContext.getSystemService(eq(Context.ALARM_SERVICE))).thenReturn(mAlarm);
         when(mContext.getSystemService(eq(ConnectivityManager.class))).thenReturn(mCm);
+        when(mContext.getSystemService(INetd.class)).thenReturn(mNetd);
         when(mContext.getResources()).thenReturn(mResources);
         when(mResources.getInteger(R.integer.config_networkAvoidBadWifi))
                 .thenReturn(DEFAULT_AVOIDBADWIFI_CONFIG_VALUE);
@@ -113,28 +114,24 @@
         when(mContext.getContentResolver()).thenReturn(mContentResolver);
 
         mIfParams = null;
-
-        when(mDependecies.getNMS()).thenReturn(mNMService);
-        when(mDependecies.getNetd()).thenReturn(mNetd);
     }
 
     private void setTestInterfaceParams(String ifname) {
         mIfParams = (ifname != null)
                 ? new InterfaceParams(ifname, TEST_IFINDEX, TEST_MAC)
                 : null;
-        when(mDependecies.getInterfaceParams(anyString())).thenReturn(mIfParams);
+        when(mDependencies.getInterfaceParams(anyString())).thenReturn(mIfParams);
     }
 
     private IpClient makeIpClient(String ifname) throws Exception {
         setTestInterfaceParams(ifname);
-        final IpClient ipc = new IpClient(mContext, ifname, mCb, mDependecies);
+        final IpClient ipc = new IpClient(mContext, ifname, mCb, mObserverRegistry, mDependencies);
         verify(mNetd, timeout(TEST_TIMEOUT_MS).times(1)).interfaceSetEnableIPv6(ifname, false);
         verify(mNetd, timeout(TEST_TIMEOUT_MS).times(1)).interfaceClearAddrs(ifname);
-        ArgumentCaptor<BaseNetworkObserver> arg =
-                ArgumentCaptor.forClass(BaseNetworkObserver.class);
-        verify(mNMService, times(1)).registerObserver(arg.capture());
+        ArgumentCaptor<NetworkObserver> arg = ArgumentCaptor.forClass(NetworkObserver.class);
+        verify(mObserverRegistry, times(1)).registerObserver(arg.capture(), any());
         mObserver = arg.getValue();
-        reset(mNMService);
+        reset(mObserverRegistry);
         reset(mNetd);
         // Verify IpClient doesn't call onLinkPropertiesChange() when it starts.
         verify(mCb, never()).onLinkPropertiesChange(any());
@@ -152,7 +149,8 @@
     public void testNullInterfaceNameMostDefinitelyThrows() throws Exception {
         setTestInterfaceParams(null);
         try {
-            final IpClient ipc = new IpClient(mContext, null, mCb, mDependecies);
+            final IpClient ipc = new IpClient(
+                    mContext, null, mCb, mObserverRegistry, mDependencies);
             ipc.shutdown();
             fail();
         } catch (NullPointerException npe) {
@@ -165,7 +163,8 @@
         final String ifname = "lo";
         setTestInterfaceParams(ifname);
         try {
-            final IpClient ipc = new IpClient(mContext, ifname, null, mDependecies);
+            final IpClient ipc = new IpClient(
+                    mContext, ifname, null, mObserverRegistry, mDependencies);
             ipc.shutdown();
             fail();
         } catch (NullPointerException npe) {
@@ -176,14 +175,16 @@
     @Test
     public void testInvalidInterfaceDoesNotThrow() throws Exception {
         setTestInterfaceParams(TEST_IFNAME);
-        final IpClient ipc = new IpClient(mContext, TEST_IFNAME, mCb, mDependecies);
+        final IpClient ipc = new IpClient(
+                mContext, TEST_IFNAME, mCb, mObserverRegistry, mDependencies);
         ipc.shutdown();
     }
 
     @Test
     public void testInterfaceNotFoundFailsImmediately() throws Exception {
         setTestInterfaceParams(null);
-        final IpClient ipc = new IpClient(mContext, TEST_IFNAME, mCb, mDependecies);
+        final IpClient ipc = new IpClient(
+                mContext, TEST_IFNAME, mCb, mObserverRegistry, mDependencies);
         ipc.startProvisioning(new ProvisioningConfiguration());
         verify(mCb, times(1)).onProvisioningFailure(any());
         ipc.shutdown();
@@ -247,13 +248,13 @@
 
         // Add N - 1 addresses
         for (int i = 0; i < lastAddr; i++) {
-            mObserver.addressUpdated(iface, new LinkAddress(addresses[i]));
+            mObserver.onInterfaceAddressUpdated(new LinkAddress(addresses[i]), iface);
             verify(mCb, timeout(TEST_TIMEOUT_MS)).onLinkPropertiesChange(any());
             reset(mCb);
         }
 
         // Add Nth address
-        mObserver.addressUpdated(iface, new LinkAddress(addresses[lastAddr]));
+        mObserver.onInterfaceAddressUpdated(new LinkAddress(addresses[lastAddr]), iface);
         LinkProperties want = linkproperties(links(addresses), routes(prefixes));
         want.setInterfaceName(iface);
         verify(mCb, timeout(TEST_TIMEOUT_MS).times(1)).onProvisioningSuccess(argThat(
diff --git a/packages/PrintSpooler/src/com/android/printspooler/widget/PrintContentView.java b/packages/PrintSpooler/src/com/android/printspooler/widget/PrintContentView.java
index 8b00ed0..00b3736 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/widget/PrintContentView.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/widget/PrintContentView.java
@@ -23,6 +23,7 @@
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.inputmethod.InputMethodManager;
+
 import com.android.printspooler.R;
 
 /**
@@ -366,7 +367,8 @@
             // and is janky. Now it is there but transparent, doing nothing.
             mEmbeddedContentScrim.setOnClickListener(null);
             mEmbeddedContentScrim.setClickable(false);
-            mExpandCollapseIcon.setBackgroundResource(R.drawable.ic_expand_more);
+            mExpandCollapseIcon.setBackgroundResource(
+                    com.android.internal.R.drawable.ic_expand_more);
         } else {
             if (mMoreOptionsButton.getVisibility() != View.GONE) {
                 mMoreOptionsButton.setVisibility(View.VISIBLE);
diff --git a/packages/SettingsLib/res/drawable/ic_info_outline_24dp.xml b/packages/SettingsLib/res/drawable/ic_info_outline_24dp.xml
deleted file mode 100644
index 46b8309..0000000
--- a/packages/SettingsLib/res/drawable/ic_info_outline_24dp.xml
+++ /dev/null
@@ -1,32 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-     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.
--->
-<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/textColorSecondary">
-    <path
-        android:fillColor="#FF000000"
-        android:pathData="M11,7h2v2h-2z"/>
-    <path
-        android:fillColor="#FF000000"
-        android:pathData="M11,11h2v6h-2z"/>
-    <path
-        android:fillColor="#FF000000"
-        android:pathData="M12,2C6.48,2 2,6.48 2,12c0,5.52 4.48,10 10,10s10,-4.48 10,-10C22,6.48 17.52,2 12,2zM12,20c-4.41,0 -8,-3.59 -8,-8c0,-4.41 3.59,-8 8,-8s8,3.59 8,8C20,16.41 16.41,20 12,20z"/>
-</vector>
diff --git a/packages/SettingsLib/res/drawable/ic_landscape_from_auto_rotate.xml b/packages/SettingsLib/res/drawable/ic_landscape_from_auto_rotate.xml
deleted file mode 100644
index 44b1866..0000000
--- a/packages/SettingsLib/res/drawable/ic_landscape_from_auto_rotate.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-     Copyright (C) 2017 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<vector
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:name="ic_rotate_to_landscape"
-    android:width="24dp"
-    android:height="24dp"
-    android:viewportHeight="24.0"
-    android:viewportWidth="24.0"
-    android:tint="?android:attr/colorControlNormal" >
-    <path
-        android:fillColor="#FF000000"
-        android:pathData="M12.72,23H11C5.49,23 1,18.51 1,13h2c0,3.78 2.63,6.95 6.15,7.79L8.13,19L9.87,18L12.72,23zM13,1h-1.72l2.85,5L15.87,5l-1.02,-1.79C18.37,4.05 21,7.22 21,11h2C23,5.49 18.51,1 13,1zM10.23,6L18,13.76L13.77,18L6,10.24L10.23,6C10.23,6 10.23,6 10.23,6M10.23,4C9.72,4 9.21,4.2 8.82,4.59L4.59,8.82c-0.78,0.78 -0.78,2.04 0,2.82l7.77,7.77c0.39,0.39 0.9,0.59 1.41,0.59c0.51,0 1.02,-0.2 1.41,-0.59l4.24,-4.24c0.78,-0.78 0.78,-2.04 0,-2.82l-7.77,-7.77C11.26,4.2 10.75,4 10.23,4L10.23,4z"/>
-</vector>
diff --git a/packages/SettingsLib/res/drawable/notification_auto_importance.xml b/packages/SettingsLib/res/drawable/notification_auto_importance.xml
deleted file mode 100644
index c946153..0000000
--- a/packages/SettingsLib/res/drawable/notification_auto_importance.xml
+++ /dev/null
@@ -1,27 +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.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="24dp"
-        android:height="24dp"
-        android:viewportWidth="24.0"
-        android:viewportHeight="24.0">
-    <path
-            android:fillColor="#FFFFFFFF"
-            android:pathData="M10.8,12.7l2.4,0l-1.2,-3.7z"/>
-    <path
-            android:fillColor="#FF000000"
-            android:pathData="M12,2C6.5,2 2,6.5 2,12s4.5,10 10,10s10,-4.5 10,-10S17.5,2 12,2zM14.3,16l-0.7,-2h-3.2l-0.7,2H7.8L11,7h2l3.2,9H14.3z"/>
-</vector>
\ No newline at end of file
diff --git a/packages/SettingsLib/res/layout/zen_mode_condition.xml b/packages/SettingsLib/res/layout/zen_mode_condition.xml
index c85a892..3222174 100644
--- a/packages/SettingsLib/res/layout/zen_mode_condition.xml
+++ b/packages/SettingsLib/res/layout/zen_mode_condition.xml
@@ -67,7 +67,7 @@
         android:layout_toStartOf="@android:id/button2"
         android:contentDescription="@string/accessibility_manual_zen_less_time"
         android:tint="?android:attr/colorAccent"
-        android:src="@drawable/ic_minus" />
+        android:src="@*android:drawable/ic_minus" />
 
     <ImageView
         android:id="@android:id/button2"
@@ -79,6 +79,6 @@
         android:layout_centerVertical="true"
         android:contentDescription="@string/accessibility_manual_zen_more_time"
         android:tint="?android:attr/colorAccent"
-        android:src="@drawable/ic_plus" />
+        android:src="@*android:drawable/ic_plus" />
 
-</RelativeLayout>
\ No newline at end of file
+</RelativeLayout>
diff --git a/packages/SettingsLib/res/values/styles.xml b/packages/SettingsLib/res/values/styles.xml
index bae8387..015f52c 100644
--- a/packages/SettingsLib/res/values/styles.xml
+++ b/packages/SettingsLib/res/values/styles.xml
@@ -24,7 +24,7 @@
 
     <style name="BorderlessButton">
         <item name="android:padding">12dp</item>
-        <item name="android:background">@drawable/btn_borderless_rect</item>
+        <item name="android:background">@*android:drawable/btn_borderless_rect</item>
         <item name="android:gravity">center</item>
     </style>
 </resources>
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpProfile.java
index c059156..bed3030 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpProfile.java
@@ -296,7 +296,7 @@
     }
 
     public int getDrawableResource(BluetoothClass btClass) {
-        return R.drawable.ic_bt_headphones_a2dp;
+        return com.android.internal.R.drawable.ic_bt_headphones_a2dp;
     }
 
     protected void finalize() {
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpSinkProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpSinkProfile.java
index 873dd1a..4ce9d3e 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpSinkProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpSinkProfile.java
@@ -205,7 +205,7 @@
     }
 
     public int getDrawableResource(BluetoothClass btClass) {
-        return R.drawable.ic_bt_headphones_a2dp;
+        return com.android.internal.R.drawable.ic_bt_headphones_a2dp;
     }
 
     protected void finalize() {
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothUtils.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothUtils.java
index ee80aa1..a8a0b6d 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothUtils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothUtils.java
@@ -61,13 +61,14 @@
         if (btClass != null) {
             switch (btClass.getMajorDeviceClass()) {
                 case BluetoothClass.Device.Major.COMPUTER:
-                    return new Pair<>(getBluetoothDrawable(context, R.drawable.ic_bt_laptop, level,
-                            iconScale),
+                    return new Pair<>(getBluetoothDrawable(context,
+                            com.android.internal.R.drawable.ic_bt_laptop, level, iconScale),
                             context.getString(R.string.bluetooth_talkback_computer));
 
                 case BluetoothClass.Device.Major.PHONE:
                     return new Pair<>(
-                            getBluetoothDrawable(context, R.drawable.ic_bt_cellphone, level,
+                            getBluetoothDrawable(context,
+                                    com.android.internal.R.drawable.ic_bt_cellphone, level,
                                     iconScale),
                             context.getString(R.string.bluetooth_talkback_phone));
 
@@ -79,7 +80,8 @@
 
                 case BluetoothClass.Device.Major.IMAGING:
                     return new Pair<>(
-                            getBluetoothDrawable(context, R.drawable.ic_settings_print, level,
+                            getBluetoothDrawable(context,
+                                    com.android.internal.R.drawable.ic_settings_print, level,
                                     iconScale),
                             context.getString(R.string.bluetooth_talkback_imaging));
 
@@ -98,19 +100,22 @@
         if (btClass != null) {
             if (btClass.doesClassMatch(BluetoothClass.PROFILE_HEADSET)) {
                 return new Pair<>(
-                        getBluetoothDrawable(context, R.drawable.ic_bt_headset_hfp, level,
+                        getBluetoothDrawable(context,
+                                com.android.internal.R.drawable.ic_bt_headset_hfp, level,
                                 iconScale),
                         context.getString(R.string.bluetooth_talkback_headset));
             }
             if (btClass.doesClassMatch(BluetoothClass.PROFILE_A2DP)) {
                 return new Pair<>(
-                        getBluetoothDrawable(context, R.drawable.ic_bt_headphones_a2dp, level,
+                        getBluetoothDrawable(context,
+                                com.android.internal.R.drawable.ic_bt_headphones_a2dp, level,
                                 iconScale),
                         context.getString(R.string.bluetooth_talkback_headphone));
             }
         }
         return new Pair<>(
-                getBluetoothDrawable(context, R.drawable.ic_settings_bluetooth, level, iconScale),
+                getBluetoothDrawable(context,
+                        com.android.internal.R.drawable.ic_settings_bluetooth, level, iconScale),
                 context.getString(R.string.bluetooth_talkback_bluetooth));
     }
 
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HeadsetProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HeadsetProfile.java
index 6b6df9b..a1bf936 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HeadsetProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HeadsetProfile.java
@@ -226,7 +226,7 @@
     }
 
     public int getDrawableResource(BluetoothClass btClass) {
-        return R.drawable.ic_bt_headset_hfp;
+        return com.android.internal.R.drawable.ic_bt_headset_hfp;
     }
 
     protected void finalize() {
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidProfile.java
index 77dfbe9..41c1d60 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidProfile.java
@@ -228,7 +228,7 @@
     }
 
     public int getDrawableResource(BluetoothClass btClass) {
-        return R.drawable.ic_bt_hearing_aid;
+        return com.android.internal.R.drawable.ic_bt_hearing_aid;
     }
 
     protected void finalize() {
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HfpClientProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HfpClientProfile.java
index c6bb2b3..4bdbc31 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HfpClientProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HfpClientProfile.java
@@ -211,7 +211,7 @@
 
     @Override
     public int getDrawableResource(BluetoothClass btClass) {
-        return R.drawable.ic_bt_headset_hfp;
+        return com.android.internal.R.drawable.ic_bt_headset_hfp;
     }
 
     protected void finalize() {
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HidDeviceProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HidDeviceProfile.java
index 4dc050c..35600b5 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HidDeviceProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HidDeviceProfile.java
@@ -171,7 +171,7 @@
 
     @Override
     public int getDrawableResource(BluetoothClass btClass) {
-        return R.drawable.ic_bt_misc_hid;
+        return com.android.internal.R.drawable.ic_bt_misc_hid;
     }
 
     protected void finalize() {
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HidProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HidProfile.java
index ca840d9a..7f906f6 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HidProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HidProfile.java
@@ -165,7 +165,7 @@
 
     public int getDrawableResource(BluetoothClass btClass) {
         if (btClass == null) {
-            return R.drawable.ic_lockscreen_ime;
+            return com.android.internal.R.drawable.ic_lockscreen_ime;
         }
         return getHidClassDrawable(btClass);
     }
@@ -174,11 +174,11 @@
         switch (btClass.getDeviceClass()) {
             case BluetoothClass.Device.PERIPHERAL_KEYBOARD:
             case BluetoothClass.Device.PERIPHERAL_KEYBOARD_POINTING:
-                return R.drawable.ic_lockscreen_ime;
+                return com.android.internal.R.drawable.ic_lockscreen_ime;
             case BluetoothClass.Device.PERIPHERAL_POINTING:
-                return R.drawable.ic_bt_pointing_hid;
+                return com.android.internal.R.drawable.ic_bt_pointing_hid;
             default:
-                return R.drawable.ic_bt_misc_hid;
+                return com.android.internal.R.drawable.ic_bt_misc_hid;
         }
     }
 
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/MapClientProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/MapClientProfile.java
index 6acdcac..0afc878 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/MapClientProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/MapClientProfile.java
@@ -200,7 +200,7 @@
     }
 
     public int getDrawableResource(BluetoothClass btClass) {
-        return R.drawable.ic_bt_cellphone;
+        return com.android.internal.R.drawable.ic_bt_cellphone;
     }
 
     protected void finalize() {
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/MapProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/MapProfile.java
index 28975d4..bea944c 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/MapProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/MapProfile.java
@@ -196,7 +196,7 @@
     }
 
     public int getDrawableResource(BluetoothClass btClass) {
-        return R.drawable.ic_bt_cellphone;
+        return com.android.internal.R.drawable.ic_bt_cellphone;
     }
 
     protected void finalize() {
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/PanProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/PanProfile.java
index 2d0a090..6638592 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/PanProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/PanProfile.java
@@ -153,7 +153,7 @@
     }
 
     public int getDrawableResource(BluetoothClass btClass) {
-        return R.drawable.ic_bt_network_pan;
+        return com.android.internal.R.drawable.ic_bt_network_pan;
     }
 
     // Tethering direction determines UI strings.
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/PbapClientProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/PbapClientProfile.java
index 4672393..4a27715 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/PbapClientProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/PbapClientProfile.java
@@ -192,7 +192,7 @@
     }
 
     public int getDrawableResource(BluetoothClass btClass) {
-        return R.drawable.ic_bt_cellphone;
+        return com.android.internal.R.drawable.ic_bt_cellphone;
     }
 
     protected void finalize() {
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/PbapServerProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/PbapServerProfile.java
index 1b3c453..165af2c 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/PbapServerProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/PbapServerProfile.java
@@ -135,7 +135,7 @@
     }
 
     public int getDrawableResource(BluetoothClass btClass) {
-        return R.drawable.ic_bt_cellphone;
+        return com.android.internal.R.drawable.ic_bt_cellphone;
     }
 
     protected void finalize() {
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/SapProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/SapProfile.java
index ea2ebde..9e9c5b9 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/SapProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/SapProfile.java
@@ -196,7 +196,7 @@
     }
 
     public int getDrawableResource(BluetoothClass btClass) {
-        return R.drawable.ic_bt_cellphone;
+        return com.android.internal.R.drawable.ic_bt_cellphone;
     }
 
     protected void finalize() {
diff --git a/packages/SettingsLib/src/com/android/settingslib/media/BluetoothMediaDevice.java b/packages/SettingsLib/src/com/android/settingslib/media/BluetoothMediaDevice.java
index a5c6f0c..6d0e3ac 100644
--- a/packages/SettingsLib/src/com/android/settingslib/media/BluetoothMediaDevice.java
+++ b/packages/SettingsLib/src/com/android/settingslib/media/BluetoothMediaDevice.java
@@ -19,7 +19,6 @@
 import android.content.Context;
 import android.util.Log;
 
-import com.android.settingslib.R;
 import com.android.settingslib.bluetooth.CachedBluetoothDevice;
 
 /**
@@ -45,7 +44,7 @@
     @Override
     public int getIcon() {
         //TODO(b/117129183): This is not final icon for bluetooth device, just for demo.
-        return R.drawable.ic_bt_headphones_a2dp;
+        return com.android.internal.R.drawable.ic_bt_headphones_a2dp;
     }
 
     @Override
diff --git a/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaDevice.java b/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaDevice.java
index 04f70cc..99d9d1c 100644
--- a/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaDevice.java
+++ b/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaDevice.java
@@ -20,8 +20,6 @@
 
 import androidx.mediarouter.media.MediaRouter;
 
-import com.android.settingslib.R;
-
 /**
  * InfoMediaDevice extends MediaDevice to represents wifi device.
  */
@@ -45,7 +43,7 @@
     @Override
     public int getIcon() {
         //TODO(b/121083246): This is not final icon for cast device, just for demo.
-        return R.drawable.ic_settings_print;
+        return com.android.internal.R.drawable.ic_settings_print;
     }
 
     @Override
diff --git a/packages/SettingsLib/src/com/android/settingslib/media/PhoneMediaDevice.java b/packages/SettingsLib/src/com/android/settingslib/media/PhoneMediaDevice.java
index c808214..01003aa 100644
--- a/packages/SettingsLib/src/com/android/settingslib/media/PhoneMediaDevice.java
+++ b/packages/SettingsLib/src/com/android/settingslib/media/PhoneMediaDevice.java
@@ -18,7 +18,6 @@
 import android.content.Context;
 import android.util.Log;
 
-import com.android.settingslib.R;
 import com.android.settingslib.bluetooth.A2dpProfile;
 import com.android.settingslib.bluetooth.HearingAidProfile;
 import com.android.settingslib.bluetooth.LocalBluetoothManager;
@@ -53,7 +52,7 @@
     @Override
     public int getIcon() {
         //TODO(b/117129183): This is not final icon for phone device, just for demo.
-        return R.drawable.ic_bt_cellphone;
+        return com.android.internal.R.drawable.ic_bt_cellphone;
     }
 
     @Override
diff --git a/packages/SettingsLib/src/com/android/settingslib/widget/FooterPreference.java b/packages/SettingsLib/src/com/android/settingslib/widget/FooterPreference.java
index f02044d..a106846 100644
--- a/packages/SettingsLib/src/com/android/settingslib/widget/FooterPreference.java
+++ b/packages/SettingsLib/src/com/android/settingslib/widget/FooterPreference.java
@@ -56,7 +56,7 @@
     }
 
     private void init() {
-        setIcon(R.drawable.ic_info_outline_24dp);
+        setIcon(com.android.internal.R.drawable.ic_info_outline_24);
         setKey(KEY_FOOTER);
         setOrder(ORDER_FOOTER);
         setSelectable(false);
diff --git a/packages/SettingsLib/tests/integ/src/com/android/settingslib/drawable/UserIconDrawableTest.java b/packages/SettingsLib/tests/integ/src/com/android/settingslib/drawable/UserIconDrawableTest.java
index a436cb5..cf7bcb2 100644
--- a/packages/SettingsLib/tests/integ/src/com/android/settingslib/drawable/UserIconDrawableTest.java
+++ b/packages/SettingsLib/tests/integ/src/com/android/settingslib/drawable/UserIconDrawableTest.java
@@ -31,8 +31,6 @@
 import androidx.test.InstrumentationRegistry;
 import androidx.test.runner.AndroidJUnit4;
 
-import com.android.settingslib.R;
-
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
@@ -45,7 +43,7 @@
     public void getConstantState_shouldNotBeNull() {
         final Bitmap b = BitmapFactory.decodeResource(
                 InstrumentationRegistry.getTargetContext().getResources(),
-                R.drawable.ic_mode_edit);
+                com.android.internal.R.drawable.ic_mode_edit);
         mDrawable = new UserIconDrawable(100 /* size */).setIcon(b).bake();
         assertThat(mDrawable.getConstantState()).isNotNull();
     }
diff --git a/packages/SettingsLib/tests/robotests/res/drawable/ic_info_outline_24dp.xml b/packages/SettingsLib/tests/robotests/res/drawable/ic_info_outline_24dp.xml
deleted file mode 100644
index 3fe1e9e..0000000
--- a/packages/SettingsLib/tests/robotests/res/drawable/ic_info_outline_24dp.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-     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.
--->
-<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/textColorSecondary">
-    <path
-        android:fillColor="#000000"
-        android:pathData="M11,17h2v-6h-2v6zM12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM12,20c-4.41,0 -8,-3.59 -8,-8s3.59,-8 8,-8 8,3.59 8,8 -3.59,8 -8,8zM11,9h2L13,7h-2v2z"/>
-</vector>
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 0eb6de9..7a71551 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
@@ -20,7 +20,6 @@
 import android.bluetooth.BluetoothDevice;
 import android.graphics.drawable.Drawable;
 
-import com.android.settingslib.R;
 import com.android.settingslib.graph.BluetoothDeviceLayerDrawable;
 
 import org.junit.Test;
@@ -34,7 +33,7 @@
     @Test
     public void testGetBluetoothDrawable_noBatteryLevel_returnSimpleDrawable() {
         final Drawable drawable = BluetoothUtils.getBluetoothDrawable(
-                RuntimeEnvironment.application, R.drawable.ic_bt_laptop,
+                RuntimeEnvironment.application, com.android.internal.R.drawable.ic_bt_laptop,
                 BluetoothDevice.BATTERY_LEVEL_UNKNOWN, 1 /* iconScale */);
 
         assertThat(drawable).isNotInstanceOf(BluetoothDeviceLayerDrawable.class);
@@ -43,7 +42,7 @@
     @Test
     public void testGetBluetoothDrawable_hasBatteryLevel_returnLayerDrawable() {
         final Drawable drawable = BluetoothUtils.getBluetoothDrawable(
-                RuntimeEnvironment.application, R.drawable.ic_bt_laptop,
+                RuntimeEnvironment.application, com.android.internal.R.drawable.ic_bt_laptop,
                 10 /* batteryLevel */, 1 /* iconScale */);
 
         assertThat(drawable).isInstanceOf(BluetoothDeviceLayerDrawable.class);
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/TileTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/TileTest.java
index b77670b..491f32d 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/TileTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/TileTest.java
@@ -12,8 +12,6 @@
 import android.content.pm.ActivityInfo;
 import android.os.Bundle;
 
-import com.android.settingslib.R;
-
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -31,7 +29,7 @@
         mActivityInfo = new ActivityInfo();
         mActivityInfo.packageName = RuntimeEnvironment.application.getPackageName();
         mActivityInfo.name = "abc";
-        mActivityInfo.icon = R.drawable.ic_plus;
+        mActivityInfo.icon = com.android.internal.R.drawable.ic_plus;
         mActivityInfo.metaData = new Bundle();
         mTile = new Tile(mActivityInfo, "category");
     }
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/TileUtilsTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/TileUtilsTest.java
index bbb4249..b379b54 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/TileUtilsTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/TileUtilsTest.java
@@ -53,8 +53,6 @@
 import android.util.ArrayMap;
 import android.util.Pair;
 
-import com.android.settingslib.R;
-
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -255,7 +253,7 @@
 
         resolveInfo.activityInfo.metaData = new Bundle(oldMetadata);
         resolveInfo.activityInfo.metaData.putInt(META_DATA_PREFERENCE_ICON,
-                R.drawable.ic_bt_cellphone);
+                com.android.internal.R.drawable.ic_bt_cellphone);
         outTiles.clear();
         TileUtils.getTilesForAction(mContext, UserHandle.CURRENT, IA_SETTINGS_ACTION, addedCache,
                 null /* defaultCategory */, outTiles, false /* usePriority */);
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/graph/BluetoothDeviceLayerDrawableTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/graph/BluetoothDeviceLayerDrawableTest.java
index 1b350cc..c6c2a44 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/graph/BluetoothDeviceLayerDrawableTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/graph/BluetoothDeviceLayerDrawableTest.java
@@ -31,7 +31,7 @@
 
 @RunWith(RobolectricTestRunner.class)
 public class BluetoothDeviceLayerDrawableTest {
-    private static final int RES_ID = R.drawable.ic_bt_cellphone;
+    private static final int RES_ID = com.android.internal.R.drawable.ic_bt_cellphone;
     private static final int BATTERY_LEVEL = 15;
     private static final float BATTERY_ICON_SCALE = 0.75f;
     private static final int BATTERY_ICON_PADDING_TOP = 6;
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/ActionButtonsPreferenceTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/ActionButtonsPreferenceTest.java
index 97de7ef..e24b525 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/ActionButtonsPreferenceTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/ActionButtonsPreferenceTest.java
@@ -74,10 +74,10 @@
 
     @Test
     public void onBindViewHolder_setIcon_shouldShowButtonByDefault() {
-        mPref.setButton1Icon(R.drawable.ic_plus);
-        mPref.setButton2Icon(R.drawable.ic_plus);
-        mPref.setButton3Icon(R.drawable.ic_plus);
-        mPref.setButton4Icon(R.drawable.ic_plus);
+        mPref.setButton1Icon(com.android.internal.R.drawable.ic_plus);
+        mPref.setButton2Icon(com.android.internal.R.drawable.ic_plus);
+        mPref.setButton3Icon(com.android.internal.R.drawable.ic_plus);
+        mPref.setButton4Icon(com.android.internal.R.drawable.ic_plus);
 
         mPref.onBindViewHolder(mHolder);
 
@@ -126,10 +126,10 @@
 
     @Test
     public void onBindViewHolder_setVisibleIsGoneAndSetIcon_shouldNotShowButton() {
-        mPref.setButton1Icon(R.drawable.ic_plus).setButton1Visible(false);
-        mPref.setButton2Icon(R.drawable.ic_plus).setButton2Visible(false);
-        mPref.setButton3Icon(R.drawable.ic_plus).setButton3Visible(false);
-        mPref.setButton4Icon(R.drawable.ic_plus).setButton4Visible(false);
+        mPref.setButton1Icon(com.android.internal.R.drawable.ic_plus).setButton1Visible(false);
+        mPref.setButton2Icon(com.android.internal.R.drawable.ic_plus).setButton2Visible(false);
+        mPref.setButton3Icon(com.android.internal.R.drawable.ic_plus).setButton3Visible(false);
+        mPref.setButton4Icon(com.android.internal.R.drawable.ic_plus).setButton4Visible(false);
 
         mPref.onBindViewHolder(mHolder);
 
@@ -215,7 +215,7 @@
     @Test
     public void onBindViewHolder_setButtonIcon_iconMustDisplayAboveText() {
         mPref.setButton1Text(R.string.install_other_apps);
-        mPref.setButton1Icon(R.drawable.ic_plus);
+        mPref.setButton1Icon(com.android.internal.R.drawable.ic_plus);
 
         mPref.onBindViewHolder(mHolder);
         final Drawable[] drawablesAroundText =
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/AppEntitiesHeaderControllerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/AppEntitiesHeaderControllerTest.java
index 4c68c14..63a958e 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/AppEntitiesHeaderControllerTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/AppEntitiesHeaderControllerTest.java
@@ -54,7 +54,7 @@
         mController = AppEntitiesHeaderController.newInstance(mContext,
                 mAppEntitiesHeaderView);
         mAppEntityInfo = new AppEntityInfo.Builder()
-                .setIcon(mContext.getDrawable(R.drawable.ic_menu))
+                .setIcon(mContext.getDrawable(com.android.internal.R.drawable.ic_menu))
                 .setTitle(TITLE)
                 .setSummary(SUMMARY)
                 .setOnClickListener(v -> {
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/BarChartPreferenceTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/BarChartPreferenceTest.java
index cf6137d..c3ea336 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/BarChartPreferenceTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/BarChartPreferenceTest.java
@@ -58,7 +58,7 @@
         mHolder = PreferenceViewHolder.createInstanceForTests(mBarChartView);
         mPreference = new BarChartPreference(mContext, null /* attrs */);
 
-        mIcon = mContext.getDrawable(R.drawable.ic_menu);
+        mIcon = mContext.getDrawable(com.android.internal.R.drawable.ic_menu);
         mBarView1 = mBarChartView.findViewById(R.id.bar_view1);
         mBarView2 = mBarChartView.findViewById(R.id.bar_view2);
         mBarView3 = mBarChartView.findViewById(R.id.bar_view3);
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
index 4f6a4ad..a1aefab 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
@@ -1714,6 +1714,12 @@
         dumpSetting(s, p,
                 Settings.Secure.TOUCH_EXPLORATION_GRANTED_ACCESSIBILITY_SERVICES,
                 SecureSettingsProto.Accessibility.TOUCH_EXPLORATION_GRANTED_ACCESSIBILITY_SERVICES);
+        dumpSetting(s, p,
+                Settings.Secure.ACCESSIBILITY_NON_INTERACTIVE_UI_TIMEOUT_MS,
+                SecureSettingsProto.Accessibility.NON_INTERACTIVE_UI_TIMEOUT_MS);
+        dumpSetting(s, p,
+                Settings.Secure.ACCESSIBILITY_INTERACTIVE_UI_TIMEOUT_MS,
+                SecureSettingsProto.Accessibility.INTERACTIVE_UI_TIMEOUT_MS);
         p.end(accessibilityToken);
 
         dumpSetting(s, p,
diff --git a/packages/SystemUI/res/drawable/smart_reply_button_background.xml b/packages/SystemUI/res/drawable/smart_reply_button_background.xml
index 31119a9..5652b49 100644
--- a/packages/SystemUI/res/drawable/smart_reply_button_background.xml
+++ b/packages/SystemUI/res/drawable/smart_reply_button_background.xml
@@ -25,7 +25,7 @@
             android:insetRight="0dp"
             android:insetBottom="8dp">
             <shape android:shape="rectangle">
-                <corners android:radius="8dp" />
+              <corners android:radius="@dimen/smart_reply_button_corner_radius" />
                 <stroke android:width="@dimen/smart_reply_button_stroke_width"
                         android:color="@color/smart_reply_button_stroke" />
                 <solid android:color="@color/smart_reply_button_background"/>
diff --git a/packages/SystemUI/res/layout/qs_footer_impl.xml b/packages/SystemUI/res/layout/qs_footer_impl.xml
index abf9e05..67e31ac 100644
--- a/packages/SystemUI/res/layout/qs_footer_impl.xml
+++ b/packages/SystemUI/res/layout/qs_footer_impl.xml
@@ -109,7 +109,7 @@
                 android:contentDescription="@string/accessibility_quick_settings_edit"
                 android:focusable="true"
                 android:padding="15dp"
-                android:src="@drawable/ic_mode_edit"
+                android:src="@*android:drawable/ic_mode_edit"
                 android:tint="?android:attr/colorForeground"/>
 
             <com.android.systemui.statusbar.AlphaOptimizedFrameLayout
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index a14259e..d435c67 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -888,8 +888,10 @@
     <dimen name="smart_reply_button_stroke_width">1dp</dimen>
     <dimen name="smart_reply_button_font_size">14sp</dimen>
     <dimen name="smart_reply_button_line_spacing_extra">6sp</dimen> <!-- Total line height 20sp. -->
-    <dimen name="smart_action_button_icon_size">24dp</dimen>
-    <dimen name="smart_action_button_icon_padding">10dp</dimen>
+    <!-- Corner radius = half of min_height to create rounded sides. -->
+    <dimen name="smart_reply_button_corner_radius">24dp</dimen>
+    <dimen name="smart_action_button_icon_size">18dp</dimen>
+    <dimen name="smart_action_button_icon_padding">8dp</dimen>
 
     <!-- A reasonable upper bound for the height of the smart reply button. The measuring code
             needs to start with a guess for the maximum size. Currently two-line smart reply buttons
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 190bd7a..ffa5de8 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -2305,8 +2305,8 @@
         <item quantity="other"><xliff:g id="num_apps" example="3">%1$d</xliff:g> applications are using your <xliff:g id="type" example="camera">%2$s</xliff:g>.</item>
     </plurals>
 
-    <!-- Action on Ongoing Privacy Dialog to dismiss [CHAR LIMIT=10]-->
-    <string name="ongoing_privacy_dialog_cancel">Cancel</string>
+    <!-- Action for accepting the Ongoing privacy dialog [CHAR LIMIT=10]-->
+    <string name="ongoing_privacy_dialog_ok">Got it</string>
 
     <!-- Action on Ongoing Privacy Dialog to open privacy hub [CHAR LIMIT=20]-->
     <string name="ongoing_privacy_dialog_open_settings">View details</string>
@@ -2337,6 +2337,7 @@
         <item quantity="one"><xliff:g id="num_apps" example="1">%d</xliff:g> other app</item>
         <item quantity="other"><xliff:g id="num_apps" example="3">%d</xliff:g> other apps</item>
     </plurals>
+
     <!-- Text for the quick setting tile for sensor privacy [CHAR LIMIT=30] -->
     <string name="sensor_privacy_mode">Sensors off</string>
 
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
index b7bee30..da29ab4 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
@@ -428,7 +428,7 @@
                 entry.key).canBubble();
         boolean hasOverlayIntent = n.getNotification().getBubbleMetadata() != null
                 && n.getNotification().getBubbleMetadata().getIntent() != null;
-        return hasOverlayIntent && canChannelOverlay && canAppOverlay;
+        return DEBUG_ENABLE_AUTO_BUBBLE && hasOverlayIntent && canChannelOverlay && canAppOverlay;
     }
 
     /**
@@ -438,7 +438,8 @@
      * message-like notification.
      * </p>
      */
-    private boolean shouldAutoBubble(Context context, NotificationEntry entry) {
+    @VisibleForTesting
+    protected boolean shouldAutoBubble(Context context, NotificationEntry entry) {
         if (entry.isBubbleDismissed()) {
             return false;
         }
@@ -465,9 +466,11 @@
         Class<? extends Notification.Style> style = n.getNotification().getNotificationStyle();
         boolean isMessageType = Notification.CATEGORY_MESSAGE.equals(n.getNotification().category);
         boolean isMessageStyle = Notification.MessagingStyle.class.equals(style);
-        return (((isMessageType && hasRemoteInput) || isMessageStyle) && autoBubbleMessages)
+        boolean shouldAutoBubble =
+                (((isMessageType && hasRemoteInput) || isMessageStyle) && autoBubbleMessages)
                 || (isImportantOngoing && autoBubbleOngoing)
                 || autoBubbleAll;
+        return DEBUG_ENABLE_AUTO_BUBBLE && shouldAutoBubble;
     }
 
     private static boolean shouldAutoBubbleMessages(Context context) {
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index f14495b..4527f73 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -40,6 +40,7 @@
 import android.content.IntentFilter;
 import android.content.pm.UserInfo;
 import android.hardware.biometrics.BiometricSourceType;
+import android.media.AudioAttributes;
 import android.media.AudioManager;
 import android.media.SoundPool;
 import android.os.Bundle;
@@ -750,7 +751,14 @@
 
         mDeviceInteractive = mPM.isInteractive();
 
-        mLockSounds = new SoundPool(1, AudioManager.STREAM_SYSTEM, 0);
+        mLockSounds = new SoundPool.Builder()
+                .setMaxStreams(1)
+                .setAudioAttributes(
+                        new AudioAttributes.Builder()
+                                .setUsage(AudioAttributes.USAGE_ASSISTANCE_SONIFICATION)
+                                .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
+                                .build())
+                .build();
         String soundPath = Settings.Global.getString(cr, Settings.Global.LOCK_SOUND);
         if (soundPath != null) {
             mLockSoundId = mLockSounds.load(soundPath, 1);
diff --git a/packages/SystemUI/src/com/android/systemui/privacy/OngoingPrivacyDialog.kt b/packages/SystemUI/src/com/android/systemui/privacy/OngoingPrivacyDialog.kt
index 26c6d50..db5c244 100644
--- a/packages/SystemUI/src/com/android/systemui/privacy/OngoingPrivacyDialog.kt
+++ b/packages/SystemUI/src/com/android/systemui/privacy/OngoingPrivacyDialog.kt
@@ -20,6 +20,7 @@
 import android.content.DialogInterface
 import android.content.Intent
 import android.content.res.ColorStateList
+import android.os.UserHandle
 import android.util.IconDrawableFactory
 import android.view.Gravity
 import android.view.LayoutInflater
@@ -48,6 +49,7 @@
             R.dimen.ongoing_appops_dialog_icon_margin)
     private val MAX_ITEMS = context.resources.getInteger(R.integer.ongoing_appops_dialog_max_apps)
     private val iconFactory = IconDrawableFactory.newInstance(context, true)
+    private var dismissDialog: (() -> Unit)? = null
 
     init {
         val a = context.theme.obtainStyledAttributes(
@@ -58,8 +60,8 @@
 
     fun createDialog(): Dialog {
         val builder = AlertDialog.Builder(context).apply {
-            setNegativeButton(R.string.ongoing_privacy_dialog_cancel, null)
-            setPositiveButton(R.string.ongoing_privacy_dialog_open_settings,
+            setPositiveButton(R.string.ongoing_privacy_dialog_ok, null)
+            setNeutralButton(R.string.ongoing_privacy_dialog_open_settings,
                     object : DialogInterface.OnClickListener {
                         val intent = Intent(Intent.ACTION_REVIEW_PERMISSION_USAGE).putExtra(
                                 Intent.EXTRA_DURATION_MILLIS, TimeUnit.MINUTES.toMillis(1))
@@ -72,7 +74,9 @@
                     })
         }
         builder.setView(getContentView())
-        return builder.create()
+        val dialog = builder.create()
+        dismissDialog = dialog::dismiss
+        return dialog
     }
 
     fun getContentView(): View {
@@ -116,6 +120,7 @@
         return contentView
     }
 
+    @Suppress("DEPRECATION")
     private fun addAppItem(
         itemList: LinearLayout,
         app: PrivacyApplication,
@@ -152,6 +157,16 @@
         } else {
             icons.visibility = View.GONE
         }
+        item.setOnClickListener(object : View.OnClickListener {
+            val intent = Intent(Intent.ACTION_REVIEW_APP_PERMISSION_USAGE)
+                    .putExtra(Intent.EXTRA_PACKAGE_NAME, app.packageName)
+                    .putExtra(Intent.EXTRA_USER, UserHandle.getUserHandleForUid(app.uid))
+            override fun onClick(v: View?) {
+                Dependency.get(ActivityStarter::class.java)
+                        .postStartActivityDismissingKeyguard(intent, 0)
+                dismissDialog?.invoke()
+            }
+        })
         itemList.addView(item)
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/privacy/PrivacyItem.kt b/packages/SystemUI/src/com/android/systemui/privacy/PrivacyItem.kt
index 9252167..dbe87d1 100644
--- a/packages/SystemUI/src/com/android/systemui/privacy/PrivacyItem.kt
+++ b/packages/SystemUI/src/com/android/systemui/privacy/PrivacyItem.kt
@@ -37,7 +37,7 @@
     val application: PrivacyApplication
 )
 
-data class PrivacyApplication(val packageName: String, val context: Context)
+data class PrivacyApplication(val packageName: String, val uid: Int, val context: Context)
     : Comparable<PrivacyApplication> {
 
     override fun compareTo(other: PrivacyApplication): Int {
diff --git a/packages/SystemUI/src/com/android/systemui/privacy/PrivacyItemController.kt b/packages/SystemUI/src/com/android/systemui/privacy/PrivacyItemController.kt
index 2339fae..f1c3bf2 100644
--- a/packages/SystemUI/src/com/android/systemui/privacy/PrivacyItemController.kt
+++ b/packages/SystemUI/src/com/android/systemui/privacy/PrivacyItemController.kt
@@ -59,7 +59,8 @@
     @Suppress("DEPRECATION")
     private val uiHandler = Dependency.get(Dependency.MAIN_HANDLER)
     private var listening = false
-    val systemApp = PrivacyApplication(context.getString(R.string.device_services), context)
+    val systemApp =
+            PrivacyApplication(context.getString(R.string.device_services), SYSTEM_UID, context)
     private val callbacks = mutableListOf<WeakReference<Callback>>()
 
     private val notifyChanges = Runnable {
@@ -162,7 +163,7 @@
             else -> return null
         }
         if (appOpItem.uid == SYSTEM_UID) return PrivacyItem(type, systemApp)
-        val app = PrivacyApplication(appOpItem.packageName, context)
+        val app = PrivacyApplication(appOpItem.packageName, appOpItem.uid, context)
         return PrivacyItem(type, app)
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java
index d740033..a0f4e24 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java
@@ -24,7 +24,6 @@
 
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.systemui.R;
-import com.android.systemui.R.drawable;
 import com.android.systemui.plugins.ActivityStarter;
 import com.android.systemui.plugins.qs.QSTile.BooleanState;
 import com.android.systemui.qs.QSHost;
@@ -38,7 +37,7 @@
 /** Quick settings tile: Location **/
 public class LocationTile extends QSTileImpl<BooleanState> {
 
-    private final Icon mIcon = ResourceIcon.get(drawable.ic_signal_location);
+    private final Icon mIcon = ResourceIcon.get(com.android.internal.R.drawable.ic_signal_location);
 
     private final LocationController mController;
     private final KeyguardMonitor mKeyguard;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/NightDisplayTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/NightDisplayTile.java
index 43ce0b5..de78d33 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/NightDisplayTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/NightDisplayTile.java
@@ -111,7 +111,7 @@
     protected void handleUpdateState(BooleanState state, Object arg) {
         state.value = mController.isActivated();
         state.label = mContext.getString(R.string.quick_settings_night_display_label);
-        state.icon = ResourceIcon.get(R.drawable.ic_qs_night_display_on);
+        state.icon = ResourceIcon.get(com.android.internal.R.drawable.ic_qs_night_display_on);
         state.expandedAccessibilityClassName = Switch.class.getName();
         state.state = state.value ? Tile.STATE_ACTIVE : Tile.STATE_INACTIVE;
         state.secondaryLabel = getSecondaryLabel(state.value);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
index 904478e..0150852 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
@@ -111,6 +111,7 @@
     private static final int MSG_SHOW_CHARGING_ANIMATION       = 44 << MSG_SHIFT;
     private static final int MSG_SHOW_PINNING_TOAST_ENTER_EXIT = 45 << MSG_SHIFT;
     private static final int MSG_SHOW_PINNING_TOAST_ESCAPE     = 46 << MSG_SHIFT;
+    private static final int MSG_DISPLAY_READY                 = 47 << MSG_SHIFT;
 
     public static final int FLAG_EXCLUDE_NONE = 0;
     public static final int FLAG_EXCLUDE_SEARCH_PANEL = 1 << 0;
@@ -274,6 +275,11 @@
         default void onBiometricHelp(String message) { }
         default void onBiometricError(String error) { }
         default void hideBiometricDialog() { }
+
+        /**
+        * @see IStatusBar#onDisplayReady(int)
+        */
+        default void onDisplayReady(int displayId) { }
     }
 
     @VisibleForTesting
@@ -761,6 +767,13 @@
         }
     }
 
+    @Override
+    public void onDisplayReady(int displayId) {
+        synchronized (mLock) {
+            mHandler.obtainMessage(MSG_DISPLAY_READY, displayId, 0).sendToTarget();
+        }
+    }
+
     private final class H extends Handler {
         private H(Looper l) {
             super(l);
@@ -1015,6 +1028,11 @@
                         mCallbacks.get(i).showPinningEscapeToast();
                     }
                     break;
+                case MSG_DISPLAY_READY:
+                    for (int i = 0; i < mCallbacks.size(); i++) {
+                        mCallbacks.get(i).onDisplayReady(msg.arg1);
+                    }
+                    break;
             }
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NavigationBarController.java b/packages/SystemUI/src/com/android/systemui/statusbar/NavigationBarController.java
index 9740d1d..e11ec2d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NavigationBarController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NavigationBarController.java
@@ -19,6 +19,7 @@
 import static android.view.Display.DEFAULT_DISPLAY;
 
 import static com.android.systemui.Dependency.MAIN_HANDLER_NAME;
+import static com.android.systemui.SysUiServiceProvider.getComponent;
 
 import android.content.Context;
 import android.hardware.display.DisplayManager;
@@ -34,6 +35,7 @@
 
 import com.android.systemui.Dependency;
 import com.android.systemui.plugins.DarkIconDispatcher;
+import com.android.systemui.statusbar.CommandQueue.Callbacks;
 import com.android.systemui.statusbar.phone.AutoHideController;
 import com.android.systemui.statusbar.phone.BarTransitions.TransitionMode;
 import com.android.systemui.statusbar.phone.LightBarController;
@@ -48,7 +50,7 @@
 
 /** A controller to handle navigation bars. */
 @Singleton
-public class NavigationBarController implements DisplayListener {
+public class NavigationBarController implements DisplayListener, Callbacks {
 
     private static final String TAG = NavigationBarController.class.getName();
 
@@ -65,13 +67,11 @@
         mHandler = handler;
         mDisplayManager = (DisplayManager) mContext.getSystemService(Context.DISPLAY_SERVICE);
         mDisplayManager.registerDisplayListener(this, mHandler);
+        getComponent(mContext, CommandQueue.class).addCallback(this);
     }
 
     @Override
-    public void onDisplayAdded(int displayId) {
-        Display display = mDisplayManager.getDisplay(displayId);
-        createNavigationBar(display);
-    }
+    public void onDisplayAdded(int displayId) { }
 
     @Override
     public void onDisplayRemoved(int displayId) {
@@ -79,7 +79,12 @@
     }
 
     @Override
-    public void onDisplayChanged(int displayId) {
+    public void onDisplayChanged(int displayId) { }
+
+    @Override
+    public void onDisplayReady(int displayId) {
+        Display display = mDisplayManager.getDisplay(displayId);
+        createNavigationBar(display);
     }
 
     // TODO(b/117478341): I use {@code includeDefaultDisplay} to make this method compatible to
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationLogger.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationLogger.java
index 35b7ef4..5e52419 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationLogger.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationLogger.java
@@ -39,7 +39,6 @@
 import com.android.systemui.statusbar.notification.NotificationEntryListener;
 import com.android.systemui.statusbar.notification.NotificationEntryManager;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
-import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
 import com.android.systemui.statusbar.notification.stack.ExpandableViewState;
 import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
 import com.android.systemui.statusbar.policy.HeadsUpManager;
@@ -221,6 +220,11 @@
             }
 
             @Override
+            public void onEntryReinflated(NotificationEntry entry) {
+                mExpansionStateLogger.onEntryReinflated(entry.key);
+            }
+
+            @Override
             public void onInflationError(
                     StatusBarNotification notification,
                     Exception exception) {
@@ -468,6 +472,13 @@
             mLoggedExpansionState.remove(key);
         }
 
+        @VisibleForTesting
+        void onEntryReinflated(String key) {
+            // When the notification is updated, we should consider the notification as not
+            // yet logged.
+            mLoggedExpansionState.remove(key);
+        }
+
         private State getState(String key) {
             State state = mExpansionStates.get(key);
             if (state == null) {
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 c108371..711b08e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -448,6 +448,11 @@
                 false);
         addView(mKeyguardStatusView, index);
 
+        // Re-associate the clock container with the keyguard clock switch.
+        mBigClockContainer.removeAllViews();
+        KeyguardClockSwitch keyguardClockSwitch = findViewById(R.id.keyguard_clock_container);
+        keyguardClockSwitch.setBigClockContainer(mBigClockContainer);
+
         // Update keyguard bottom area
         index = indexOfChild(mKeyguardBottomArea);
         removeView(mKeyguardBottomArea);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyView.java
index c4f027f..07c6587 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyView.java
@@ -479,13 +479,20 @@
         remeasureButtonsIfNecessary(accumulatedMeasures.mButtonPaddingHorizontal,
                                     accumulatedMeasures.mMaxChildHeight);
 
+        int buttonHeight = Math.max(getSuggestedMinimumHeight(), mPaddingTop
+                + accumulatedMeasures.mMaxChildHeight + mPaddingBottom);
+
+        // Set the corner radius to half the button height to make the side of the buttons look like
+        // a semicircle.
+        for (View smartSuggestionButton : smartSuggestions) {
+            setCornerRadius((Button) smartSuggestionButton, ((float) buttonHeight) / 2);
+        }
+
         setMeasuredDimension(
                 resolveSize(Math.max(getSuggestedMinimumWidth(),
                                      accumulatedMeasures.mMeasuredWidth),
                             widthMeasureSpec),
-                resolveSize(Math.max(getSuggestedMinimumHeight(), mPaddingTop
-                        + accumulatedMeasures.mMaxChildHeight + mPaddingBottom),
-                            heightMeasureSpec));
+                resolveSize(buttonHeight, heightMeasureSpec));
     }
 
     /**
@@ -806,6 +813,23 @@
         button.setTextColor(textColor);
     }
 
+    private void setCornerRadius(Button button, float radius) {
+        Drawable drawable = button.getBackground();
+        if (drawable instanceof RippleDrawable) {
+            // Mutate in case other notifications are using this drawable.
+            drawable = drawable.mutate();
+            RippleDrawable ripple = (RippleDrawable) drawable;
+            Drawable inset = ripple.getDrawable(0);
+            if (inset instanceof InsetDrawable) {
+                Drawable background = ((InsetDrawable) inset).getDrawable();
+                if (background instanceof GradientDrawable) {
+                    GradientDrawable gradientDrawable = (GradientDrawable) background;
+                    gradientDrawable.setCornerRadius(radius);
+                }
+            }
+        }
+    }
+
     private ActivityStarter getActivityStarter() {
         if (mActivityStarter == null) {
             mActivityStarter = Dependency.get(ActivityStarter.class);
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 e802757..44ff4a7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java
@@ -36,6 +36,7 @@
 import com.android.systemui.statusbar.notification.NotificationEntryListener;
 import com.android.systemui.statusbar.notification.NotificationEntryManager;
 import com.android.systemui.statusbar.notification.collection.NotificationData;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
 import com.android.systemui.statusbar.phone.DozeParameters;
 import com.android.systemui.statusbar.phone.StatusBarWindowController;
@@ -189,5 +190,10 @@
                 StatusBarWindowController statusBarWindowController) {
             super(context, statusBarWindowController);
         }
+
+        @Override
+        public boolean shouldAutoBubble(Context c, NotificationEntry entry) {
+            return entry.notification.getNotification().getBubbleMetadata() != null;
+        }
     }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyDialogBuilderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyDialogBuilderTest.kt
index d3b3dae..f163b88 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyDialogBuilderTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyDialogBuilderTest.kt
@@ -27,16 +27,20 @@
 @SmallTest
 class PrivacyDialogBuilderTest : SysuiTestCase() {
 
+    companion object {
+        val TEST_UID = 1
+    }
+
     @Test
     fun testGenerateAppsList() {
         val bar2 = PrivacyItem(Privacy.TYPE_CAMERA, PrivacyApplication(
-                "Bar", context))
+                "Bar", TEST_UID, context))
         val bar3 = PrivacyItem(Privacy.TYPE_LOCATION, PrivacyApplication(
-                "Bar", context))
+                "Bar", TEST_UID, context))
         val foo0 = PrivacyItem(Privacy.TYPE_CAMERA, PrivacyApplication(
-                "Foo", context))
+                "Foo", TEST_UID, context))
         val baz1 = PrivacyItem(Privacy.TYPE_CAMERA, PrivacyApplication(
-                "Baz", context))
+                "Baz", TEST_UID, context))
 
         val items = listOf(bar2, foo0, baz1, bar3)
 
@@ -55,11 +59,14 @@
     @Test
     fun testOrder() {
         // We want location to always go last, so it will go in the "+ other apps"
-        val appCamera = PrivacyItem(PrivacyType.TYPE_CAMERA, PrivacyApplication("Camera", context))
+        val appCamera = PrivacyItem(PrivacyType.TYPE_CAMERA,
+                PrivacyApplication("Camera", TEST_UID, context))
         val appMicrophone =
-                PrivacyItem(PrivacyType.TYPE_MICROPHONE, PrivacyApplication("Microphone", context))
+                PrivacyItem(PrivacyType.TYPE_MICROPHONE,
+                        PrivacyApplication("Microphone", TEST_UID, context))
         val appLocation =
-                PrivacyItem(PrivacyType.TYPE_LOCATION, PrivacyApplication("Location", context))
+                PrivacyItem(PrivacyType.TYPE_LOCATION,
+                        PrivacyApplication("Location", TEST_UID, context))
 
         val items = listOf(appLocation, appMicrophone, appCamera)
         val textBuilder = PrivacyDialogBuilder(context, items)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/ExpansionStateLoggerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/ExpansionStateLoggerTest.java
index 5ff9d14..f1d9003 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/ExpansionStateLoggerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/ExpansionStateLoggerTest.java
@@ -15,10 +15,10 @@
  */
 package com.android.systemui.statusbar.notification.logging;
 
-import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyBoolean;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 
 import android.os.RemoteException;
@@ -31,6 +31,7 @@
 import com.android.systemui.Dependency;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.UiOffloadThread;
+import com.android.systemui.statusbar.notification.stack.ExpandableViewState;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -155,6 +156,27 @@
                 NotificationVisibility.NotificationLocation.LOCATION_UNKNOWN.toMetricsEventEnum());
     }
 
+    @Test
+    public void testOnEntryReinflated() throws RemoteException {
+        mLogger.onExpansionChanged(NOTIFICATION_KEY, true, true,
+                NotificationVisibility.NotificationLocation.LOCATION_UNKNOWN);
+        mLogger.onVisibilityChanged(
+                Collections.singletonList(createNotificationVisibility(NOTIFICATION_KEY, true)),
+                Collections.emptyList());
+        waitForUiOffloadThread();
+        verify(mBarService).onNotificationExpansionChanged(
+                NOTIFICATION_KEY, true, true, ExpandableViewState.LOCATION_UNKNOWN);
+
+        mLogger.onEntryReinflated(NOTIFICATION_KEY);
+        mLogger.onVisibilityChanged(
+                Collections.singletonList(createNotificationVisibility(NOTIFICATION_KEY, true)),
+                Collections.emptyList());
+        waitForUiOffloadThread();
+        // onNotificationExpansionChanged is called the second time.
+        verify(mBarService, times(2)).onNotificationExpansionChanged(
+                NOTIFICATION_KEY, true, true, ExpandableViewState.LOCATION_UNKNOWN);
+    }
+
     private NotificationVisibility createNotificationVisibility(String key, boolean visibility) {
         return createNotificationVisibility(key, visibility,
                 NotificationVisibility.NotificationLocation.LOCATION_UNKNOWN);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarButtonTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarButtonTest.java
index 73f3b43..6177344 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarButtonTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarButtonTest.java
@@ -51,6 +51,7 @@
 
     @Before
     public void setup() {
+        mContext.putComponent(CommandQueue.class, mock(CommandQueue.class));
         final Display display = createVirtualDisplay();
         final SysuiTestableContext context =
                 (SysuiTestableContext) mContext.createDisplayContext(display);
diff --git a/proto/src/metrics_constants/metrics_constants.proto b/proto/src/metrics_constants/metrics_constants.proto
index 73fcb01..43e9435 100644
--- a/proto/src/metrics_constants/metrics_constants.proto
+++ b/proto/src/metrics_constants/metrics_constants.proto
@@ -6904,6 +6904,12 @@
     // OS: Q
     FIELD_TEXT_CLASSIFIER_WIDGET_VERSION = 1640;
 
+    // Tagged data for NOTIFICATION_ITEM. One of the CATEGORY String constants from
+    // https://developer.android.com/reference/android/app/Notification .
+    // OS: Q
+    // CATEGORY: NOTIFICATION
+    FIELD_NOTIFICATION_CATEGORY = 1641;
+
     // ---- End Q Constants, all Q constants go above this line ----
     // Add new aosp constants above this line.
     // END OF AOSP CONSTANTS
diff --git a/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java b/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java
index 2c075dc..f4ac130 100644
--- a/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java
+++ b/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java
@@ -275,6 +275,9 @@
                 & AccessibilityServiceInfo.CAPABILITY_CAN_REQUEST_FILTER_KEY_EVENTS) == 0) {
             return false;
         }
+        if (!mSecurityPolicy.checkAccessibilityAccess(this)) {
+            return false;
+        }
         try {
             mServiceInterface.onKeyEvent(keyEvent, sequenceNumber);
         } catch (RemoteException e) {
@@ -388,6 +391,9 @@
             if (mSecurityPolicy.mWindows == null) {
                 return null;
             }
+            if (!mSecurityPolicy.checkAccessibilityAccess(this)) {
+                return null;
+            }
             List<AccessibilityWindowInfo> windows = new ArrayList<>();
             final int windowCount = mSecurityPolicy.mWindows.size();
             for (int i = 0; i < windowCount; i++) {
@@ -413,6 +419,9 @@
             if (!permissionGranted) {
                 return null;
             }
+            if (!mSecurityPolicy.checkAccessibilityAccess(this)) {
+                return null;
+            }
             AccessibilityWindowInfo window = mSecurityPolicy.findA11yWindowInfoById(windowId);
             if (window != null) {
                 AccessibilityWindowInfo windowClone = AccessibilityWindowInfo.obtain(window);
@@ -455,6 +464,9 @@
             }
             spec = mSystemSupport.getCompatibleMagnificationSpecLocked(resolvedWindowId);
         }
+        if (!mSecurityPolicy.checkAccessibilityAccess(this)) {
+            return null;
+        }
         final int interrogatingPid = Binder.getCallingPid();
         callback = mSystemSupport.replaceCallbackIfNeeded(callback, resolvedWindowId, interactionId,
                 interrogatingPid, interrogatingTid);
@@ -511,6 +523,9 @@
             }
             spec = mSystemSupport.getCompatibleMagnificationSpecLocked(resolvedWindowId);
         }
+        if (!mSecurityPolicy.checkAccessibilityAccess(this)) {
+            return null;
+        }
         final int interrogatingPid = Binder.getCallingPid();
         callback = mSystemSupport.replaceCallbackIfNeeded(callback, resolvedWindowId, interactionId,
                 interrogatingPid, interrogatingTid);
@@ -567,6 +582,9 @@
             }
             spec = mSystemSupport.getCompatibleMagnificationSpecLocked(resolvedWindowId);
         }
+        if (!mSecurityPolicy.checkAccessibilityAccess(this)) {
+            return null;
+        }
         final int interrogatingPid = Binder.getCallingPid();
         callback = mSystemSupport.replaceCallbackIfNeeded(callback, resolvedWindowId, interactionId,
                 interrogatingPid, interrogatingTid);
@@ -623,6 +641,9 @@
             }
             spec = mSystemSupport.getCompatibleMagnificationSpecLocked(resolvedWindowId);
         }
+        if (!mSecurityPolicy.checkAccessibilityAccess(this)) {
+            return null;
+        }
         final int interrogatingPid = Binder.getCallingPid();
         callback = mSystemSupport.replaceCallbackIfNeeded(callback, resolvedWindowId, interactionId,
                 interrogatingPid, interrogatingTid);
@@ -678,6 +699,9 @@
             }
             spec = mSystemSupport.getCompatibleMagnificationSpecLocked(resolvedWindowId);
         }
+        if (!mSecurityPolicy.checkAccessibilityAccess(this)) {
+            return null;
+        }
         final int interrogatingPid = Binder.getCallingPid();
         callback = mSystemSupport.replaceCallbackIfNeeded(callback, resolvedWindowId, interactionId,
                 interrogatingPid, interrogatingTid);
@@ -722,6 +746,9 @@
                 return false;
             }
         }
+        if (!mSecurityPolicy.checkAccessibilityAccess(this)) {
+            return false;
+        }
         boolean returnValue =
                 mSystemSupport.performAccessibilityAction(resolvedWindowId, accessibilityNodeId,
                 action, arguments, interactionId, callback, mFetchFlags, interrogatingTid);
@@ -974,6 +1001,9 @@
                 return;
             }
 
+            if (!mSecurityPolicy.checkAccessibilityAccess(this)) {
+                return;
+            }
             // Make a copy since during dispatch it is possible the event to
             // be modified to remove its source if the receiving service does
             // not have permission to access the window content.
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index 305c53e..f88d521 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -3787,6 +3787,31 @@
                 return findWindowIdLocked(token);
             }
         }
+
+        public boolean checkAccessibilityAccess(AbstractAccessibilityServiceConnection service) {
+            final String packageName = service.getComponentName().getPackageName();
+            final ResolveInfo resolveInfo = service.getServiceInfo().getResolveInfo();
+
+            if (resolveInfo == null) {
+                // For InteractionBridge and UiAutomation
+                return true;
+            }
+
+            final int uid = resolveInfo.serviceInfo.applicationInfo.uid;
+            final long identityToken = Binder.clearCallingIdentity();
+            try {
+                // For the caller is system, just block the data to a11y services.
+                if (OWN_PROCESS_ID == Binder.getCallingPid()) {
+                    return mAppOpsManager.noteOpNoThrow(AppOpsManager.OPSTR_ACCESS_ACCESSIBILITY,
+                            uid, packageName) == AppOpsManager.MODE_ALLOWED;
+                }
+
+                return mAppOpsManager.noteOp(AppOpsManager.OPSTR_ACCESS_ACCESSIBILITY,
+                        uid, packageName) == AppOpsManager.MODE_ALLOWED;
+            } finally {
+                Binder.restoreCallingIdentity(identityToken);
+            }
+        }
     }
 
     /**
diff --git a/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java b/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java
index 844096d..6108aaa 100644
--- a/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java
+++ b/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java
@@ -177,12 +177,13 @@
     final class ContentCaptureManagerServiceStub extends IContentCaptureManager.Stub {
 
         @Override
-        public void startSession(@UserIdInt int userId, @NonNull IBinder activityToken,
+        public void startSession(@NonNull IBinder activityToken,
                 @NonNull ComponentName componentName, @NonNull String sessionId, int flags,
                 @NonNull IResultReceiver result) {
             Preconditions.checkNotNull(activityToken);
             Preconditions.checkNotNull(componentName);
             Preconditions.checkNotNull(sessionId);
+            final int userId = UserHandle.getCallingUserId();
 
             // TODO(b/111276913): refactor getTaskIdForActivity() to also return ComponentName,
             // so we don't pass it on startSession (same for Autofill)
@@ -199,8 +200,9 @@
         }
 
         @Override
-        public void finishSession(@UserIdInt int userId, @NonNull String sessionId) {
+        public void finishSession(@NonNull String sessionId) {
             Preconditions.checkNotNull(sessionId);
+            final int userId = UserHandle.getCallingUserId();
 
             synchronized (mLock) {
                 final ContentCapturePerUserService service = getServiceForUserLocked(userId);
@@ -209,15 +211,16 @@
         }
 
         @Override
-        public void getReceiverServiceComponentName(@UserIdInt int userId,
-                IResultReceiver receiver) {
+        public void getServiceComponentName(@NonNull IResultReceiver result) {
+            final int userId = UserHandle.getCallingUserId();
             ComponentName connectedServiceComponentName;
             synchronized (mLock) {
                 final ContentCapturePerUserService service = getServiceForUserLocked(userId);
                 connectedServiceComponentName = service.getServiceComponentName();
             }
             try {
-                receiver.send(0, SyncResultReceiver.bundleFor(connectedServiceComponentName));
+                result.send(/* resultCode= */ 0,
+                        SyncResultReceiver.bundleFor(connectedServiceComponentName));
             } catch (RemoteException e) {
                 // Ignore exception as we need to be resilient against app behavior.
                 Slog.w(TAG, "Unable to send service component name: " + e);
@@ -225,8 +228,9 @@
         }
 
         @Override
-        public void removeUserData(@UserIdInt int userId, @NonNull UserDataRemovalRequest request) {
+        public void removeUserData(@NonNull UserDataRemovalRequest request) {
             Preconditions.checkNotNull(request);
+            final int userId = UserHandle.getCallingUserId();
             synchronized (mLock) {
                 final ContentCapturePerUserService service = getServiceForUserLocked(userId);
                 service.removeUserDataLocked(request);
diff --git a/services/core/java/com/android/server/AlarmManagerInternal.java b/services/core/java/com/android/server/AlarmManagerInternal.java
index dbff957..2756610 100644
--- a/services/core/java/com/android/server/AlarmManagerInternal.java
+++ b/services/core/java/com/android/server/AlarmManagerInternal.java
@@ -17,5 +17,15 @@
 package com.android.server;
 
 public interface AlarmManagerInternal {
-    void removeAlarmsForUid(int uid);
+    // Some other components in the system server need to know about
+    // broadcast alarms currently in flight
+    public interface InFlightListener {
+        /** There is now an alarm pending delivery to the given app */
+        void broadcastAlarmPending(int recipientUid);
+        /** A broadcast alarm targeted to the given app has completed delivery */
+        void broadcastAlarmComplete(int recipientUid);
+    }
+
+    public void removeAlarmsForUid(int uid);
+    public void registerInFlightListener(InFlightListener callback);
 }
diff --git a/services/core/java/com/android/server/AlarmManagerService.java b/services/core/java/com/android/server/AlarmManagerService.java
index e3dcb7d..10b5327 100644
--- a/services/core/java/com/android/server/AlarmManagerService.java
+++ b/services/core/java/com/android/server/AlarmManagerService.java
@@ -197,6 +197,8 @@
     PowerManager.WakeLock mWakeLock;
     ArrayList<Alarm> mPendingNonWakeupAlarms = new ArrayList<>();
     ArrayList<InFlight> mInFlight = new ArrayList<>();
+    private final ArrayList<AlarmManagerInternal.InFlightListener> mInFlightListeners =
+            new ArrayList<>();
     AlarmHandler mHandler;
     AppWakeupHistory mAppWakeupHistory;
     ClockReceiver mClockReceiver;
@@ -1315,6 +1317,10 @@
             mAlarmType = alarm.type;
         }
 
+        boolean isBroadcast() {
+            return mPendingIntent != null && mPendingIntent.isBroadcast();
+        }
+
         @Override
         public String toString() {
             return "InFlight{"
@@ -1354,6 +1360,20 @@
         }
     }
 
+    private void notifyBroadcastAlarmPendingLocked(int uid) {
+        final int numListeners = mInFlightListeners.size();
+        for (int i = 0; i < numListeners; i++) {
+            mInFlightListeners.get(i).broadcastAlarmPending(uid);
+        }
+    }
+
+    private void notifyBroadcastAlarmCompleteLocked(int uid) {
+        final int numListeners = mInFlightListeners.size();
+        for (int i = 0; i < numListeners; i++) {
+            mInFlightListeners.get(i).broadcastAlarmComplete(uid);
+        }
+    }
+
     static final class FilterStats {
         final BroadcastStats mBroadcastStats;
         final String mTag;
@@ -1976,6 +1996,13 @@
                 removeLocked(uid);
             }
         }
+
+        @Override
+        public void registerInFlightListener(InFlightListener callback) {
+            synchronized (mLock) {
+                mInFlightListeners.add(callback);
+            }
+        }
     }
 
     /**
@@ -4426,7 +4453,11 @@
 
         private InFlight removeLocked(PendingIntent pi, Intent intent) {
             for (int i = 0; i < mInFlight.size(); i++) {
-                if (mInFlight.get(i).mPendingIntent == pi) {
+                final InFlight inflight = mInFlight.get(i);
+                if (inflight.mPendingIntent == pi) {
+                    if (pi.isBroadcast()) {
+                        notifyBroadcastAlarmCompleteLocked(inflight.mUid);
+                    }
                     return mInFlight.remove(i);
                 }
             }
@@ -4649,6 +4680,9 @@
             final InFlight inflight = new InFlight(AlarmManagerService.this, alarm, nowELAPSED);
             mInFlight.add(inflight);
             mBroadcastRefCount++;
+            if (inflight.isBroadcast()) {
+                notifyBroadcastAlarmPendingLocked(alarm.uid);
+            }
             if (allowWhileIdle) {
                 // Record the last time this uid handled an ALLOW_WHILE_IDLE alarm.
                 mLastAllowWhileIdleDispatch.put(alarm.creatorUid, nowELAPSED);
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 14e2354..1519c17 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -1884,6 +1884,12 @@
                 "ConnectivityService");
     }
 
+    private void enforceControlAlwaysOnVpnPermission() {
+        mContext.enforceCallingOrSelfPermission(
+                android.Manifest.permission.CONTROL_ALWAYS_ON_VPN,
+                "ConnectivityService");
+    }
+
     private void enforceNetworkStackSettingsOrSetup() {
         enforceAnyPermissionOf(
             android.Manifest.permission.NETWORK_SETTINGS,
@@ -1891,6 +1897,12 @@
             android.Manifest.permission.NETWORK_STACK);
     }
 
+    private void enforceNetworkStackPermission() {
+        mContext.enforceCallingOrSelfPermission(
+                android.Manifest.permission.NETWORK_STACK,
+                "ConnectivityService");
+    }
+
     private boolean checkNetworkStackPermission() {
         return PERMISSION_GRANTED == mContext.checkCallingOrSelfPermission(
                 android.Manifest.permission.NETWORK_STACK);
@@ -4147,8 +4159,9 @@
     }
 
     @Override
-    public boolean setAlwaysOnVpnPackage(int userId, String packageName, boolean lockdown) {
-        enforceConnectivityInternalPermission();
+    public boolean setAlwaysOnVpnPackage(
+            int userId, String packageName, boolean lockdown, List<String> lockdownWhitelist) {
+        enforceControlAlwaysOnVpnPermission();
         enforceCrossUserPermission(userId);
 
         synchronized (mVpns) {
@@ -4162,11 +4175,11 @@
                 Slog.w(TAG, "User " + userId + " has no Vpn configuration");
                 return false;
             }
-            if (!vpn.setAlwaysOnPackage(packageName, lockdown)) {
+            if (!vpn.setAlwaysOnPackage(packageName, lockdown, lockdownWhitelist)) {
                 return false;
             }
             if (!startAlwaysOnVpn(userId)) {
-                vpn.setAlwaysOnPackage(null, false);
+                vpn.setAlwaysOnPackage(null, false, null);
                 return false;
             }
         }
@@ -4175,7 +4188,7 @@
 
     @Override
     public String getAlwaysOnVpnPackage(int userId) {
-        enforceConnectivityInternalPermission();
+        enforceControlAlwaysOnVpnPermission();
         enforceCrossUserPermission(userId);
 
         synchronized (mVpns) {
@@ -4189,6 +4202,36 @@
     }
 
     @Override
+    public boolean isVpnLockdownEnabled(int userId) {
+        enforceControlAlwaysOnVpnPermission();
+        enforceCrossUserPermission(userId);
+
+        synchronized (mVpns) {
+            Vpn vpn = mVpns.get(userId);
+            if (vpn == null) {
+                Slog.w(TAG, "User " + userId + " has no Vpn configuration");
+                return false;
+            }
+            return vpn.getLockdown();
+        }
+    }
+
+    @Override
+    public List<String> getVpnLockdownWhitelist(int userId) {
+        enforceControlAlwaysOnVpnPermission();
+        enforceCrossUserPermission(userId);
+
+        synchronized (mVpns) {
+            Vpn vpn = mVpns.get(userId);
+            if (vpn == null) {
+                Slog.w(TAG, "User " + userId + " has no Vpn configuration");
+                return null;
+            }
+            return vpn.getLockdownWhitelist();
+        }
+    }
+
+    @Override
     public int checkMobileProvisioning(int suggestedTimeOutMs) {
         // TODO: Remove?  Any reason to trigger a provisioning check?
         return -1;
@@ -4417,7 +4460,7 @@
             if (TextUtils.equals(vpn.getAlwaysOnPackage(), packageName) && !isReplacing) {
                 Slog.d(TAG, "Removing always-on VPN package " + packageName + " for user "
                         + userId);
-                vpn.setAlwaysOnPackage(null, false);
+                vpn.setAlwaysOnPackage(null, false, null);
             }
         }
     }
@@ -6297,7 +6340,7 @@
             synchronized (mVpns) {
                 final String alwaysOnPackage = getAlwaysOnVpnPackage(userId);
                 if (alwaysOnPackage != null) {
-                    setAlwaysOnVpnPackage(userId, null, false);
+                    setAlwaysOnVpnPackage(userId, null, false, null);
                     setVpnPackageAuthorization(alwaysOnPackage, userId, false);
                 }
 
diff --git a/services/core/java/com/android/server/LooperStatsService.java b/services/core/java/com/android/server/LooperStatsService.java
index 4a8706e..2f7929c 100644
--- a/services/core/java/com/android/server/LooperStatsService.java
+++ b/services/core/java/com/android/server/LooperStatsService.java
@@ -55,11 +55,11 @@
             "debug.sys.looper_stats_enabled";
     private static final int DEFAULT_SAMPLING_INTERVAL = 100;
     private static final int DEFAULT_ENTRIES_SIZE_CAP = 2000;
-    private static final boolean DEFAULT_ENABLED = false;
+    private static final boolean DEFAULT_ENABLED = true;
 
     private final Context mContext;
     private final LooperStats mStats;
-    private boolean mEnabled = false;
+    private boolean mEnabled = DEFAULT_ENABLED;
 
     private LooperStatsService(Context context, LooperStats stats) {
         this.mContext = context;
diff --git a/services/core/java/com/android/server/PackageWatchdog.java b/services/core/java/com/android/server/PackageWatchdog.java
index 8adc416..84577f1 100644
--- a/services/core/java/com/android/server/PackageWatchdog.java
+++ b/services/core/java/com/android/server/PackageWatchdog.java
@@ -16,6 +16,9 @@
 
 package com.android.server;
 
+import static java.lang.annotation.RetentionPolicy.SOURCE;
+
+import android.annotation.IntDef;
 import android.annotation.Nullable;
 import android.content.Context;
 import android.os.Environment;
@@ -46,6 +49,7 @@
 import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
+import java.lang.annotation.Retention;
 import java.nio.charset.StandardCharsets;
 import java.util.ArrayList;
 import java.util.Collections;
@@ -55,7 +59,8 @@
 
 /**
  * Monitors the health of packages on the system and notifies interested observers when packages
- * fail. All registered observers will be notified until an observer takes a mitigation action.
+ * fail. On failure, the registered observer with the least user impacting mitigation will
+ * be notified.
  */
 public class PackageWatchdog {
     private static final String TAG = "PackageWatchdog";
@@ -78,7 +83,8 @@
     private final Context mContext;
     // Handler to run package cleanup runnables
     private final Handler mTimerHandler;
-    private final Handler mIoHandler;
+    // Handler for processing IO and observer actions
+    private final Handler mWorkerHandler;
     // Contains (observer-name -> observer-handle) that have ever been registered from
     // previous boots. Observers with all packages expired are periodically pruned.
     // It is saved to disk on system shutdown and repouplated on startup so it survives reboots.
@@ -101,7 +107,7 @@
         mPolicyFile = new AtomicFile(new File(new File(Environment.getDataDirectory(), "system"),
                         "package-watchdog.xml"));
         mTimerHandler = new Handler(Looper.myLooper());
-        mIoHandler = BackgroundThread.getHandler();
+        mWorkerHandler = BackgroundThread.getHandler();
         mPackageCleanup = this::rescheduleCleanup;
         loadFromFile();
     }
@@ -115,7 +121,7 @@
         mContext = context;
         mPolicyFile = new AtomicFile(new File(context.getFilesDir(), "package-watchdog.xml"));
         mTimerHandler = new Handler(looper);
-        mIoHandler = mTimerHandler;
+        mWorkerHandler = mTimerHandler;
         mPackageCleanup = this::rescheduleCleanup;
         loadFromFile();
     }
@@ -228,49 +234,46 @@
     /**
      * Called when a process fails either due to a crash or ANR.
      *
-     * <p>All registered observers for the packages contained in the process will be notified in
-     * order of priority until an observer signifies that it has taken action and other observers
-     * should not notified.
+     * <p>For each package contained in the process, one registered observer with the least user
+     * impact will be notified for mitigation.
      *
      * <p>This method could be called frequently if there is a severe problem on the device.
      */
     public void onPackageFailure(String[] packages) {
-        ArrayMap<String, List<PackageHealthObserver>> packagesToReport = new ArrayMap<>();
-        synchronized (mLock) {
-            if (mAllObservers.isEmpty()) {
-                return;
-            }
+        mWorkerHandler.post(() -> {
+            synchronized (mLock) {
+                if (mAllObservers.isEmpty()) {
+                    return;
+                }
 
-            for (int pIndex = 0; pIndex < packages.length; pIndex++) {
-                // Observers interested in receiving packageName failures
-                List<PackageHealthObserver> observersToNotify = new ArrayList<>();
-                for (int oIndex = 0; oIndex < mAllObservers.size(); oIndex++) {
-                    PackageHealthObserver registeredObserver =
-                            mAllObservers.valueAt(oIndex).mRegisteredObserver;
-                    if (registeredObserver != null) {
-                        observersToNotify.add(registeredObserver);
+                for (int pIndex = 0; pIndex < packages.length; pIndex++) {
+                    String packageToReport = packages[pIndex];
+                    // Observer that will receive failure for packageToReport
+                    PackageHealthObserver currentObserverToNotify = null;
+                    int currentObserverImpact = Integer.MAX_VALUE;
+
+                    // Find observer with least user impact
+                    for (int oIndex = 0; oIndex < mAllObservers.size(); oIndex++) {
+                        ObserverInternal observer = mAllObservers.valueAt(oIndex);
+                        PackageHealthObserver registeredObserver = observer.mRegisteredObserver;
+                        if (registeredObserver != null
+                                && observer.onPackageFailure(packageToReport)) {
+                            int impact = registeredObserver.onHealthCheckFailed(packageToReport);
+                            if (impact != PackageHealthObserverImpact.USER_IMPACT_NONE
+                                    && impact < currentObserverImpact) {
+                                currentObserverToNotify = registeredObserver;
+                                currentObserverImpact = impact;
+                            }
+                        }
+                    }
+
+                    // Execute action with least user impact
+                    if (currentObserverToNotify != null) {
+                        currentObserverToNotify.execute(packageToReport);
                     }
                 }
-                // Save interested observers and notify them outside the lock
-                if (!observersToNotify.isEmpty()) {
-                    packagesToReport.put(packages[pIndex], observersToNotify);
-                }
             }
-        }
-
-        // Notify observers
-        for (int pIndex = 0; pIndex < packagesToReport.size(); pIndex++) {
-            List<PackageHealthObserver> observers = packagesToReport.valueAt(pIndex);
-            String packageName = packages[pIndex];
-            for (int oIndex = 0; oIndex < observers.size(); oIndex++) {
-                PackageHealthObserver observer = observers.get(oIndex);
-                if (mAllObservers.get(observer.getName()).onPackageFailure(packageName)
-                        && observer.onHealthCheckFailed(packageName)) {
-                    // Observer has handled, do not notify others
-                    break;
-                }
-            }
-        }
+        });
     }
 
     // TODO(zezeozue): Optimize write? Maybe only write a separate smaller file?
@@ -278,21 +281,46 @@
     /** Writes the package information to file during shutdown. */
     public void writeNow() {
         if (!mAllObservers.isEmpty()) {
-            mIoHandler.removeCallbacks(this::saveToFile);
+            mWorkerHandler.removeCallbacks(this::saveToFile);
             pruneObservers(SystemClock.uptimeMillis() - mUptimeAtLastRescheduleMs);
             saveToFile();
             Slog.i(TAG, "Last write to update package durations");
         }
     }
 
+    /** Possible severity values of the user impact of a {@link PackageHealthObserver#execute}. */
+    @Retention(SOURCE)
+    @IntDef(value = {PackageHealthObserverImpact.USER_IMPACT_NONE,
+                     PackageHealthObserverImpact.USER_IMPACT_LOW,
+                     PackageHealthObserverImpact.USER_IMPACT_MEDIUM,
+                     PackageHealthObserverImpact.USER_IMPACT_HIGH})
+    public @interface PackageHealthObserverImpact {
+        /** No action to take. */
+        int USER_IMPACT_NONE = 0;
+        /* Action has low user impact, user of a device will barely notice. */
+        int USER_IMPACT_LOW = 1;
+        /* Action has medium user impact, user of a device will likely notice. */
+        int USER_IMPACT_MEDIUM = 3;
+        /* Action has high user impact, a last resort, user of a device will be very frustrated. */
+        int USER_IMPACT_HIGH = 5;
+    }
+
     /** Register instances of this interface to receive notifications on package failure. */
     public interface PackageHealthObserver {
         /**
          * Called when health check fails for the {@code packageName}.
-         * @return {@code true} if action was taken and other observers should not be notified of
-         * this failure, {@code false} otherwise.
+         *
+         * @return any one of {@link PackageHealthObserverImpact} to express the impact
+         * to the user on {@link #execute}
          */
-        boolean onHealthCheckFailed(String packageName);
+        @PackageHealthObserverImpact int onHealthCheckFailed(String packageName);
+
+        /**
+         * Executes mitigation for {@link #onHealthCheckFailed}.
+         *
+         * @return {@code true} if action was executed successfully, {@code false} otherwise
+         */
+        boolean execute(String packageName);
 
         // TODO(zezeozue): Ensure uniqueness?
         /**
@@ -442,8 +470,8 @@
     }
 
     private void saveToFileAsync() {
-        mIoHandler.removeCallbacks(this::saveToFile);
-        mIoHandler.post(this::saveToFile);
+        mWorkerHandler.removeCallbacks(this::saveToFile);
+        mWorkerHandler.post(this::saveToFile);
     }
 
     /**
@@ -606,7 +634,11 @@
             } else {
                 mFailures++;
             }
-            return mFailures >= TRIGGER_FAILURE_COUNT;
+            boolean failed = mFailures >= TRIGGER_FAILURE_COUNT;
+            if (failed) {
+                mFailures = 0;
+            }
+            return failed;
         }
     }
 }
diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java
index cec825f..cecd55a3 100644
--- a/services/core/java/com/android/server/StorageManagerService.java
+++ b/services/core/java/com/android/server/StorageManagerService.java
@@ -802,10 +802,7 @@
         // For now, simply clone property when it changes
         DeviceConfig.addOnPropertyChangedListener(DeviceConfig.Storage.NAMESPACE,
                 mContext.getMainExecutor(), (namespace, name, value) -> {
-                    if (DeviceConfig.Storage.ISOLATED_STORAGE_ENABLED.equals(name)) {
-                        Settings.Global.putString(mResolver,
-                                Settings.Global.ISOLATED_STORAGE_REMOTE, value);
-                    }
+                    refreshIsolatedStorageSettings();
                 });
         refreshIsolatedStorageSettings();
     }
@@ -840,6 +837,12 @@
     }
 
     private void refreshIsolatedStorageSettings() {
+        // 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));
+
         final int local = Settings.Global.getInt(mContext.getContentResolver(),
                 Settings.Global.ISOLATED_STORAGE_LOCAL, 0);
         final int remote = Settings.Global.getInt(mContext.getContentResolver(),
diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java
index e543617..10b126f 100644
--- a/services/core/java/com/android/server/TelephonyRegistry.java
+++ b/services/core/java/com/android/server/TelephonyRegistry.java
@@ -206,9 +206,10 @@
 
     private Map<Integer, List<EmergencyNumber>> mEmergencyNumberList;
 
-    private CallQuality mCallQuality;
+    private CallQuality mCallQuality = new CallQuality();
 
-    private CallAttributes mCallAttributes;
+    private CallAttributes mCallAttributes = new CallAttributes(new PreciseCallState(),
+            TelephonyManager.NETWORK_TYPE_UNKNOWN, new CallQuality());
 
     private int[] mSrvccState;
 
diff --git a/services/core/java/com/android/server/am/ActivityManagerDebugConfig.java b/services/core/java/com/android/server/am/ActivityManagerDebugConfig.java
index 0aaea2f..e42666c 100644
--- a/services/core/java/com/android/server/am/ActivityManagerDebugConfig.java
+++ b/services/core/java/com/android/server/am/ActivityManagerDebugConfig.java
@@ -48,6 +48,7 @@
     static final boolean DEBUG_BROADCAST = DEBUG_ALL || false;
     static final boolean DEBUG_BROADCAST_BACKGROUND = DEBUG_BROADCAST || false;
     static final boolean DEBUG_BROADCAST_LIGHT = DEBUG_BROADCAST || false;
+    static final boolean DEBUG_BROADCAST_DEFERRAL = DEBUG_BROADCAST || false;
     static final boolean DEBUG_LRU = DEBUG_ALL || false;
     static final boolean DEBUG_MU = DEBUG_ALL || false;
     static final boolean DEBUG_NETWORK = DEBUG_ALL || false;
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index eb643b6..d9f3c02 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -224,7 +224,6 @@
 import android.location.LocationManager;
 import android.media.audiofx.AudioEffect;
 import android.net.Proxy;
-import android.net.ProxyInfo;
 import android.net.Uri;
 import android.os.AppZygote;
 import android.os.BatteryStats;
@@ -2090,6 +2089,8 @@
             if (phase == PHASE_SYSTEM_SERVICES_READY) {
                 mService.mBatteryStatsService.systemServicesReady();
                 mService.mServices.systemServicesReady();
+            } else if (phase == PHASE_ACTIVITY_MANAGER_READY) {
+                mService.startBroadcastObservers();
             }
         }
 
@@ -2266,12 +2267,27 @@
         mProcessList.init(this, activeUids);
         mOomAdjuster = new OomAdjuster(this, mProcessList, activeUids);
 
+        // Broadcast policy parameters
+        final BroadcastConstants foreConstants = new BroadcastConstants(
+                Settings.Global.BROADCAST_FG_CONSTANTS);
+        foreConstants.TIMEOUT = BROADCAST_FG_TIMEOUT;
+
+        final BroadcastConstants backConstants = new BroadcastConstants(
+                Settings.Global.BROADCAST_BG_CONSTANTS);
+        backConstants.TIMEOUT = BROADCAST_BG_TIMEOUT;
+
+        final BroadcastConstants offloadConstants = new BroadcastConstants(
+                Settings.Global.BROADCAST_OFFLOAD_CONSTANTS);
+        offloadConstants.TIMEOUT = BROADCAST_BG_TIMEOUT;
+        // by default, no "slow" policy in this queue
+        offloadConstants.SLOW_TIME = Integer.MAX_VALUE;
+
         mFgBroadcastQueue = new BroadcastQueue(this, mHandler,
-                "foreground", BROADCAST_FG_TIMEOUT, false);
+                "foreground", foreConstants, false);
         mBgBroadcastQueue = new BroadcastQueue(this, mHandler,
-                "background", BROADCAST_BG_TIMEOUT, true);
+                "background", backConstants, true);
         mOffloadBroadcastQueue = new BroadcastQueue(this, mHandler,
-                "offload", BROADCAST_BG_TIMEOUT, true);
+                "offload", offloadConstants, true);
         mBroadcastQueues[0] = mFgBroadcastQueue;
         mBroadcastQueues[1] = mBgBroadcastQueue;
         mBroadcastQueues[2] = mOffloadBroadcastQueue;
@@ -5226,6 +5242,15 @@
     }
 
     @Override
+    public boolean isIntentSenderABroadcast(IIntentSender pendingResult) {
+        if (pendingResult instanceof PendingIntentRecord) {
+            final PendingIntentRecord res = (PendingIntentRecord) pendingResult;
+            return res.key.type == ActivityManager.INTENT_SENDER_BROADCAST;
+        }
+        return false;
+    }
+
+    @Override
     public Intent getIntentForIntentSender(IIntentSender pendingResult) {
         enforceCallingPermission(Manifest.permission.GET_INTENT_SENDER_INTENT,
                 "getIntentForIntentSender()");
@@ -7211,7 +7236,6 @@
         synchronized (this) {
             mSystemProvidersInstalled = true;
         }
-
         mConstants.start(mContext.getContentResolver());
         mCoreSettingsObserver = new CoreSettingsObserver(this);
         mActivityTaskManager.installSystemProviders();
@@ -8711,6 +8735,12 @@
         }
     }
 
+    private void startBroadcastObservers() {
+        for (BroadcastQueue queue : mBroadcastQueues) {
+            queue.start(mContext.getContentResolver());
+        }
+    }
+
     private void updateForceBackgroundCheck(boolean enabled) {
         synchronized (this) {
             if (mForceBackgroundCheck != enabled) {
@@ -14909,10 +14939,7 @@
                     resultData, resultExtras, ordered, sticky, false, userId,
                     allowBackgroundActivityStarts);
 
-            if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Enqueueing ordered broadcast " + r
-                    + ": prev had " + queue.mOrderedBroadcasts.size());
-            if (DEBUG_BROADCAST) Slog.i(TAG_BROADCAST,
-                    "Enqueueing broadcast " + r.intent.getAction());
+            if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Enqueueing ordered broadcast " + r);
 
             final BroadcastRecord oldRecord =
                     replacePending ? queue.replaceOrderedBroadcastLocked(r) : null;
@@ -15788,13 +15815,12 @@
      * Returns true if things are idle enough to perform GCs.
      */
     private final boolean canGcNowLocked() {
-        boolean processingBroadcasts = false;
         for (BroadcastQueue q : mBroadcastQueues) {
-            if (q.mParallelBroadcasts.size() != 0 || q.mOrderedBroadcasts.size() != 0) {
-                processingBroadcasts = true;
+            if (!q.mParallelBroadcasts.isEmpty() || !q.mDispatcher.isEmpty()) {
+                return false;
             }
         }
-        return !processingBroadcasts && mAtmInternal.canGcNow();
+        return mAtmInternal.canGcNow();
     }
 
     /**
diff --git a/services/core/java/com/android/server/am/BroadcastConstants.java b/services/core/java/com/android/server/am/BroadcastConstants.java
new file mode 100644
index 0000000..820caf1
--- /dev/null
+++ b/services/core/java/com/android/server/am/BroadcastConstants.java
@@ -0,0 +1,151 @@
+/*
+ * 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.server.am;
+
+import android.content.ContentResolver;
+import android.database.ContentObserver;
+import android.os.Handler;
+import android.provider.Settings;
+import android.util.KeyValueListParser;
+import android.util.Slog;
+import android.util.TimeUtils;
+
+import java.io.PrintWriter;
+
+/**
+ * Tunable parameters for broadcast dispatch policy
+ */
+public class BroadcastConstants {
+    private static final String TAG = "BroadcastConstants";
+
+    // Value element names within the Settings record
+    static final String KEY_TIMEOUT = "bcast_timeout";
+    static final String KEY_SLOW_TIME = "bcast_slow_time";
+    static final String KEY_DEFERRAL = "bcast_deferral";
+    static final String KEY_DEFERRAL_DECAY_FACTOR = "bcast_deferral_decay_factor";
+    static final String KEY_DEFERRAL_FLOOR = "bcast_deferral_floor";
+
+    // All time intervals are in milliseconds
+    private static final long DEFAULT_TIMEOUT = 10_000;
+    private static final long DEFAULT_SLOW_TIME = 5_000;
+    private static final long DEFAULT_DEFERRAL = 5_000;
+    private static final float DEFAULT_DEFERRAL_DECAY_FACTOR = 0.75f;
+    private static final long DEFAULT_DEFERRAL_FLOOR = 0;
+
+    // All time constants are in milliseconds
+
+    // Timeout period for this broadcast queue
+    public long TIMEOUT = DEFAULT_TIMEOUT;
+    // Handling time above which we declare that a broadcast recipient was "slow".  Any
+    // value <= zero is interpreted as disabling broadcast deferral policy entirely.
+    public long SLOW_TIME = DEFAULT_SLOW_TIME;
+    // How long to initially defer broadcasts, if an app is slow to handle one
+    public long DEFERRAL = DEFAULT_DEFERRAL;
+    // Decay factor for successive broadcasts' deferral time
+    public float DEFERRAL_DECAY_FACTOR = DEFAULT_DEFERRAL_DECAY_FACTOR;
+    // Minimum that the deferral time can decay to until the backlog fully clears
+    public long DEFERRAL_FLOOR = DEFAULT_DEFERRAL_FLOOR;
+
+    // Settings override tracking for this instance
+    private String mSettingsKey;
+    private SettingsObserver mSettingsObserver;
+    private ContentResolver mResolver;
+    private final KeyValueListParser mParser = new KeyValueListParser(',');
+
+    class SettingsObserver extends ContentObserver {
+        SettingsObserver(Handler handler) {
+            super(handler);
+        }
+
+        @Override
+        public void onChange(boolean selfChange) {
+            updateConstants();
+        }
+    }
+
+    // A given constants instance is configured to observe specific keys from which
+    // that instance's values are drawn.
+    public BroadcastConstants(String settingsKey) {
+        mSettingsKey = settingsKey;
+    }
+
+    /**
+     * Spin up the observer lazily, since it can only happen once the settings provider
+     * has been brought into service
+     */
+    public void startObserving(Handler handler, ContentResolver resolver) {
+        mResolver = resolver;
+
+        mSettingsObserver = new SettingsObserver(handler);
+        mResolver.registerContentObserver(Settings.Global.getUriFor(mSettingsKey),
+                false, mSettingsObserver);
+
+        updateConstants();
+    }
+
+    private void updateConstants() {
+        synchronized (mParser) {
+            try {
+                mParser.setString(Settings.Global.getString(mResolver, mSettingsKey));
+            } catch (IllegalArgumentException e) {
+                Slog.e(TAG, "Bad broadcast settings in key '" + mSettingsKey + "'", e);
+                return;
+            }
+
+            // Unspecified fields retain their current value rather than revert to default
+            TIMEOUT = mParser.getLong(KEY_TIMEOUT, TIMEOUT);
+            SLOW_TIME = mParser.getLong(KEY_SLOW_TIME, SLOW_TIME);
+            DEFERRAL = mParser.getLong(KEY_DEFERRAL, DEFERRAL);
+            DEFERRAL_DECAY_FACTOR = mParser.getFloat(KEY_DEFERRAL_DECAY_FACTOR,
+                    DEFERRAL_DECAY_FACTOR);
+            DEFERRAL_FLOOR = mParser.getLong(KEY_DEFERRAL_FLOOR, DEFERRAL_FLOOR);
+        }
+    }
+
+    /**
+     * Standard dumpsys support; invoked from BroadcastQueue dump
+     */
+    public void dump(PrintWriter pw) {
+        synchronized (mParser) {
+            pw.println();
+            pw.print("  Broadcast parameters (key=");
+            pw.print(mSettingsKey);
+            pw.print(", observing=");
+            pw.print(mSettingsObserver != null);
+            pw.println("):");
+
+            pw.print("    "); pw.print(KEY_TIMEOUT); pw.print(" = ");
+            TimeUtils.formatDuration(TIMEOUT, pw);
+            pw.println();
+
+            pw.print("    "); pw.print(KEY_SLOW_TIME); pw.print(" = ");
+            TimeUtils.formatDuration(SLOW_TIME, pw);
+            pw.println();
+
+            pw.print("    "); pw.print(KEY_DEFERRAL); pw.print(" = ");
+            TimeUtils.formatDuration(DEFERRAL, pw);
+            pw.println();
+
+            pw.print("    "); pw.print(KEY_DEFERRAL_DECAY_FACTOR); pw.print(" = ");
+            pw.println(DEFERRAL_DECAY_FACTOR);
+
+            pw.print("    "); pw.print(KEY_DEFERRAL_FLOOR); pw.print(" = ");
+            TimeUtils.formatDuration(DEFERRAL_FLOOR, pw);
+            pw.println();
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/am/BroadcastDispatcher.java b/services/core/java/com/android/server/am/BroadcastDispatcher.java
new file mode 100644
index 0000000..0d46379
--- /dev/null
+++ b/services/core/java/com/android/server/am/BroadcastDispatcher.java
@@ -0,0 +1,687 @@
+/*
+ * 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.server.am;
+
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_BROADCAST;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_BROADCAST_DEFERRAL;
+
+import android.content.Intent;
+import android.os.Handler;
+import android.os.SystemClock;
+import android.util.Slog;
+import android.util.SparseIntArray;
+import android.util.proto.ProtoOutputStream;
+
+import com.android.server.AlarmManagerInternal;
+import com.android.server.LocalServices;
+
+import java.io.PrintWriter;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Set;
+
+/**
+ * Manages ordered broadcast delivery, applying policy to mitigate the effects of
+ * slow receivers.
+ */
+public class BroadcastDispatcher {
+    private static final String TAG = "BroadcastDispatcher";
+
+    // Deferred broadcasts to one app; times are all uptime time base like
+    // other broadcast-related timekeeping
+    static class Deferrals {
+        final int uid;
+        long deferredAt;    // when we started deferring
+        long deferredBy;    // how long did we defer by last time?
+        long deferUntil;    // when does the next element become deliverable?
+        int alarmCount;
+
+        final ArrayList<BroadcastRecord> broadcasts;
+
+        Deferrals(int uid, long now, long backoff, int count) {
+            this.uid = uid;
+            this.deferredAt = now;
+            this.deferredBy = backoff;
+            this.deferUntil = now + backoff;
+            this.alarmCount = count;
+            broadcasts = new ArrayList<>();
+        }
+
+        void add(BroadcastRecord br) {
+            broadcasts.add(br);
+        }
+
+        void writeToProto(ProtoOutputStream proto, long fieldId) {
+            for (BroadcastRecord br : broadcasts) {
+                br.writeToProto(proto, fieldId);
+            }
+        }
+
+        void dumpLocked(Dumper d) {
+            for (BroadcastRecord br : broadcasts) {
+                d.dump(br);
+            }
+        }
+
+        @Override
+        public String toString() {
+            StringBuilder sb = new StringBuilder(128);
+            sb.append("Deferrals{uid=");
+            sb.append(uid);
+            sb.append(", deferUntil=");
+            sb.append(deferUntil);
+            sb.append(", #broadcasts=");
+            sb.append(broadcasts.size());
+            sb.append("}");
+            return sb.toString();
+        }
+    }
+
+    // Carrying dump formatting state across multiple concatenated datasets
+    class Dumper {
+        final PrintWriter mPw;
+        final String mQueueName;
+        final String mDumpPackage;
+        final SimpleDateFormat mSdf;
+        boolean mPrinted;
+        boolean mNeedSep;
+        String mHeading;
+        String mLabel;
+        int mOrdinal;
+
+        Dumper(PrintWriter pw, String queueName, String dumpPackage, SimpleDateFormat sdf) {
+            mPw = pw;
+            mQueueName = queueName;
+            mDumpPackage = dumpPackage;
+            mSdf = sdf;
+
+            mPrinted = false;
+            mNeedSep = true;
+        }
+
+        void setHeading(String heading) {
+            mHeading = heading;
+            mPrinted = false;
+        }
+
+        void setLabel(String label) {
+            //"  Active Ordered Broadcast " + mQueueName + " #" + i + ":"
+            mLabel = "  " + label + " " + mQueueName + " #";
+            mOrdinal = 0;
+        }
+
+        boolean didPrint() {
+            return mPrinted;
+        }
+
+        void dump(BroadcastRecord br) {
+            if (mDumpPackage == null || mDumpPackage.equals(br.callerPackage)) {
+                if (!mPrinted) {
+                    if (mNeedSep) {
+                        mPw.println();
+                    }
+                    mPrinted = true;
+                    mNeedSep = true;
+                    mPw.println("  " + mHeading + " [" + mQueueName + "]:");
+                }
+                mPw.println(mLabel + mOrdinal + ":");
+                mOrdinal++;
+
+                br.dump(mPw, "    ", mSdf);
+            }
+        }
+    }
+
+    private final Object mLock;
+    private final BroadcastQueue mQueue;
+    private final BroadcastConstants mConstants;
+    private final Handler mHandler;
+    private AlarmManagerInternal mAlarm;
+
+    // Current alarm targets; mapping uid -> in-flight alarm count
+    final SparseIntArray mAlarmUids = new SparseIntArray();
+    final AlarmManagerInternal.InFlightListener mAlarmListener =
+            new AlarmManagerInternal.InFlightListener() {
+        @Override
+        public void broadcastAlarmPending(final int recipientUid) {
+            synchronized (mLock) {
+                final int newCount = mAlarmUids.get(recipientUid, 0) + 1;
+                mAlarmUids.put(recipientUid, newCount);
+                // any deferred broadcasts to this app now get fast-tracked
+                final int numEntries = mDeferredBroadcasts.size();
+                for (int i = 0; i < numEntries; i++) {
+                    if (recipientUid == mDeferredBroadcasts.get(i).uid) {
+                        Deferrals d = mDeferredBroadcasts.remove(i);
+                        mAlarmBroadcasts.add(d);
+                        break;
+                    }
+                }
+            }
+        }
+
+        @Override
+        public void broadcastAlarmComplete(final int recipientUid) {
+            synchronized (mLock) {
+                final int newCount = mAlarmUids.get(recipientUid, 0) - 1;
+                if (newCount >= 0) {
+                    mAlarmUids.put(recipientUid, newCount);
+                } else {
+                    Slog.wtf(TAG, "Undercount of broadcast alarms in flight for " + recipientUid);
+                    mAlarmUids.put(recipientUid, 0);
+                }
+
+                // No longer an alarm target, so resume ordinary deferral policy
+                if (newCount <= 0) {
+                    final int numEntries = mAlarmBroadcasts.size();
+                    for (int i = 0; i < numEntries; i++) {
+                        if (recipientUid == mAlarmBroadcasts.get(i).uid) {
+                            Deferrals d = mAlarmBroadcasts.remove(i);
+                            insertLocked(mDeferredBroadcasts, d);
+                            break;
+                        }
+                    }
+                }
+            }
+        }
+    };
+
+    // Queue recheck operation used to tickle broadcast delivery when appropriate
+    final Runnable mScheduleRunnable = new Runnable() {
+        @Override
+        public void run() {
+            synchronized (mLock) {
+                if (DEBUG_BROADCAST_DEFERRAL) {
+                    Slog.v(TAG, "Deferral recheck of pending broadcasts");
+                }
+                mQueue.scheduleBroadcastsLocked();
+                mRecheckScheduled = false;
+            }
+        }
+    };
+    private boolean mRecheckScheduled = false;
+
+    // Usual issuance-order outbound queue
+    private final ArrayList<BroadcastRecord> mOrderedBroadcasts = new ArrayList<>();
+    // General deferrals not holding up alarms
+    private final ArrayList<Deferrals> mDeferredBroadcasts = new ArrayList<>();
+    // Deferrals that *are* holding up alarms; ordered by alarm dispatch time
+    private final ArrayList<Deferrals> mAlarmBroadcasts = new ArrayList<>();
+
+    // Next outbound broadcast, established by getNextBroadcastLocked()
+    private BroadcastRecord mCurrentBroadcast;
+
+    /**
+     * Constructed & sharing a lock with its associated BroadcastQueue instance
+     */
+    public BroadcastDispatcher(BroadcastQueue queue, BroadcastConstants constants,
+            Handler handler, Object lock) {
+        mQueue = queue;
+        mConstants = constants;
+        mHandler = handler;
+        mLock = lock;
+    }
+
+    /**
+     * Spin up the integration with the alarm manager service; done lazily to manage
+     * service availability ordering during boot.
+     */
+    public void start() {
+        // Set up broadcast alarm tracking
+        mAlarm = LocalServices.getService(AlarmManagerInternal.class);
+        mAlarm.registerInFlightListener(mAlarmListener);
+    }
+
+    /**
+     * Standard contents-are-empty check
+     */
+    public boolean isEmpty() {
+        synchronized (mLock) {
+            return mCurrentBroadcast == null
+                    && mOrderedBroadcasts.isEmpty()
+                    && mDeferredBroadcasts.isEmpty()
+                    && mAlarmBroadcasts.isEmpty();
+        }
+    }
+
+    /**
+     * Not quite the traditional size() measurement; includes any in-process but
+     * not yet retired active outbound broadcast.
+     */
+    public int totalUndelivered() {
+        synchronized (mLock) {
+            return mAlarmBroadcasts.size()
+                    + mDeferredBroadcasts.size()
+                    + mOrderedBroadcasts.size()
+                    + (mCurrentBroadcast == null ? 0 : 1);
+        }
+    }
+
+    // ----------------------------------
+    // BroadcastQueue operation support
+
+    void enqueueOrderedBroadcastLocked(BroadcastRecord r) {
+        mOrderedBroadcasts.add(r);
+    }
+
+    // Returns the now-replaced broadcast record, or null if none
+    BroadcastRecord replaceBroadcastLocked(BroadcastRecord r, String typeForLogging) {
+        // Simple case, in the ordinary queue.
+        BroadcastRecord old = replaceBroadcastLocked(mOrderedBroadcasts, r, typeForLogging);
+
+        // If we didn't find it, less-simple:  in a deferral queue?
+        if (old == null) {
+            old = replaceDeferredBroadcastLocked(mAlarmBroadcasts, r, typeForLogging);
+        }
+        if (old == null) {
+            old = replaceDeferredBroadcastLocked(mDeferredBroadcasts, r, typeForLogging);
+        }
+        return old;
+    }
+
+    private BroadcastRecord replaceDeferredBroadcastLocked(ArrayList<Deferrals> list,
+            BroadcastRecord r, String typeForLogging) {
+        BroadcastRecord old;
+        final int numEntries = list.size();
+        for (int i = 0; i < numEntries; i++) {
+            final Deferrals d = list.get(i);
+            old = replaceBroadcastLocked(d.broadcasts, r, typeForLogging);
+            if (old != null) {
+                return old;
+            }
+        }
+        return null;
+    }
+
+    private BroadcastRecord replaceBroadcastLocked(ArrayList<BroadcastRecord> list,
+            BroadcastRecord r, String typeForLogging) {
+        BroadcastRecord old;
+        final Intent intent = r.intent;
+        // Any in-flight broadcast has already been popped, and cannot be replaced.
+        // (This preserves existing behavior of the replacement API)
+        for (int i = list.size() - 1; i >= 0; i++) {
+            old = list.get(i);
+            if (old.userId == r.userId && intent.filterEquals(old.intent)) {
+                if (DEBUG_BROADCAST) {
+                    Slog.v(TAG, "***** Replacing " + typeForLogging
+                            + " [" + mQueue.mQueueName + "]: " + intent);
+                }
+                // Clone deferral state too if any
+                r.deferred = old.deferred;
+                list.set(i, r);
+                return old;
+            }
+        }
+        return null;
+    }
+
+    boolean cleanupDisabledPackageReceiversLocked(final String packageName,
+            Set<String> filterByClasses, final int userId, final boolean doit) {
+        // Note: fast short circuits when 'doit' is false, as soon as we hit any
+        // "yes we would do something" circumstance
+        boolean didSomething = cleanupBroadcastListDisabledReceiversLocked(mOrderedBroadcasts,
+                packageName, filterByClasses, userId, doit);
+        if (doit || !didSomething) {
+            didSomething |= cleanupDeferralsListDisabledReceiversLocked(mAlarmBroadcasts,
+                    packageName, filterByClasses, userId, doit);
+        }
+        if (doit || !didSomething) {
+            didSomething |= cleanupDeferralsListDisabledReceiversLocked(mDeferredBroadcasts,
+                    packageName, filterByClasses, userId, doit);
+        }
+        if ((doit || !didSomething) && mCurrentBroadcast != null) {
+            didSomething |= mCurrentBroadcast.cleanupDisabledPackageReceiversLocked(
+                    packageName, filterByClasses, userId, doit);
+        }
+
+        return didSomething;
+    }
+
+    private boolean cleanupDeferralsListDisabledReceiversLocked(ArrayList<Deferrals> list,
+            final String packageName, Set<String> filterByClasses, final int userId,
+            final boolean doit) {
+        boolean didSomething = false;
+        for (Deferrals d : list) {
+            didSomething = cleanupBroadcastListDisabledReceiversLocked(d.broadcasts,
+                    packageName, filterByClasses, userId, doit);
+            if (!doit && didSomething) {
+                return true;
+            }
+        }
+        return didSomething;
+    }
+
+    private boolean cleanupBroadcastListDisabledReceiversLocked(ArrayList<BroadcastRecord> list,
+            final String packageName, Set<String> filterByClasses, final int userId,
+            final boolean doit) {
+        boolean didSomething = false;
+        for (BroadcastRecord br : list) {
+            didSomething |= br.cleanupDisabledPackageReceiversLocked(packageName,
+                    filterByClasses, userId, doit);
+            if (!doit && didSomething) {
+                return true;
+            }
+        }
+        return didSomething;
+    }
+
+    /**
+     * Standard proto dump entry point
+     */
+    public void writeToProto(ProtoOutputStream proto, long fieldId) {
+        if (mCurrentBroadcast != null) {
+            mCurrentBroadcast.writeToProto(proto, fieldId);
+        }
+        for (Deferrals d : mAlarmBroadcasts) {
+            d.writeToProto(proto, fieldId);
+        }
+        for (BroadcastRecord br : mOrderedBroadcasts) {
+            br.writeToProto(proto, fieldId);
+        }
+        for (Deferrals d : mDeferredBroadcasts) {
+            d.writeToProto(proto, fieldId);
+        }
+    }
+
+    // ----------------------------------
+    // Dispatch & deferral management
+
+    public BroadcastRecord getActiveBroadcastLocked() {
+        return mCurrentBroadcast;
+    }
+
+    /**
+     * If there is a deferred broadcast that is being sent to an alarm target, return
+     * that one.  If there's no deferred alarm target broadcast but there is one
+     * that has reached the end of its deferral, return that.
+     *
+     * This stages the broadcast internally until it is retired, and returns that
+     * staged record if this is called repeatedly, until retireBroadcast(r) is called.
+     */
+    public BroadcastRecord getNextBroadcastLocked(final long now) {
+        if (mCurrentBroadcast != null) {
+            return mCurrentBroadcast;
+        }
+
+        BroadcastRecord next = null;
+        if (!mAlarmBroadcasts.isEmpty()) {
+            next = popLocked(mAlarmBroadcasts);
+            if (DEBUG_BROADCAST_DEFERRAL && next != null) {
+                Slog.i(TAG, "Next broadcast from alarm targets: " + next);
+            }
+        }
+
+        if (next == null && !mDeferredBroadcasts.isEmpty()) {
+            for (int i = 0; i < mDeferredBroadcasts.size(); i++) {
+                Deferrals d = mDeferredBroadcasts.get(i);
+                if (now < d.deferUntil) {
+                    // No more deferrals due
+                    break;
+                }
+
+                if (d.broadcasts.size() > 0) {
+                    next = d.broadcasts.remove(0);
+                    // apply deferral-interval decay policy and move this uid's
+                    // deferred broadcasts down in the delivery queue accordingly
+                    mDeferredBroadcasts.remove(i); // already 'd'
+                    d.deferredBy = calculateDeferral(d.deferredBy);
+                    d.deferUntil += d.deferredBy;
+                    insertLocked(mDeferredBroadcasts, d);
+                    if (DEBUG_BROADCAST_DEFERRAL) {
+                        Slog.i(TAG, "Next broadcast from deferrals " + next
+                                + ", deferUntil now " + d.deferUntil);
+                    }
+                    break;
+                }
+            }
+        }
+
+        if (next == null && !mOrderedBroadcasts.isEmpty()) {
+            next = mOrderedBroadcasts.remove(0);
+            if (DEBUG_BROADCAST_DEFERRAL) {
+                Slog.i(TAG, "Next broadcast from main queue: " + next);
+            }
+        }
+
+        mCurrentBroadcast = next;
+        return next;
+    }
+
+    /**
+     * Called after the broadcast queue finishes processing the currently
+     * active broadcast (obtained by calling getNextBroadcastLocked()).
+     */
+    public void retireBroadcastLocked(final BroadcastRecord r) {
+        // ERROR if 'r' is not the active broadcast
+        if (r != mCurrentBroadcast) {
+            Slog.wtf(TAG, "Retiring broadcast " + r
+                    + " doesn't match current outgoing " + mCurrentBroadcast);
+        }
+        mCurrentBroadcast = null;
+    }
+
+    /**
+     * Called prior to broadcast dispatch to check whether the intended
+     * recipient is currently subject to deferral policy.
+     */
+    public boolean isDeferringLocked(final int uid) {
+        Deferrals d = findUidLocked(uid);
+        if (d != null && d.broadcasts.isEmpty()) {
+            // once we've caught up with deferred broadcasts to this uid
+            // and time has advanced sufficiently that we wouldn't be
+            // deferring newly-enqueued ones, we're back to normal policy.
+            if (SystemClock.uptimeMillis() >= d.deferUntil) {
+                if (DEBUG_BROADCAST_DEFERRAL) {
+                    Slog.i(TAG, "No longer deferring broadcasts to uid " + d.uid);
+                }
+                removeDeferral(d);
+                return false;
+            }
+        }
+        return (d != null);
+    }
+
+    /**
+     * Defer broadcasts for the given app.  If 'br' is non-null, this also makes
+     * sure that broadcast record is enqueued as the next upcoming broadcast for
+     * the app.
+     */
+    public void startDeferring(final int uid) {
+        synchronized (mLock) {
+            Deferrals d = findUidLocked(uid);
+
+            // If we're not yet tracking this app, set up that bookkeeping
+            if (d == null) {
+                // Start a new deferral
+                final long now = SystemClock.uptimeMillis();
+                d = new Deferrals(uid,
+                        now,
+                        mConstants.DEFERRAL,
+                        mAlarmUids.get(uid, 0));
+                if (DEBUG_BROADCAST_DEFERRAL) {
+                    Slog.i(TAG, "Now deferring broadcasts to " + uid
+                            + " until " + d.deferUntil);
+                }
+                // where it goes depends on whether it is coming into an alarm-related situation
+                if (d.alarmCount == 0) {
+                    // common case, put it in the ordinary priority queue
+                    insertLocked(mDeferredBroadcasts, d);
+                    scheduleDeferralCheckLocked(true);
+                } else {
+                    // alarm-related: strict order-encountered
+                    mAlarmBroadcasts.add(d);
+                }
+            } else {
+                // We're already deferring, but something was slow again.  Reset the
+                // deferral decay progression.
+                d.deferredBy = mConstants.DEFERRAL;
+                if (DEBUG_BROADCAST_DEFERRAL) {
+                    Slog.i(TAG, "Uid " + uid + " slow again, deferral interval reset to "
+                            + d.deferredBy);
+                }
+            }
+        }
+    }
+
+    /**
+     * Key entry point when a broadcast about to be delivered is instead
+     * set aside for deferred delivery
+     */
+    public void addDeferredBroadcast(final int uid, BroadcastRecord br) {
+        if (DEBUG_BROADCAST_DEFERRAL) {
+            Slog.i(TAG, "Enqueuing deferred broadcast " + br);
+        }
+        synchronized (mLock) {
+            Deferrals d = findUidLocked(uid);
+            if (d == null) {
+                Slog.wtf(TAG, "Adding deferred broadcast but not tracking " + uid);
+            } else {
+                if (br == null) {
+                    Slog.wtf(TAG, "Deferring null broadcast to " + uid);
+                } else {
+                    br.deferred = true;
+                    d.add(br);
+                }
+            }
+        }
+    }
+
+    /**
+     * When there are deferred broadcasts, we need to make sure to recheck the
+     * dispatch queue when they come due.  Alarm-sensitive deferrals get dispatched
+     * aggressively, so we only need to use the ordinary deferrals timing to figure
+     * out when to recheck.
+     */
+    public void scheduleDeferralCheckLocked(boolean force) {
+        if ((force || !mRecheckScheduled) && !mDeferredBroadcasts.isEmpty()) {
+            final Deferrals d = mDeferredBroadcasts.get(0);
+            if (!d.broadcasts.isEmpty()) {
+                mHandler.removeCallbacks(mScheduleRunnable);
+                mHandler.postAtTime(mScheduleRunnable, d.deferUntil);
+                mRecheckScheduled = true;
+                if (DEBUG_BROADCAST_DEFERRAL) {
+                    Slog.i(TAG, "Scheduling deferred broadcast recheck at " + d.deferUntil);
+                }
+            }
+        }
+    }
+
+    // ----------------------------------
+
+    /**
+     * If broadcasts to this uid are being deferred, find the deferrals record about it.
+     * @return null if this uid's broadcasts are not being deferred
+     */
+    private Deferrals findUidLocked(final int uid) {
+        // The common case is that they it isn't also an alarm target...
+        Deferrals d = findUidLocked(uid, mDeferredBroadcasts);
+        // ...but if not there, also check alarm-prioritized deferrals
+        if (d == null) {
+            d = findUidLocked(uid, mAlarmBroadcasts);
+        }
+        return d;
+    }
+
+    /**
+     * Remove the given deferral record from whichever queue it might be in at present
+     * @return true if the deferral was in fact found, false if this made no changes
+     */
+    private boolean removeDeferral(Deferrals d) {
+        boolean didRemove = mDeferredBroadcasts.remove(d);
+        if (!didRemove) {
+            didRemove = mAlarmBroadcasts.remove(d);
+        }
+        return didRemove;
+    }
+
+    /**
+     * Find the deferrals record for the given uid in the given list
+     */
+    private static Deferrals findUidLocked(final int uid, ArrayList<Deferrals> list) {
+        final int numElements = list.size();
+        for (int i = 0; i < numElements; i++) {
+            Deferrals d = list.get(i);
+            if (uid == d.uid) {
+                return d;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Pop the next broadcast record from the head of the given deferrals list,
+     * if one exists.
+     */
+    private static BroadcastRecord popLocked(ArrayList<Deferrals> list) {
+        final Deferrals d = list.get(0);
+        return d.broadcasts.isEmpty() ? null : d.broadcasts.remove(0);
+    }
+
+    /**
+     * Insert the given Deferrals into the priority queue, sorted by defer-until milestone
+     */
+    private static void insertLocked(ArrayList<Deferrals> list, Deferrals d) {
+        // Simple linear search is appropriate here because we expect to
+        // have very few entries in the deferral lists (i.e. very few badly-
+        // behaving apps currently facing deferral)
+        int i;
+        final int numElements = list.size();
+        for (i = 0; i < numElements; i++) {
+            if (d.deferUntil < list.get(i).deferUntil) {
+                break;
+            }
+        }
+        list.add(i, d);
+    }
+
+    /**
+     * Calculate a new deferral time based on the previous time.  This should decay
+     * toward zero, though a small nonzero floor is an option.
+     */
+    private long calculateDeferral(long previous) {
+        return Math.max(mConstants.DEFERRAL_FLOOR,
+                (long) (previous * mConstants.DEFERRAL_DECAY_FACTOR));
+    }
+
+    // ----------------------------------
+
+    boolean dumpLocked(PrintWriter pw, String dumpPackage, String queueName,
+            SimpleDateFormat sdf) {
+        final Dumper dumper = new Dumper(pw, queueName, dumpPackage, sdf);
+        boolean printed = false;
+
+        dumper.setHeading("Active ordered broadcasts");
+        dumper.setLabel("Active Ordered Broadcast");
+        for (Deferrals d : mAlarmBroadcasts) {
+            d.dumpLocked(dumper);
+        }
+        printed |= dumper.didPrint();
+
+        for (BroadcastRecord br : mOrderedBroadcasts) {
+            dumper.dump(br);
+        }
+        printed |= dumper.didPrint();
+
+        dumper.setHeading("Deferred ordered broadcasts");
+        dumper.setLabel("Deferred Ordered Broadcast");
+        for (Deferrals d : mDeferredBroadcasts) {
+            d.dumpLocked(dumper);
+        }
+        printed |= dumper.didPrint();
+
+        return printed;
+    }
+}
diff --git a/services/core/java/com/android/server/am/BroadcastQueue.java b/services/core/java/com/android/server/am/BroadcastQueue.java
index cdf6e0e..64a36ef 100644
--- a/services/core/java/com/android/server/am/BroadcastQueue.java
+++ b/services/core/java/com/android/server/am/BroadcastQueue.java
@@ -24,6 +24,7 @@
 import android.app.BroadcastOptions;
 import android.app.PendingIntent;
 import android.content.ComponentName;
+import android.content.ContentResolver;
 import android.content.IIntentReceiver;
 import android.content.IIntentSender;
 import android.content.Intent;
@@ -45,6 +46,7 @@
 import android.os.UserHandle;
 import android.util.EventLog;
 import android.util.Slog;
+import android.util.SparseIntArray;
 import android.util.StatsLog;
 import android.util.TimeUtils;
 import android.util.proto.ProtoOutputStream;
@@ -75,16 +77,17 @@
     final ActivityManagerService mService;
 
     /**
+     * Behavioral parameters such as timeouts and deferral policy, tracking Settings
+     * for runtime configurability
+     */
+    final BroadcastConstants mConstants;
+
+    /**
      * Recognizable moniker for this queue
      */
     final String mQueueName;
 
     /**
-     * Timeout period for this queue's broadcasts
-     */
-    final long mTimeoutPeriod;
-
-    /**
      * If true, we can delay broadcasts while waiting services to finish in the previous
      * receiver's process.
      */
@@ -100,13 +103,18 @@
     final ArrayList<BroadcastRecord> mParallelBroadcasts = new ArrayList<>();
 
     /**
-     * List of all active broadcasts that are to be executed one at a time.
-     * The object at the top of the list is the currently activity broadcasts;
-     * those after it are waiting for the top to finish.  As with parallel
-     * broadcasts, separate background- and foreground-priority queues are
-     * maintained.
+     * Tracking of the ordered broadcast queue, including deferral policy and alarm
+     * prioritization.
      */
-    final ArrayList<BroadcastRecord> mOrderedBroadcasts = new ArrayList<>();
+    final BroadcastDispatcher mDispatcher;
+
+    /**
+     * Refcounting for completion callbacks of split/deferred broadcasts.  The key
+     * is an opaque integer token assigned lazily when a broadcast is first split
+     * into multiple BroadcastRecord objects.
+     */
+    final SparseIntArray mSplitRefcounts = new SparseIntArray();
+    private int mNextToken = 0;
 
     /**
      * Historical data of past broadcasts, for debugging.  This is a ring buffer
@@ -173,7 +181,8 @@
             switch (msg.what) {
                 case BROADCAST_INTENT_MSG: {
                     if (DEBUG_BROADCAST) Slog.v(
-                            TAG_BROADCAST, "Received BROADCAST_INTENT_MSG");
+                            TAG_BROADCAST, "Received BROADCAST_INTENT_MSG ["
+                            + mQueueName + "]");
                     processNextBroadcast(true);
                 } break;
                 case BROADCAST_TIMEOUT_MSG: {
@@ -201,12 +210,19 @@
     }
 
     BroadcastQueue(ActivityManagerService service, Handler handler,
-            String name, long timeoutPeriod, boolean allowDelayBehindServices) {
+            String name, BroadcastConstants constants, boolean allowDelayBehindServices) {
         mService = service;
         mHandler = new BroadcastHandler(handler.getLooper());
         mQueueName = name;
-        mTimeoutPeriod = timeoutPeriod;
         mDelayBehindServices = allowDelayBehindServices;
+
+        mConstants = constants;
+        mDispatcher = new BroadcastDispatcher(this, mConstants, mHandler, mService);
+    }
+
+    void start(ContentResolver resolver) {
+        mDispatcher.start();
+        mConstants.startObserving(mHandler, resolver);
     }
 
     @Override
@@ -224,7 +240,7 @@
     }
 
     public void enqueueOrderedBroadcastLocked(BroadcastRecord r) {
-        mOrderedBroadcasts.add(r);
+        mDispatcher.enqueueOrderedBroadcastLocked(r);
         enqueueBroadcastHelper(r);
     }
 
@@ -255,7 +271,7 @@
      * the old one.
      */
     public final BroadcastRecord replaceOrderedBroadcastLocked(BroadcastRecord r) {
-        return replaceBroadcastLocked(mOrderedBroadcasts, r, "ORDERED");
+        return mDispatcher.replaceBroadcastLocked(r, "ORDERED");
     }
 
     private BroadcastRecord replaceBroadcastLocked(ArrayList<BroadcastRecord> queue,
@@ -365,14 +381,17 @@
         }
     }
 
+    // Skip the current receiver, if any, that is in flight to the given process
     public void skipCurrentReceiverLocked(ProcessRecord app) {
         BroadcastRecord r = null;
-        if (mOrderedBroadcasts.size() > 0) {
-            BroadcastRecord br = mOrderedBroadcasts.get(0);
-            if (br.curApp == app) {
-                r = br;
-            }
+        final BroadcastRecord curActive = mDispatcher.getActiveBroadcastLocked();
+        if (curActive != null && curActive.curApp == app) {
+            // confirmed: the current active broadcast is to the given app
+            r = curActive;
         }
+
+        // If the current active broadcast isn't this BUT we're waiting for
+        // mPendingBroadcast to spin up the target app, that's what we use.
         if (r == null && mPendingBroadcast != null && mPendingBroadcast.curApp == app) {
             if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST,
                     "[" + mQueueName + "] skip & discard pending app " + r);
@@ -404,20 +423,29 @@
     }
 
     public BroadcastRecord getMatchingOrderedReceiver(IBinder receiver) {
-        if (mOrderedBroadcasts.size() > 0) {
-            final BroadcastRecord r = mOrderedBroadcasts.get(0);
-            if (r != null && r.receiver == receiver) {
-                return r;
-            }
+        BroadcastRecord br = mDispatcher.getActiveBroadcastLocked();
+        if (br != null && br.receiver == receiver) {
+            return br;
         }
         return null;
     }
 
+    // > 0 only, no worry about "eventual" recycling
+    private int nextSplitTokenLocked() {
+        int next = mNextToken + 1;
+        if (next <= 0) {
+            next = 1;
+        }
+        mNextToken = next;
+        return next;
+    }
+
     public boolean finishReceiverLocked(BroadcastRecord r, int resultCode,
             String resultData, Bundle resultExtras, boolean resultAbort, boolean waitForServices) {
         final int state = r.state;
         final ActivityInfo receiver = r.curReceiver;
         final long finishTime = SystemClock.uptimeMillis();
+        final long elapsed = finishTime - r.receiverTime;
         r.state = BroadcastRecord.IDLE;
         if (state == BroadcastRecord.IDLE) {
             Slog.w(TAG, "finishReceiver [" + mQueueName + "] called but state is IDLE");
@@ -428,8 +456,22 @@
         // If we're abandoning this broadcast before any receivers were actually spun up,
         // nextReceiver is zero; in which case time-to-process bookkeeping doesn't apply.
         if (r.nextReceiver > 0) {
-            r.duration[r.nextReceiver - 1] = finishTime - r.receiverTime;
+            r.duration[r.nextReceiver - 1] = elapsed;
         }
+
+        // if this receiver was slow, impose deferral policy on the app.  This will kick in
+        // when processNextBroadcastLocked() next finds this uid as a receiver identity.
+        if (mConstants.SLOW_TIME > 0 && elapsed > mConstants.SLOW_TIME) {
+            if (DEBUG_BROADCAST_DEFERRAL) {
+                Slog.i(TAG, "Broadcast receiver was slow: " + receiver + " br=" + r);
+            }
+            if (r.curApp != null) {
+                mDispatcher.startDeferring(r.curApp.uid);
+            } else {
+                Slog.d(TAG, "finish receiver curApp is null? " + r);
+            }
+        }
+
         r.receiver = null;
         r.intent.setComponent(null);
         if (r.curApp != null && r.curApp.curReceivers.contains(r)) {
@@ -452,9 +494,10 @@
             r.resultAbort = false;
         }
 
+        // If we want to wait behind services *AND* we're finishing the head/
+        // active broadcast on its queue
         if (waitForServices && r.curComponent != null && r.queue.mDelayBehindServices
-                && r.queue.mOrderedBroadcasts.size() > 0
-                && r.queue.mOrderedBroadcasts.get(0) == r) {
+                && r.queue.mDispatcher.getActiveBroadcastLocked() == r) {
             ActivityInfo nextReceiver;
             if (r.nextReceiver < r.receivers.size()) {
                 Object obj = r.receivers.get(r.nextReceiver);
@@ -488,8 +531,8 @@
     }
 
     public void backgroundServicesFinishedLocked(int userId) {
-        if (mOrderedBroadcasts.size() > 0) {
-            BroadcastRecord br = mOrderedBroadcasts.get(0);
+        BroadcastRecord br = mDispatcher.getActiveBroadcastLocked();
+        if (br != null) {
             if (br.userId == userId && br.state == BroadcastRecord.WAITING_SERVICES) {
                 Slog.i(TAG, "Resuming delayed broadcast");
                 br.curComponent = null;
@@ -861,7 +904,7 @@
         if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "processNextBroadcast ["
                 + mQueueName + "]: "
                 + mParallelBroadcasts.size() + " parallel broadcasts, "
-                + mOrderedBroadcasts.size() + " ordered broadcasts");
+                + mDispatcher.totalUndelivered() + " ordered broadcasts");
 
         mService.updateCpuStats();
 
@@ -937,8 +980,12 @@
         boolean looped = false;
 
         do {
-            if (mOrderedBroadcasts.size() == 0) {
-                // No more broadcasts pending, so all done!
+            final long now = SystemClock.uptimeMillis();
+            r = mDispatcher.getNextBroadcastLocked(now);
+
+            if (r == null) {
+                // No more broadcasts are deliverable right now, so all done!
+                mDispatcher.scheduleDeferralCheckLocked(false);
                 mService.scheduleAppGcsLocked();
                 if (looped) {
                     // If we had finished the last ordered broadcast, then
@@ -954,7 +1001,7 @@
 
                 return;
             }
-            r = mOrderedBroadcasts.get(0);
+
             boolean forceReceive = false;
 
             // Ensure that even if something goes awry with the timeout
@@ -967,9 +1014,8 @@
             // significant amounts of time.
             int numReceivers = (r.receivers != null) ? r.receivers.size() : 0;
             if (mService.mProcessesReady && r.dispatchTime > 0) {
-                long now = SystemClock.uptimeMillis();
                 if ((numReceivers > 0) &&
-                        (now > r.dispatchTime + (2*mTimeoutPeriod*numReceivers))) {
+                        (now > r.dispatchTime + (2 * mConstants.TIMEOUT * numReceivers))) {
                     Slog.w(TAG, "Hung broadcast ["
                             + mQueueName + "] discarded after timeout failure:"
                             + " now=" + now
@@ -993,27 +1039,53 @@
                 return;
             }
 
+            // Is the current broadcast is done for any reason?
             if (r.receivers == null || r.nextReceiver >= numReceivers
                     || r.resultAbort || forceReceive) {
-                // No more receivers for this broadcast!  Send the final
-                // result if requested...
+                // Send the final result if requested
                 if (r.resultTo != null) {
-                    try {
-                        if (DEBUG_BROADCAST) Slog.i(TAG_BROADCAST,
-                                "Finishing broadcast [" + mQueueName + "] "
-                                + r.intent.getAction() + " app=" + r.callerApp);
-                        performReceiveLocked(r.callerApp, r.resultTo,
-                            new Intent(r.intent), r.resultCode,
-                            r.resultData, r.resultExtras, false, false, r.userId);
-                        // Set this to null so that the reference
-                        // (local and remote) isn't kept in the mBroadcastHistory.
-                        r.resultTo = null;
-                    } catch (RemoteException e) {
-                        r.resultTo = null;
-                        Slog.w(TAG, "Failure ["
-                                + mQueueName + "] sending broadcast result of "
-                                + r.intent, e);
+                    boolean sendResult = true;
 
+                    // if this was part of a split/deferral complex, update the refcount and only
+                    // send the completion when we clear all of them
+                    if (r.splitToken != 0) {
+                        int newCount = mSplitRefcounts.get(r.splitToken) - 1;
+                        if (newCount == 0) {
+                            // done!  clear out this record's bookkeeping and deliver
+                            if (DEBUG_BROADCAST_DEFERRAL) {
+                                Slog.i(TAG, "Sending broadcast completion for split token "
+                                        + r.splitToken);
+                            }
+                            mSplitRefcounts.delete(r.splitToken);
+                        } else {
+                            // still have some split broadcast records in flight; update refcount
+                            // and hold off on the callback
+                            if (DEBUG_BROADCAST_DEFERRAL) {
+                                Slog.i(TAG, "Result refcount " + newCount + " for split token "
+                                        + r.splitToken + " - not sending completion yet");
+                            }
+                            sendResult = false;
+                            mSplitRefcounts.put(r.splitToken, newCount);
+                        }
+                    }
+                    if (sendResult) {
+                        try {
+                            if (DEBUG_BROADCAST) {
+                                Slog.i(TAG_BROADCAST, "Finishing broadcast [" + mQueueName + "] "
+                                        + r.intent.getAction() + " app=" + r.callerApp);
+                            }
+                            performReceiveLocked(r.callerApp, r.resultTo,
+                                    new Intent(r.intent), r.resultCode,
+                                    r.resultData, r.resultExtras, false, false, r.userId);
+                            // Set this to null so that the reference
+                            // (local and remote) isn't kept in the mBroadcastHistory.
+                            r.resultTo = null;
+                        } catch (RemoteException e) {
+                            r.resultTo = null;
+                            Slog.w(TAG, "Failure ["
+                                    + mQueueName + "] sending broadcast result of "
+                                    + r.intent, e);
+                        }
                     }
                 }
 
@@ -1031,11 +1103,76 @@
                     mService.addBroadcastStatLocked(r.intent.getAction(), r.callerPackage,
                             r.manifestCount, r.manifestSkipCount, r.finishTime-r.dispatchTime);
                 }
-                mOrderedBroadcasts.remove(0);
+                mDispatcher.retireBroadcastLocked(r);
                 r = null;
                 looped = true;
                 continue;
             }
+
+            // Check whether the next receiver is under deferral policy, and handle that
+            // accordingly.  If the current broadcast was already part of deferred-delivery
+            // tracking, we know that it must now be deliverable as-is without re-deferral.
+            if (!r.deferred) {
+                final int receiverUid = r.getReceiverUid(r.receivers.get(r.nextReceiver));
+                if (mDispatcher.isDeferringLocked(receiverUid)) {
+                    if (DEBUG_BROADCAST_DEFERRAL) {
+                        Slog.i(TAG_BROADCAST, "Next receiver in " + r + " uid " + receiverUid
+                                + " at " + r.nextReceiver + " is under deferral");
+                    }
+                    // If this is the only (remaining) receiver in the broadcast, "splitting"
+                    // doesn't make sense -- just defer it as-is and retire it as the
+                    // currently active outgoing broadcast.
+                    BroadcastRecord defer;
+                    if (r.nextReceiver + 1 == numReceivers) {
+                        if (DEBUG_BROADCAST_DEFERRAL) {
+                            Slog.i(TAG, "Sole receiver of " + r
+                                    + " is under deferral; setting aside and proceeding");
+                        }
+                        defer = r;
+                        mDispatcher.retireBroadcastLocked(r);
+                    } else {
+                        // Nontrivial case; split out 'uid's receivers to a new broadcast record
+                        // and defer that, then loop and pick up continuing delivery of the current
+                        // record (now absent those receivers).
+
+                        // The split operation is guaranteed to match at least at 'nextReceiver'
+                        defer = r.splitRecipientsLocked(receiverUid, r.nextReceiver);
+                        if (DEBUG_BROADCAST_DEFERRAL) {
+                            Slog.i(TAG_BROADCAST, "Post split:");
+                            Slog.i(TAG_BROADCAST, "Original broadcast receivers:");
+                            for (int i = 0; i < r.receivers.size(); i++) {
+                                Slog.i(TAG_BROADCAST, "  " + r.receivers.get(i));
+                            }
+                            Slog.i(TAG_BROADCAST, "Split receivers:");
+                            for (int i = 0; i < defer.receivers.size(); i++) {
+                                Slog.i(TAG_BROADCAST, "  " + defer.receivers.get(i));
+                            }
+                        }
+                        // Track completion refcount as well if relevant
+                        if (r.resultTo != null) {
+                            int token = r.splitToken;
+                            if (token == 0) {
+                                // first split of this record; refcount for 'r' and 'deferred'
+                                r.splitToken = defer.splitToken = nextSplitTokenLocked();
+                                mSplitRefcounts.put(r.splitToken, 2);
+                            } else {
+                                // new split from an already-refcounted situation; increment count
+                                final int curCount = mSplitRefcounts.get(token);
+                                if (DEBUG_BROADCAST_DEFERRAL) {
+                                    if (curCount == 0) {
+                                        Slog.wtf(TAG, "Split refcount is zero with token for " + r);
+                                    }
+                                }
+                                mSplitRefcounts.put(token, curCount + 1);
+                            }
+                        }
+                    }
+                    mDispatcher.addDeferredBroadcast(receiverUid, defer);
+                    r = null;
+                    looped = true;
+                    continue;
+                }
+            }
         } while (r == null);
 
         // Get the next receiver...
@@ -1066,7 +1203,7 @@
                     + mQueueName + "] " + r);
         }
         if (! mPendingBroadcastTimeoutMessage) {
-            long timeoutTime = r.receiverTime + mTimeoutPeriod;
+            long timeoutTime = r.receiverTime + mConstants.TIMEOUT;
             if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST,
                     "Submitting BROADCAST_TIMEOUT_MSG ["
                     + mQueueName + "] for " + r + " at " + timeoutTime);
@@ -1474,12 +1611,12 @@
             mPendingBroadcastTimeoutMessage = false;
         }
 
-        if (mOrderedBroadcasts.size() == 0) {
+        if (mDispatcher.isEmpty() || mDispatcher.getActiveBroadcastLocked() == null) {
             return;
         }
 
         long now = SystemClock.uptimeMillis();
-        BroadcastRecord r = mOrderedBroadcasts.get(0);
+        BroadcastRecord r = mDispatcher.getActiveBroadcastLocked();
         if (fromMsg) {
             if (!mService.mProcessesReady) {
                 // Only process broadcast timeouts if the system is ready. That way
@@ -1488,7 +1625,7 @@
                 return;
             }
 
-            long timeoutTime = r.receiverTime + mTimeoutPeriod;
+            long timeoutTime = r.receiverTime + mConstants.TIMEOUT;
             if (timeoutTime > now) {
                 // We can observe premature timeouts because we do not cancel and reset the
                 // broadcast timeout message after each receiver finishes.  Instead, we set up
@@ -1503,16 +1640,15 @@
             }
         }
 
-        BroadcastRecord br = mOrderedBroadcasts.get(0);
-        if (br.state == BroadcastRecord.WAITING_SERVICES) {
+        if (r.state == BroadcastRecord.WAITING_SERVICES) {
             // In this case the broadcast had already finished, but we had decided to wait
             // for started services to finish as well before going on.  So if we have actually
             // waited long enough time timeout the broadcast, let's give up on the whole thing
             // and just move on to the next.
-            Slog.i(TAG, "Waited long enough for: " + (br.curComponent != null
-                    ? br.curComponent.flattenToShortString() : "(null)"));
-            br.curComponent = null;
-            br.state = BroadcastRecord.IDLE;
+            Slog.i(TAG, "Waited long enough for: " + (r.curComponent != null
+                    ? r.curComponent.flattenToShortString() : "(null)"));
+            r.curComponent = null;
+            r.state = BroadcastRecord.IDLE;
             processNextBroadcast(false);
             return;
         }
@@ -1619,13 +1755,8 @@
             }
         }
 
-        for (int i = mOrderedBroadcasts.size() - 1; i >= 0; i--) {
-            didSomething |= mOrderedBroadcasts.get(i).cleanupDisabledPackageReceiversLocked(
-                    packageName, filterByClasses, userId, doit);
-            if (!doit && didSomething) {
-                return true;
-            }
-        }
+        didSomething |= mDispatcher.cleanupDisabledPackageReceiversLocked(packageName,
+                filterByClasses, userId, doit);
 
         return didSomething;
     }
@@ -1665,7 +1796,7 @@
     }
 
     final boolean isIdle() {
-        return mParallelBroadcasts.isEmpty() && mOrderedBroadcasts.isEmpty()
+        return mParallelBroadcasts.isEmpty() && mDispatcher.isEmpty()
                 && (mPendingBroadcast == null);
     }
 
@@ -1677,10 +1808,7 @@
         for (int i = N - 1; i >= 0; i--) {
             mParallelBroadcasts.get(i).writeToProto(proto, BroadcastQueueProto.PARALLEL_BROADCASTS);
         }
-        N = mOrderedBroadcasts.size();
-        for (int i = N - 1; i >= 0; i--) {
-            mOrderedBroadcasts.get(i).writeToProto(proto, BroadcastQueueProto.ORDERED_BROADCASTS);
-        }
+        mDispatcher.writeToProto(proto, BroadcastQueueProto.ORDERED_BROADCASTS);
         if (mPendingBroadcast != null) {
             mPendingBroadcast.writeToProto(proto, BroadcastQueueProto.PENDING_BROADCAST);
         }
@@ -1721,7 +1849,7 @@
     final boolean dumpLocked(FileDescriptor fd, PrintWriter pw, String[] args,
             int opti, boolean dumpAll, String dumpPackage, boolean needSep) {
         SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
-        if (mParallelBroadcasts.size() > 0 || mOrderedBroadcasts.size() > 0
+        if (!mParallelBroadcasts.isEmpty() || !mDispatcher.isEmpty()
                 || mPendingBroadcast != null) {
             boolean printed = false;
             for (int i = mParallelBroadcasts.size() - 1; i >= 0; i--) {
@@ -1740,29 +1868,12 @@
                 pw.println("  Active Broadcast " + mQueueName + " #" + i + ":");
                 br.dump(pw, "    ", sdf);
             }
-            printed = false;
-            needSep = true;
-            for (int i = mOrderedBroadcasts.size() - 1; i >= 0; i--) {
-                BroadcastRecord br = mOrderedBroadcasts.get(i);
-                if (dumpPackage != null && !dumpPackage.equals(br.callerPackage)) {
-                    continue;
-                }
-                if (!printed) {
-                    if (needSep) {
-                        pw.println();
-                    }
-                    needSep = true;
-                    printed = true;
-                    pw.println("  Active ordered broadcasts [" + mQueueName + "]:");
-                }
-                pw.println("  Active Ordered Broadcast " + mQueueName + " #" + i + ":");
-                mOrderedBroadcasts.get(i).dump(pw, "    ", sdf);
-            }
+
+            mDispatcher.dumpLocked(pw, dumpPackage, mQueueName, sdf);
+
             if (dumpPackage == null || (mPendingBroadcast != null
                     && dumpPackage.equals(mPendingBroadcast.callerPackage))) {
-                if (needSep) {
-                    pw.println();
-                }
+                pw.println();
                 pw.println("  Pending broadcast [" + mQueueName + "]:");
                 if (mPendingBroadcast != null) {
                     mPendingBroadcast.dump(pw, "    ", sdf);
@@ -1773,6 +1884,8 @@
             }
         }
 
+        mConstants.dump(pw);
+
         int i;
         boolean printed = false;
 
diff --git a/services/core/java/com/android/server/am/BroadcastRecord.java b/services/core/java/com/android/server/am/BroadcastRecord.java
index 9e799f6..d9e03f8 100644
--- a/services/core/java/com/android/server/am/BroadcastRecord.java
+++ b/services/core/java/com/android/server/am/BroadcastRecord.java
@@ -36,10 +36,12 @@
 
 import java.io.PrintWriter;
 import java.text.SimpleDateFormat;
+import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Date;
 import java.util.List;
 import java.util.Set;
+import java.util.concurrent.atomic.AtomicInteger;
 
 /**
  * An active intent broadcast.
@@ -64,6 +66,9 @@
     final int[] delivery;   // delivery state of each receiver
     final long[] duration;   // duration a receiver took to process broadcast
     IIntentReceiver resultTo; // who receives final result if non-null
+    boolean deferred;
+    int splitCount;         // refcount for result callback, when split
+    int splitToken;         // identifier for cross-BroadcastRecord refcount
     long enqueueClockTime;  // the clock time the broadcast was enqueued
     long dispatchTime;      // when dispatch started on this set of receivers
     long dispatchClockTime; // the clock time the dispatch started
@@ -106,6 +111,9 @@
     ComponentName curComponent; // the receiver class that is currently running.
     ActivityInfo curReceiver;   // info about the receiver that is currently running.
 
+    // Private refcount-management bookkeeping; start > 0
+    static AtomicInteger sNextToken = new AtomicInteger(1);
+
     void dump(PrintWriter pw, String prefix, SimpleDateFormat sdf) {
         final long now = SystemClock.uptimeMillis();
 
@@ -304,6 +312,52 @@
         allowBackgroundActivityStarts = from.allowBackgroundActivityStarts;
     }
 
+    /**
+     * Split off a new BroadcastRecord that clones this one, but contains only the
+     * recipient records for the current (just-finished) receiver's app, starting
+     * after the just-finished receiver [i.e. at r.nextReceiver].  Returns null
+     * if there are no matching subsequent receivers in this BroadcastRecord.
+     */
+    BroadcastRecord splitRecipientsLocked(int slowAppUid, int startingAt) {
+        // Do we actually have any matching receivers down the line...?
+        ArrayList splitReceivers = null;
+        for (int i = startingAt; i < receivers.size(); ) {
+            Object o = receivers.get(i);
+            if (getReceiverUid(o) == slowAppUid) {
+                if (splitReceivers == null) {
+                    splitReceivers = new ArrayList<>();
+                }
+                splitReceivers.add(o);
+                receivers.remove(i);
+                break;
+            } else {
+                i++;
+            }
+        }
+
+        // No later receivers in the same app, so we have no more to do
+        if (splitReceivers == null) {
+            return null;
+        }
+
+        // build a new BroadcastRecord around that single-target list
+        BroadcastRecord split = new BroadcastRecord(queue, intent, callerApp,
+                callerPackage, callingPid, callingUid, callerInstantApp, resolvedType,
+                requiredPermissions, appOp, options, splitReceivers, resultTo, resultCode,
+                resultData, resultExtras, ordered, sticky, initialSticky, userId,
+                allowBackgroundActivityStarts);
+
+        return split;
+    }
+
+    int getReceiverUid(Object receiver) {
+        if (receiver instanceof BroadcastFilter) {
+            return ((BroadcastFilter) receiver).owningUid;
+        } else /* if (receiver instanceof ResolveInfo) */ {
+            return ((ResolveInfo) receiver).activityInfo.applicationInfo.uid;
+        }
+    }
+
     public BroadcastRecord maybeStripForHistory() {
         if (!intent.canStripForHistory()) {
             return this;
diff --git a/services/core/java/com/android/server/appop/AppOpsService.java b/services/core/java/com/android/server/appop/AppOpsService.java
index 7ede6dc..26d2d17 100644
--- a/services/core/java/com/android/server/appop/AppOpsService.java
+++ b/services/core/java/com/android/server/appop/AppOpsService.java
@@ -16,8 +16,8 @@
 
 package com.android.server.appop;
 
-import static android.app.AppOpsManager.OP_PLAY_AUDIO;
 import static android.app.AppOpsManager.OP_NONE;
+import static android.app.AppOpsManager.OP_PLAY_AUDIO;
 import static android.app.AppOpsManager.UID_STATE_BACKGROUND;
 import static android.app.AppOpsManager.UID_STATE_CACHED;
 import static android.app.AppOpsManager.UID_STATE_FOREGROUND;
@@ -94,9 +94,9 @@
 import com.android.internal.util.Preconditions;
 import com.android.internal.util.XmlUtils;
 import com.android.internal.util.function.pooled.PooledLambda;
-
 import com.android.server.LocalServices;
 import com.android.server.LockGuard;
+
 import libcore.util.EmptyArray;
 
 import org.xmlpull.v1.XmlPullParser;
@@ -1282,6 +1282,46 @@
         }
     }
 
+    /**
+     * Set all {@link #setMode (package) modes} for this uid to the default value.
+     *
+     * @param code The app-op
+     * @param uid The uid
+     */
+    private void setAllPkgModesToDefault(int code, int uid) {
+        synchronized (this) {
+            UidState uidState = getUidStateLocked(uid, false);
+            if (uidState == null) {
+                return;
+            }
+
+            ArrayMap<String, Ops> pkgOps = uidState.pkgOps;
+            if (pkgOps == null) {
+                return;
+            }
+
+            int numPkgs = pkgOps.size();
+            for (int pkgNum = 0; pkgNum < numPkgs; pkgNum++) {
+                Ops ops = pkgOps.valueAt(pkgNum);
+
+                Op op = ops.get(code);
+                if (op == null) {
+                    continue;
+                }
+
+                int defaultMode = AppOpsManager.opToDefaultMode(code);
+                if (op.mode != defaultMode) {
+                    Slog.w(TAG, "resetting app-op mode for " + AppOpsManager.opToName(code) + " of "
+                            + pkgOps.keyAt(pkgNum));
+
+                    op.mode = defaultMode;
+
+                    scheduleWriteLocked();
+                }
+            }
+        }
+    }
+
     @Override
     public void setMode(int code, int uid, String packageName, int mode) {
         setMode(code, uid, packageName, mode, true, false);
@@ -4387,5 +4427,10 @@
         public void setUidMode(int code, int uid, int mode) {
             AppOpsService.this.setUidMode(code, uid, mode);
         }
+
+        @Override
+        public void setAllPkgModesToDefault(int code, int uid) {
+            AppOpsService.this.setAllPkgModesToDefault(code, uid);
+        }
     }
 }
diff --git a/services/core/java/com/android/server/attention/AttentionManagerService.java b/services/core/java/com/android/server/attention/AttentionManagerService.java
index b71a751..5b469fe 100644
--- a/services/core/java/com/android/server/attention/AttentionManagerService.java
+++ b/services/core/java/com/android/server/attention/AttentionManagerService.java
@@ -16,6 +16,10 @@
 
 package com.android.server.attention;
 
+import static android.provider.DeviceConfig.AttentionManagerService.NAMESPACE;
+import static android.provider.DeviceConfig.AttentionManagerService.PROPERTY_COMPONENT_NAME;
+import static android.provider.DeviceConfig.AttentionManagerService.PROPERTY_SERVICE_ENABLED;
+
 import android.Manifest;
 import android.annotation.Nullable;
 import android.annotation.UserIdInt;
@@ -40,6 +44,7 @@
 import android.os.RemoteException;
 import android.os.SystemClock;
 import android.os.UserHandle;
+import android.provider.DeviceConfig;
 import android.service.attention.AttentionService;
 import android.service.attention.AttentionService.AttentionFailureCodes;
 import android.service.attention.IAttentionCallback;
@@ -66,6 +71,9 @@
 public class AttentionManagerService extends SystemService {
     private static final String LOG_TAG = "AttentionManagerService";
 
+    /** Default value in absence of {@link DeviceConfig} override. */
+    private static final boolean DEFAULT_SERVICE_ENABLED = true;
+
     /** Service will unbind if connection is not used for that amount of time. */
     private static final long CONNECTION_TTL_MILLIS = 60_000;
 
@@ -105,7 +113,7 @@
         super.onBootPhase(phase);
         if (phase == SystemService.PHASE_THIRD_PARTY_APPS_CAN_START) {
             mComponentName = resolveAttentionService(mContext);
-            if (mComponentName != null) {
+            if (isAttentionServiceSupported()) {
                 // If the service is supported we want to keep receiving the screen off events.
                 mContext.registerReceiver(new ScreenStateReceiver(),
                         new IntentFilter(Intent.ACTION_SCREEN_OFF));
@@ -117,7 +125,12 @@
      * Returns {@code true} if attention service is supported on this device.
      */
     public boolean isAttentionServiceSupported() {
-        return mComponentName != null;
+        return mComponentName != null && isServiceEnabled();
+    }
+
+    private boolean isServiceEnabled() {
+        final String enabled = DeviceConfig.getProperty(NAMESPACE, PROPERTY_SERVICE_ENABLED);
+        return enabled == null ? DEFAULT_SERVICE_ENABLED : "true".equals(enabled);
     }
 
     /**
@@ -266,8 +279,9 @@
      * system.
      */
     private static ComponentName resolveAttentionService(Context context) {
-        // TODO(b/111939367): add a flag to turn on/off.
-        final String componentNameString = context.getString(
+        final String flag = DeviceConfig.getProperty(NAMESPACE, PROPERTY_COMPONENT_NAME);
+
+        final String componentNameString = flag != null ? flag : context.getString(
                 R.string.config_defaultAttentionService);
 
         if (TextUtils.isEmpty(componentNameString)) {
diff --git a/services/core/java/com/android/server/biometrics/BiometricServiceBase.java b/services/core/java/com/android/server/biometrics/BiometricServiceBase.java
index 174ecfa..2791165 100644
--- a/services/core/java/com/android/server/biometrics/BiometricServiceBase.java
+++ b/services/core/java/com/android/server/biometrics/BiometricServiceBase.java
@@ -279,7 +279,7 @@
         }
     }
 
-    protected class EnrollClientImpl extends EnrollClient {
+    protected abstract class EnrollClientImpl extends EnrollClient {
 
         public EnrollClientImpl(Context context, DaemonWrapper daemon, long halDeviceId,
                 IBinder token, ServiceListener listener, int userId, int groupId,
diff --git a/services/core/java/com/android/server/biometrics/EnrollClient.java b/services/core/java/com/android/server/biometrics/EnrollClient.java
index 8a0f085..3ff94bc 100644
--- a/services/core/java/com/android/server/biometrics/EnrollClient.java
+++ b/services/core/java/com/android/server/biometrics/EnrollClient.java
@@ -36,6 +36,8 @@
     private final BiometricUtils mBiometricUtils;
     private final int[] mDisabledFeatures;
 
+    public abstract boolean shouldVibrate();
+
     public EnrollClient(Context context, Metrics metrics,
             BiometricServiceBase.DaemonWrapper daemon, long halDeviceId, IBinder token,
             BiometricServiceBase.ServiceListener listener, int userId, int groupId,
@@ -62,7 +64,9 @@
      */
     private boolean sendEnrollResult(BiometricAuthenticator.Identifier identifier,
             int remaining) {
-        vibrateSuccess();
+        if (shouldVibrate()) {
+            vibrateSuccess();
+        }
         mMetricsLogger.action(mMetrics.actionBiometricEnroll());
         try {
             getListener().onEnrollResult(identifier, remaining);
diff --git a/services/core/java/com/android/server/biometrics/face/FaceService.java b/services/core/java/com/android/server/biometrics/face/FaceService.java
index a2aacdd..d4be539 100644
--- a/services/core/java/com/android/server/biometrics/face/FaceService.java
+++ b/services/core/java/com/android/server/biometrics/face/FaceService.java
@@ -121,7 +121,12 @@
             final boolean restricted = isRestricted();
             final EnrollClientImpl client = new EnrollClientImpl(getContext(), mDaemonWrapper,
                     mHalDeviceId, token, new ServiceListenerImpl(receiver), mCurrentUserId,
-                    0 /* groupId */, cryptoToken, restricted, opPackageName, disabledFeatures);
+                    0 /* groupId */, cryptoToken, restricted, opPackageName, disabledFeatures) {
+                @Override
+                public boolean shouldVibrate() {
+                    return false;
+                }
+            };
 
             enrollInternal(client, UserHandle.getCallingUserId());
         }
diff --git a/services/core/java/com/android/server/biometrics/fingerprint/FingerprintService.java b/services/core/java/com/android/server/biometrics/fingerprint/FingerprintService.java
index fcf821f2..f84cda03 100644
--- a/services/core/java/com/android/server/biometrics/fingerprint/FingerprintService.java
+++ b/services/core/java/com/android/server/biometrics/fingerprint/FingerprintService.java
@@ -142,7 +142,12 @@
             final int groupId = userId; // default group for fingerprint enrollment
             final EnrollClientImpl client = new EnrollClientImpl(getContext(), mDaemonWrapper,
                     mHalDeviceId, token, new ServiceListenerImpl(receiver), mCurrentUserId, groupId,
-                    cryptoToken, restricted, opPackageName, new int[0] /* disabledFeatures */);
+                    cryptoToken, restricted, opPackageName, new int[0] /* disabledFeatures */) {
+                @Override
+                public boolean shouldVibrate() {
+                    return true;
+                }
+            };
 
             enrollInternal(client, userId);
         }
diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java
index 62a1b03..2508844 100644
--- a/services/core/java/com/android/server/connectivity/Vpn.java
+++ b/services/core/java/com/android/server/connectivity/Vpn.java
@@ -151,7 +151,7 @@
                 .divide(BigInteger.valueOf(100));
     }
     // How many routes to evaluate before bailing and declaring this Vpn should provide
-    // the INTERNET capability. This is necessary because computing the adress space is
+    // the INTERNET capability. This is necessary because computing the address space is
     // O(n²) and this is running in the system service, so a limit is needed to alleviate
     // the risk of attack.
     // This is taken as a total of IPv4 + IPV6 routes for simplicity, but the algorithm
@@ -194,6 +194,12 @@
     private boolean mLockdown = false;
 
     /**
+     * Set of packages in addition to the VPN app itself that can access the network directly when
+     * VPN is not connected even if {@code mLockdown} is set.
+     */
+    private @NonNull List<String> mLockdownWhitelist = Collections.emptyList();
+
+    /**
      * List of UIDs for which networking should be blocked until VPN is ready, during brief periods
      * when VPN is not running. For example, during system startup or after a crash.
      * @see mLockdown
@@ -320,9 +326,9 @@
      *
      * Used to enable/disable legacy VPN lockdown.
      *
-     * This uses the same ip rule mechanism as {@link #setAlwaysOnPackage(String, boolean)};
-     * previous settings from calling that function will be replaced and saved with the
-     * always-on state.
+     * This uses the same ip rule mechanism as
+     * {@link #setAlwaysOnPackage(String, boolean, List<String>)}; previous settings from calling
+     * that function will be replaced and saved with the always-on state.
      *
      * @param lockdown whether to prevent all traffic outside of a VPN.
      */
@@ -419,12 +425,14 @@
      *
      * @param packageName the package to designate as always-on VPN supplier.
      * @param lockdown whether to prevent traffic outside of a VPN, for example while connecting.
+     * @param lockdownWhitelist packages to be whitelisted from lockdown.
      * @return {@code true} if the package has been set as always-on, {@code false} otherwise.
      */
-    public synchronized boolean setAlwaysOnPackage(String packageName, boolean lockdown) {
+    public synchronized boolean setAlwaysOnPackage(
+            String packageName, boolean lockdown, List<String> lockdownWhitelist) {
         enforceControlPermissionOrInternalCaller();
 
-        if (setAlwaysOnPackageInternal(packageName, lockdown)) {
+        if (setAlwaysOnPackageInternal(packageName, lockdown, lockdownWhitelist)) {
             saveAlwaysOnPackage();
             return true;
         }
@@ -439,15 +447,27 @@
      *
      * @param packageName the package to designate as always-on VPN supplier.
      * @param lockdown whether to prevent traffic outside of a VPN, for example while connecting.
+     * @param lockdownWhitelist packages to be whitelisted from lockdown. This is only used if
+     *        {@code lockdown} is {@code true}. Packages must not contain commas.
      * @return {@code true} if the package has been set as always-on, {@code false} otherwise.
      */
     @GuardedBy("this")
-    private boolean setAlwaysOnPackageInternal(String packageName, boolean lockdown) {
+    private boolean setAlwaysOnPackageInternal(
+            String packageName, boolean lockdown, List<String> lockdownWhitelist) {
         if (VpnConfig.LEGACY_VPN.equals(packageName)) {
             Log.w(TAG, "Not setting legacy VPN \"" + packageName + "\" as always-on.");
             return false;
         }
 
+        if (lockdownWhitelist != null) {
+            for (String pkg : lockdownWhitelist) {
+                if (pkg.contains(",")) {
+                    Log.w(TAG, "Not setting always-on vpn, invalid whitelisted package: " + pkg);
+                    return false;
+                }
+            }
+        }
+
         if (packageName != null) {
             // Pre-authorize new always-on VPN package.
             if (!setPackageAuthorization(packageName, true)) {
@@ -460,13 +480,18 @@
         }
 
         mLockdown = (mAlwaysOn && lockdown);
+        mLockdownWhitelist = (mLockdown && lockdownWhitelist != null)
+                ? Collections.unmodifiableList(new ArrayList<>(lockdownWhitelist))
+                : Collections.emptyList();
+
         if (isCurrentPreparedPackage(packageName)) {
             updateAlwaysOnNotification(mNetworkInfo.getDetailedState());
+            setVpnForcedLocked(mLockdown);
         } else {
             // Prepare this app. The notification will update as a side-effect of updateState().
+            // It also calls setVpnForcedLocked().
             prepareInternal(packageName);
         }
-        setVpnForcedLocked(mLockdown);
         return true;
     }
 
@@ -478,7 +503,6 @@
      * @return the package name of the VPN controller responsible for always-on VPN,
      *         or {@code null} if none is set or always-on VPN is controlled through
      *         lockdown instead.
-     * @hide
      */
     public synchronized String getAlwaysOnPackage() {
         enforceControlPermissionOrInternalCaller();
@@ -486,6 +510,13 @@
     }
 
     /**
+     * @return an immutable list of packages whitelisted from always-on VPN lockdown.
+     */
+    public synchronized List<String> getLockdownWhitelist() {
+        return mLockdown ? mLockdownWhitelist : null;
+    }
+
+    /**
      * Save the always-on package and lockdown config into Settings.Secure
      */
     @GuardedBy("this")
@@ -496,6 +527,9 @@
                     getAlwaysOnPackage(), mUserHandle);
             mSystemServices.settingsSecurePutIntForUser(Settings.Secure.ALWAYS_ON_VPN_LOCKDOWN,
                     (mAlwaysOn && mLockdown ? 1 : 0), mUserHandle);
+            mSystemServices.settingsSecurePutStringForUser(
+                    Settings.Secure.ALWAYS_ON_VPN_LOCKDOWN_WHITELIST,
+                    String.join(",", mLockdownWhitelist), mUserHandle);
         } finally {
             Binder.restoreCallingIdentity(token);
         }
@@ -512,7 +546,11 @@
                     Settings.Secure.ALWAYS_ON_VPN_APP, mUserHandle);
             final boolean alwaysOnLockdown = mSystemServices.settingsSecureGetIntForUser(
                     Settings.Secure.ALWAYS_ON_VPN_LOCKDOWN, 0 /*default*/, mUserHandle) != 0;
-            setAlwaysOnPackageInternal(alwaysOnPackage, alwaysOnLockdown);
+            final String whitelistString = mSystemServices.settingsSecureGetStringForUser(
+                    Settings.Secure.ALWAYS_ON_VPN_LOCKDOWN_WHITELIST, mUserHandle);
+            final List<String> whitelistedPackages = TextUtils.isEmpty(whitelistString)
+                    ? Collections.emptyList() : Arrays.asList(whitelistString.split(","));
+            setAlwaysOnPackageInternal(alwaysOnPackage, alwaysOnLockdown, whitelistedPackages);
         } finally {
             Binder.restoreCallingIdentity(token);
         }
@@ -532,7 +570,7 @@
             }
             // Remove always-on VPN if it's not supported.
             if (!isAlwaysOnPackageSupported(alwaysOnPackage)) {
-                setAlwaysOnPackage(null, false);
+                setAlwaysOnPackage(null, false, null);
                 return false;
             }
             // Skip if the service is already established. This isn't bulletproof: it's not bound
@@ -1249,9 +1287,10 @@
     }
 
     /**
-     * Restrict network access from all UIDs affected by this {@link Vpn}, apart from the VPN
-     * service app itself, to only sockets that have had {@code protect()} called on them. All
-     * non-VPN traffic is blocked via a {@code PROHIBIT} response from the kernel.
+     * Restricts network access from all UIDs affected by this {@link Vpn}, apart from the VPN
+     * service app itself and whitelisted packages, to only sockets that have had {@code protect()}
+     * called on them. All non-VPN traffic is blocked via a {@code PROHIBIT} response from the
+     * kernel.
      *
      * The exception for the VPN UID isn't technically necessary -- setup should use protected
      * sockets -- but in practice it saves apps that don't protect their sockets from breaking.
@@ -1267,8 +1306,13 @@
      */
     @GuardedBy("this")
     private void setVpnForcedLocked(boolean enforce) {
-        final List<String> exemptedPackages =
-                isNullOrLegacyVpn(mPackage) ? null : Collections.singletonList(mPackage);
+        final List<String> exemptedPackages;
+        if (isNullOrLegacyVpn(mPackage)) {
+            exemptedPackages = null;
+        } else {
+            exemptedPackages = new ArrayList<>(mLockdownWhitelist);
+            exemptedPackages.add(mPackage);
+        }
         final Set<UidRange> removedRanges = new ArraySet<>(mBlockedUsers);
 
         Set<UidRange> addedRanges = Collections.emptySet();
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index 4db541c..d20508a 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -17,9 +17,6 @@
 
 import static android.view.Display.DEFAULT_DISPLAY;
 import static android.view.Display.INVALID_DISPLAY;
-import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_SHOW_FOR_ALL_USERS;
-import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
-import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG;
 import static android.view.inputmethod.InputMethodSystemProperty.PER_PROFILE_IME_ENABLED;
 
 import static java.lang.annotation.RetentionPolicy.SOURCE;
@@ -110,7 +107,7 @@
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.Window;
-import android.view.WindowManager;
+import android.view.WindowManager.LayoutParams;
 import android.view.WindowManager.LayoutParams.SoftInputModeFlags;
 import android.view.inputmethod.EditorInfo;
 import android.view.inputmethod.InputBinding;
@@ -207,6 +204,8 @@
     static final int MSG_SET_ACTIVE = 3020;
     static final int MSG_SET_INTERACTIVE = 3030;
     static final int MSG_REPORT_FULLSCREEN_MODE = 3045;
+    static final int MSG_REPORT_PRE_RENDERED = 3060;
+    static final int MSG_APPLY_IME_VISIBILITY = 3070;
 
     static final int MSG_HARD_KEYBOARD_SWITCH_CHANGED = 4000;
 
@@ -481,7 +480,7 @@
     IBinder mLastImeTargetWindow;
 
     /**
-     * {@link WindowManager.LayoutParams#softInputMode} of {@link #mCurFocusedWindow}.
+     * {@link LayoutParams#softInputMode} of {@link #mCurFocusedWindow}.
      *
      * @see #mCurFocusedWindow
      */
@@ -2040,7 +2039,8 @@
                     Slog.v(TAG, "Adding window token: " + mCurToken + " for display: "
                             + mCurTokenDisplayId);
                 }
-                mIWindowManager.addWindowToken(mCurToken, TYPE_INPUT_METHOD, mCurTokenDisplayId);
+                mIWindowManager.addWindowToken(mCurToken, LayoutParams.TYPE_INPUT_METHOD,
+                        mCurTokenDisplayId);
             } catch (RemoteException e) {
             }
             return new InputBindResult(
@@ -2755,9 +2755,34 @@
             Slog.e(TAG, "windowToken cannot be null.");
             return InputBindResult.NULL;
         }
-        final InputBindResult result = startInputOrWindowGainedFocusInternal(startInputReason,
-                client, windowToken, startInputFlags, softInputMode, windowFlags, attribute,
-                inputContext, missingMethods, unverifiedTargetSdkVersion);
+        final int callingUserId = UserHandle.getCallingUserId();
+        final int userId;
+        if (attribute != null && attribute.targetInputMethodUser != null
+                && attribute.targetInputMethodUser.getIdentifier() != callingUserId) {
+            mContext.enforceCallingPermission(Manifest.permission.INTERACT_ACROSS_USERS_FULL,
+                    "Using EditorInfo.targetInputMethodUser requires INTERACT_ACROSS_USERS_FULL.");
+            userId = attribute.targetInputMethodUser.getIdentifier();
+            if (!mUserManagerInternal.isUserRunning(userId)) {
+                // There is a chance that we hit here because of race condition.  Let's just return
+                // an error code instead of crashing the caller process, which at least has
+                // INTERACT_ACROSS_USERS_FULL permission thus is likely to be an important process.
+                Slog.e(TAG, "User #" + userId + " is not running.");
+                return InputBindResult.INVALID_USER;
+            }
+        } else {
+            userId = callingUserId;
+        }
+        final InputBindResult result;
+        synchronized (mMethodMap) {
+            final long ident = Binder.clearCallingIdentity();
+            try {
+                result = startInputOrWindowGainedFocusInternalLocked(startInputReason, client,
+                        windowToken, startInputFlags, softInputMode, windowFlags, attribute,
+                        inputContext, missingMethods, unverifiedTargetSdkVersion, userId);
+            } finally {
+                Binder.restoreCallingIdentity(ident);
+            }
+        }
         if (result == null) {
             // This must never happen, but just in case.
             Slog.wtf(TAG, "InputBindResult is @NonNull. startInputReason="
@@ -2770,242 +2795,212 @@
     }
 
     @NonNull
-    private InputBindResult startInputOrWindowGainedFocusInternal(
+    private InputBindResult startInputOrWindowGainedFocusInternalLocked(
             @StartInputReason int startInputReason, IInputMethodClient client,
             @NonNull IBinder windowToken, @StartInputFlags int startInputFlags,
             @SoftInputModeFlags int softInputMode, int windowFlags, EditorInfo attribute,
             IInputContext inputContext, @MissingMethodFlags int missingMethods,
-            int unverifiedTargetSdkVersion) {
-        final int callingUserId = UserHandle.getCallingUserId();
-        final int userId;
-        if (attribute != null && attribute.targetInputMethodUser != null
-                && attribute.targetInputMethodUser.getIdentifier() != callingUserId) {
-            mContext.enforceCallingPermission(Manifest.permission.INTERACT_ACROSS_USERS_FULL,
-                    "Using EditorInfo.user requires INTERACT_ACROSS_USERS_FULL.");
-            userId = attribute.targetInputMethodUser.getIdentifier();
-            if (!mUserManagerInternal.isUserRunning(userId)) {
-                // There is a chance that we hit here because of race condition.  Let's just return
-                // an error code instead of crashing the caller process, which at least has
-                // INTERACT_ACROSS_USERS_FULL permission thus is likely to be an important process.
-                Slog.e(TAG, "User #" + userId + " is not running.");
-                return InputBindResult.INVALID_USER;
-            }
-        } else {
-            userId = callingUserId;
+            int unverifiedTargetSdkVersion, @UserIdInt int userId) {
+        if (DEBUG) {
+            Slog.v(TAG, "startInputOrWindowGainedFocusInternalLocked: reason="
+                    + InputMethodDebug.startInputReasonToString(startInputReason)
+                    + " client=" + client.asBinder()
+                    + " inputContext=" + inputContext
+                    + " missingMethods="
+                    + InputConnectionInspector.getMissingMethodFlagsAsString(missingMethods)
+                    + " attribute=" + attribute
+                    + " startInputFlags="
+                    + InputMethodDebug.startInputFlagsToString(startInputFlags)
+                    + " softInputMode=" + InputMethodDebug.softInputModeToString(softInputMode)
+                    + " windowFlags=#" + Integer.toHexString(windowFlags)
+                    + " unverifiedTargetSdkVersion=" + unverifiedTargetSdkVersion);
         }
+
+        final int windowDisplayId = mWindowManagerInternal.getDisplayIdForWindow(windowToken);
+
+        final ClientState cs = mClients.get(client.asBinder());
+        if (cs == null) {
+            throw new IllegalArgumentException("unknown client " + client.asBinder());
+        }
+        if (cs.selfReportedDisplayId != windowDisplayId) {
+            Slog.e(TAG, "startInputOrWindowGainedFocusInternal: display ID mismatch."
+                    + " from client:" + cs.selfReportedDisplayId
+                    + " from window:" + windowDisplayId);
+            return InputBindResult.DISPLAY_ID_MISMATCH;
+        }
+
+        if (!mWindowManagerInternal.isInputMethodClientFocus(cs.uid, cs.pid,
+                cs.selfReportedDisplayId)) {
+            // Check with the window manager to make sure this client actually
+            // has a window with focus.  If not, reject.  This is thread safe
+            // because if the focus changes some time before or after, the
+            // next client receiving focus that has any interest in input will
+            // be calling through here after that change happens.
+            if (DEBUG) {
+                Slog.w(TAG, "Focus gain on non-focused client " + cs.client
+                        + " (uid=" + cs.uid + " pid=" + cs.pid + ")");
+            }
+            return InputBindResult.NOT_IME_TARGET_WINDOW;
+        }
+
+        // cross-profile access is always allowed here to allow profile-switching.
+        if (!mSettings.isCurrentProfile(userId)) {
+            Slog.w(TAG, "A background user is requesting window. Hiding IME.");
+            Slog.w(TAG, "If you need to impersonate a foreground user/profile from"
+                    + " a background user, use EditorInfo.targetInputMethodUser with"
+                    + " INTERACT_ACROSS_USERS_FULL permission.");
+            hideCurrentInputLocked(0, null);
+            return InputBindResult.INVALID_USER;
+        }
+
+        if (PER_PROFILE_IME_ENABLED && userId != mSettings.getCurrentUserId()) {
+            switchUserLocked(userId);
+        }
+        // Master feature flag that overrides other conditions and forces IME preRendering.
+        if (DEBUG) {
+            Slog.v(TAG, "IME PreRendering MASTER flag: "
+                    + DebugFlags.FLAG_PRE_RENDER_IME_VIEWS.value() + ", LowRam: " + mIsLowRam);
+        }
+        // pre-rendering not supported on low-ram devices.
+        cs.shouldPreRenderIme = DebugFlags.FLAG_PRE_RENDER_IME_VIEWS.value() && !mIsLowRam;
+
+        if (mCurFocusedWindow == windowToken) {
+            if (DEBUG) {
+                Slog.w(TAG, "Window already focused, ignoring focus gain of: " + client
+                        + " attribute=" + attribute + ", token = " + windowToken);
+            }
+            if (attribute != null) {
+                return startInputUncheckedLocked(cs, inputContext, missingMethods,
+                        attribute, startInputFlags, startInputReason);
+            }
+            return new InputBindResult(
+                    InputBindResult.ResultCode.SUCCESS_REPORT_WINDOW_FOCUS_ONLY,
+                    null, null, null, -1);
+        }
+        mCurFocusedWindow = windowToken;
+        mCurFocusedWindowSoftInputMode = softInputMode;
+        mCurFocusedWindowClient = cs;
+
+        // Should we auto-show the IME even if the caller has not
+        // specified what should be done with it?
+        // We only do this automatically if the window can resize
+        // to accommodate the IME (so what the user sees will give
+        // them good context without input information being obscured
+        // by the IME) or if running on a large screen where there
+        // is more room for the target window + IME.
+        final boolean doAutoShow =
+                (softInputMode & LayoutParams.SOFT_INPUT_MASK_ADJUST)
+                        == LayoutParams.SOFT_INPUT_ADJUST_RESIZE
+                || mRes.getConfiguration().isLayoutSizeAtLeast(
+                        Configuration.SCREENLAYOUT_SIZE_LARGE);
+        final boolean isTextEditor = (startInputFlags & StartInputFlags.IS_TEXT_EDITOR) != 0;
+
+        // We want to start input before showing the IME, but after closing
+        // it.  We want to do this after closing it to help the IME disappear
+        // more quickly (not get stuck behind it initializing itself for the
+        // new focused input, even if its window wants to hide the IME).
+        boolean didStart = false;
+
         InputBindResult res = null;
-        synchronized (mMethodMap) {
-            final int windowDisplayId =
-                    mWindowManagerInternal.getDisplayIdForWindow(windowToken);
-            final long ident = Binder.clearCallingIdentity();
-            try {
-                if (DEBUG) Slog.v(TAG, "startInputOrWindowGainedFocusInternal: reason="
-                        + InputMethodDebug.startInputReasonToString(startInputReason)
-                        + " client=" + client.asBinder()
-                        + " inputContext=" + inputContext
-                        + " missingMethods="
-                        + InputConnectionInspector.getMissingMethodFlagsAsString(missingMethods)
-                        + " attribute=" + attribute
-                        + " startInputFlags="
-                        + InputMethodDebug.startInputFlagsToString(startInputFlags)
-                        + " softInputMode=" + InputMethodDebug.softInputModeToString(softInputMode)
-                        + " windowFlags=#" + Integer.toHexString(windowFlags)
-                        + " unverifiedTargetSdkVersion=" + unverifiedTargetSdkVersion);
+        switch (softInputMode & LayoutParams.SOFT_INPUT_MASK_STATE) {
+            case LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED:
+                if (!isTextEditor || !doAutoShow) {
+                    if (LayoutParams.mayUseInputMethod(windowFlags)) {
+                        // There is no focus view, and this window will
+                        // be behind any soft input window, so hide the
+                        // soft input window if it is shown.
+                        if (DEBUG) Slog.v(TAG, "Unspecified window will hide input");
+                        hideCurrentInputLocked(InputMethodManager.HIDE_NOT_ALWAYS, null);
 
-                ClientState cs = mClients.get(client.asBinder());
-                if (cs == null) {
-                    throw new IllegalArgumentException("unknown client "
-                            + client.asBinder());
-                }
-                if (cs.selfReportedDisplayId != windowDisplayId) {
-                    Slog.e(TAG, "startInputOrWindowGainedFocusInternal: display ID mismatch."
-                            + " from client:" + cs.selfReportedDisplayId
-                            + " from window:" + windowDisplayId);
-                    return InputBindResult.DISPLAY_ID_MISMATCH;
-                }
-
-                if (!mWindowManagerInternal.isInputMethodClientFocus(cs.uid, cs.pid,
-                        cs.selfReportedDisplayId)) {
-                    // Check with the window manager to make sure this client actually
-                    // has a window with focus.  If not, reject.  This is thread safe
-                    // because if the focus changes some time before or after, the
-                    // next client receiving focus that has any interest in input will
-                    // be calling through here after that change happens.
-                    if (DEBUG) {
-                        Slog.w(TAG, "Focus gain on non-focused client " + cs.client
-                                + " (uid=" + cs.uid + " pid=" + cs.pid + ")");
+                        // If focused display changed, we should unbind current method
+                        // to make app window in previous display relayout after Ime
+                        // window token removed.
+                        // Note that we can trust client's display ID as long as it matches
+                        // to the display ID obtained from the window.
+                        if (cs.selfReportedDisplayId != mCurTokenDisplayId) {
+                            unbindCurrentMethodLocked();
+                        }
                     }
-                    return InputBindResult.NOT_IME_TARGET_WINDOW;
-                }
-
-                // cross-profile access is always allowed here to allow profile-switching.
-                if (!mSettings.isCurrentProfile(userId)) {
-                    Slog.w(TAG, "A background user is requesting window. Hiding IME.");
-                    Slog.w(TAG, "If you need to impersonate a foreground user/profile from"
-                            + " a background user, use EditorInfo.targetInputMethodUser with"
-                            + " INTERACT_ACROSS_USERS_FULL permission.");
-                    hideCurrentInputLocked(0, null);
-                    return InputBindResult.INVALID_USER;
-                }
-
-                if (PER_PROFILE_IME_ENABLED && userId != mSettings.getCurrentUserId()) {
-                    switchUserLocked(userId);
-                }
-                // Master feature flag that overrides other conditions and forces IME preRendering.
-                if (DEBUG) {
-                    Slog.v(TAG, "IME PreRendering MASTER flag: "
-                            + DebugFlags.FLAG_PRE_RENDER_IME_VIEWS.value()
-                            + ", LowRam: " + mIsLowRam);
-                }
-                // pre-rendering not supported on low-ram devices.
-                cs.shouldPreRenderIme = DebugFlags.FLAG_PRE_RENDER_IME_VIEWS.value() && !mIsLowRam;
-
-                if (mCurFocusedWindow == windowToken) {
-                    if (DEBUG) {
-                        Slog.w(TAG, "Window already focused, ignoring focus gain of: " + client
-                                + " attribute=" + attribute + ", token = " + windowToken);
-                    }
+                } else if (isTextEditor && doAutoShow
+                        && (softInputMode & LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION) != 0) {
+                    // There is a focus view, and we are navigating forward
+                    // into the window, so show the input window for the user.
+                    // We only do this automatically if the window can resize
+                    // to accommodate the IME (so what the user sees will give
+                    // them good context without input information being obscured
+                    // by the IME) or if running on a large screen where there
+                    // is more room for the target window + IME.
+                    if (DEBUG) Slog.v(TAG, "Unspecified window will show input");
                     if (attribute != null) {
-                        return startInputUncheckedLocked(cs, inputContext, missingMethods,
+                        res = startInputUncheckedLocked(cs, inputContext, missingMethods,
                                 attribute, startInputFlags, startInputReason);
+                        didStart = true;
                     }
-                    return new InputBindResult(
-                            InputBindResult.ResultCode.SUCCESS_REPORT_WINDOW_FOCUS_ONLY,
-                            null, null, null, -1);
+                    showCurrentInputLocked(InputMethodManager.SHOW_IMPLICIT, null);
                 }
-                mCurFocusedWindow = windowToken;
-                mCurFocusedWindowSoftInputMode = softInputMode;
-                mCurFocusedWindowClient = cs;
-
-                // Should we auto-show the IME even if the caller has not
-                // specified what should be done with it?
-                // We only do this automatically if the window can resize
-                // to accommodate the IME (so what the user sees will give
-                // them good context without input information being obscured
-                // by the IME) or if running on a large screen where there
-                // is more room for the target window + IME.
-                final boolean doAutoShow =
-                        (softInputMode & WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST)
-                                == WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE
-                        || mRes.getConfiguration().isLayoutSizeAtLeast(
-                                Configuration.SCREENLAYOUT_SIZE_LARGE);
-                final boolean isTextEditor =
-                        (startInputFlags & StartInputFlags.IS_TEXT_EDITOR) != 0;
-
-                // We want to start input before showing the IME, but after closing
-                // it.  We want to do this after closing it to help the IME disappear
-                // more quickly (not get stuck behind it initializing itself for the
-                // new focused input, even if its window wants to hide the IME).
-                boolean didStart = false;
-
-                switch (softInputMode&WindowManager.LayoutParams.SOFT_INPUT_MASK_STATE) {
-                    case WindowManager.LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED:
-                        if (!isTextEditor || !doAutoShow) {
-                            if (WindowManager.LayoutParams.mayUseInputMethod(windowFlags)) {
-                                // There is no focus view, and this window will
-                                // be behind any soft input window, so hide the
-                                // soft input window if it is shown.
-                                if (DEBUG) Slog.v(TAG, "Unspecified window will hide input");
-                                hideCurrentInputLocked(InputMethodManager.HIDE_NOT_ALWAYS, null);
-
-                                // If focused display changed, we should unbind current method
-                                // to make app window in previous display relayout after Ime
-                                // window token removed.
-                                // Note that we can trust client's display ID as long as it matches
-                                // to the display ID obtained from the window.
-                                if (cs.selfReportedDisplayId != mCurTokenDisplayId) {
-                                    unbindCurrentMethodLocked();
-                                }
-                            }
-                        } else if (isTextEditor && doAutoShow && (softInputMode &
-                                WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION) != 0) {
-                            // There is a focus view, and we are navigating forward
-                            // into the window, so show the input window for the user.
-                            // We only do this automatically if the window can resize
-                            // to accommodate the IME (so what the user sees will give
-                            // them good context without input information being obscured
-                            // by the IME) or if running on a large screen where there
-                            // is more room for the target window + IME.
-                            if (DEBUG) Slog.v(TAG, "Unspecified window will show input");
-                            if (attribute != null) {
-                                res = startInputUncheckedLocked(cs, inputContext, missingMethods,
-                                        attribute, startInputFlags, startInputReason);
-                                didStart = true;
-                            }
-                            showCurrentInputLocked(InputMethodManager.SHOW_IMPLICIT, null);
-                        }
-                        break;
-                    case WindowManager.LayoutParams.SOFT_INPUT_STATE_UNCHANGED:
-                        // Do nothing.
-                        break;
-                    case WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN:
-                        if ((softInputMode &
-                                WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION) != 0) {
-                            if (DEBUG) Slog.v(TAG, "Window asks to hide input going forward");
-                            hideCurrentInputLocked(0, null);
-                        }
-                        break;
-                    case WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN:
-                        if (DEBUG) Slog.v(TAG, "Window asks to hide input");
-                        hideCurrentInputLocked(0, null);
-                        break;
-                    case WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE:
-                        if ((softInputMode &
-                                WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION) != 0) {
-                            if (DEBUG) Slog.v(TAG, "Window asks to show input going forward");
-                            if (InputMethodUtils.isSoftInputModeStateVisibleAllowed(
-                                    unverifiedTargetSdkVersion, startInputFlags)) {
-                                if (attribute != null) {
-                                    res = startInputUncheckedLocked(cs, inputContext,
-                                            missingMethods, attribute, startInputFlags,
-                                            startInputReason);
-                                    didStart = true;
-                                }
-                                showCurrentInputLocked(InputMethodManager.SHOW_IMPLICIT, null);
-                            } else {
-                                Slog.e(TAG, "SOFT_INPUT_STATE_VISIBLE is ignored because"
-                                        + " there is no focused view that also returns true from"
-                                        + " View#onCheckIsTextEditor()");
-                            }
-                        }
-                        break;
-                    case WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE:
-                        if (DEBUG) Slog.v(TAG, "Window asks to always show input");
-                        if (InputMethodUtils.isSoftInputModeStateVisibleAllowed(
-                                unverifiedTargetSdkVersion, startInputFlags)) {
-                            if (attribute != null) {
-                                res = startInputUncheckedLocked(cs, inputContext, missingMethods,
-                                        attribute, startInputFlags, startInputReason);
-                                didStart = true;
-                            }
-                            showCurrentInputLocked(InputMethodManager.SHOW_IMPLICIT, null);
-                        } else {
-                            Slog.e(TAG, "SOFT_INPUT_STATE_ALWAYS_VISIBLE is ignored because"
-                                    + " there is no focused view that also returns true from"
-                                    + " View#onCheckIsTextEditor()");
-                        }
-                        break;
+                break;
+            case LayoutParams.SOFT_INPUT_STATE_UNCHANGED:
+                // Do nothing.
+                break;
+            case LayoutParams.SOFT_INPUT_STATE_HIDDEN:
+                if ((softInputMode & LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION) != 0) {
+                    if (DEBUG) Slog.v(TAG, "Window asks to hide input going forward");
+                    hideCurrentInputLocked(0, null);
                 }
-
-                if (!didStart) {
-                    if (attribute != null) {
-                        if (!DebugFlags.FLAG_OPTIMIZE_START_INPUT.value()
-                                || (startInputFlags & StartInputFlags.IS_TEXT_EDITOR) != 0) {
+                break;
+            case LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN:
+                if (DEBUG) Slog.v(TAG, "Window asks to hide input");
+                hideCurrentInputLocked(0, null);
+                break;
+            case LayoutParams.SOFT_INPUT_STATE_VISIBLE:
+                if ((softInputMode & LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION) != 0) {
+                    if (DEBUG) Slog.v(TAG, "Window asks to show input going forward");
+                    if (InputMethodUtils.isSoftInputModeStateVisibleAllowed(
+                            unverifiedTargetSdkVersion, startInputFlags)) {
+                        if (attribute != null) {
                             res = startInputUncheckedLocked(cs, inputContext, missingMethods,
-                                    attribute,
-                                    startInputFlags, startInputReason);
-                        } else {
-                            res = InputBindResult.NO_EDITOR;
+                                    attribute, startInputFlags, startInputReason);
+                            didStart = true;
                         }
+                        showCurrentInputLocked(InputMethodManager.SHOW_IMPLICIT, null);
                     } else {
-                        res = InputBindResult.NULL_EDITOR_INFO;
+                        Slog.e(TAG, "SOFT_INPUT_STATE_VISIBLE is ignored because"
+                                + " there is no focused view that also returns true from"
+                                + " View#onCheckIsTextEditor()");
                     }
                 }
-            } finally {
-                Binder.restoreCallingIdentity(ident);
-            }
+                break;
+            case LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE:
+                if (DEBUG) Slog.v(TAG, "Window asks to always show input");
+                if (InputMethodUtils.isSoftInputModeStateVisibleAllowed(
+                        unverifiedTargetSdkVersion, startInputFlags)) {
+                    if (attribute != null) {
+                        res = startInputUncheckedLocked(cs, inputContext, missingMethods,
+                                attribute, startInputFlags, startInputReason);
+                        didStart = true;
+                    }
+                    showCurrentInputLocked(InputMethodManager.SHOW_IMPLICIT, null);
+                } else {
+                    Slog.e(TAG, "SOFT_INPUT_STATE_ALWAYS_VISIBLE is ignored because"
+                            + " there is no focused view that also returns true from"
+                            + " View#onCheckIsTextEditor()");
+                }
+                break;
         }
 
+        if (!didStart) {
+            if (attribute != null) {
+                if (!DebugFlags.FLAG_OPTIMIZE_START_INPUT.value()
+                        || (startInputFlags & StartInputFlags.IS_TEXT_EDITOR) != 0) {
+                    res = startInputUncheckedLocked(cs, inputContext, missingMethods, attribute,
+                            startInputFlags, startInputReason);
+                } else {
+                    res = InputBindResult.NO_EDITOR;
+                }
+            } else {
+                res = InputBindResult.NULL_EDITOR_INFO;
+            }
+        }
         return res;
     }
 
@@ -3327,6 +3322,32 @@
         }
     }
 
+    @BinderThread
+    private void reportPreRendered(IBinder token, EditorInfo info) {
+        synchronized (mMethodMap) {
+            if (!calledWithValidTokenLocked(token)) {
+                return;
+            }
+            if (mCurClient != null && mCurClient.client != null) {
+                executeOrSendMessage(mCurClient.client, mCaller.obtainMessageOO(
+                        MSG_REPORT_PRE_RENDERED, info, mCurClient));
+            }
+        }
+    }
+
+    @BinderThread
+    private void applyImeVisibility(IBinder token, boolean setVisible) {
+        synchronized (mMethodMap) {
+            if (!calledWithValidTokenLocked(token)) {
+                return;
+            }
+            if (mCurClient != null && mCurClient.client != null) {
+                executeOrSendMessage(mCurClient.client, mCaller.obtainMessageIO(
+                        MSG_APPLY_IME_VISIBILITY, setVisible ? 1 : 0, mCurClient));
+            }
+        }
+    }
+
     private void setInputMethodWithSubtypeIdLocked(IBinder token, String id, int subtypeId) {
         if (token == null) {
             if (mContext.checkCallingOrSelfPermission(
@@ -3580,6 +3601,32 @@
                 }
                 return true;
             }
+            case MSG_REPORT_PRE_RENDERED: {
+                args = (SomeArgs) msg.obj;
+                final EditorInfo info = (EditorInfo) args.arg1;
+                final ClientState clientState = (ClientState) args.arg2;
+                try {
+                    clientState.client.reportPreRendered(info);
+                } catch (RemoteException e) {
+                    Slog.w(TAG, "Got RemoteException sending "
+                            + "reportPreRendered(" + info + ") notification to pid="
+                            + clientState.pid + " uid=" + clientState.uid);
+                }
+                args.recycle();
+                return true;
+            }
+            case MSG_APPLY_IME_VISIBILITY: {
+                final boolean setVisible = msg.arg1 != 0;
+                final ClientState clientState = (ClientState) msg.obj;
+                try {
+                    clientState.client.applyImeVisibility(setVisible);
+                } catch (RemoteException e) {
+                    Slog.w(TAG, "Got RemoteException sending "
+                            + "applyImeVisibility(" + setVisible + ") notification to pid="
+                            + clientState.pid + " uid=" + clientState.uid);
+                }
+                return true;
+            }
 
             // --------------------------------------------------------------
             case MSG_HARD_KEYBOARD_SWITCH_CHANGED:
@@ -3921,13 +3968,13 @@
             mSwitchingDialog = mDialogBuilder.create();
             mSwitchingDialog.setCanceledOnTouchOutside(true);
             final Window w = mSwitchingDialog.getWindow();
-            final WindowManager.LayoutParams attrs = w.getAttributes();
-            w.setType(TYPE_INPUT_METHOD_DIALOG);
+            final LayoutParams attrs = w.getAttributes();
+            w.setType(LayoutParams.TYPE_INPUT_METHOD_DIALOG);
             // Use an alternate token for the dialog for that window manager can group the token
             // with other IME windows based on type vs. grouping based on whichever token happens
             // to get selected by the system later on.
             attrs.token = mSwitchingDialogToken;
-            attrs.privateFlags |= PRIVATE_FLAG_SHOW_FOR_ALL_USERS;
+            attrs.privateFlags |= LayoutParams.PRIVATE_FLAG_SHOW_FOR_ALL_USERS;
             attrs.setTitle("Select input method");
             w.setAttributes(attrs);
             updateSystemUiLocked(mImeWindowVis, mBackDisposition);
@@ -4756,5 +4803,17 @@
         public void notifyUserAction() {
             mImms.notifyUserAction(mToken);
         }
+
+        @BinderThread
+        @Override
+        public void reportPreRendered(EditorInfo info) {
+            mImms.reportPreRendered(mToken, info);
+        }
+
+        @BinderThread
+        @Override
+        public void applyImeVisibility(boolean setVisible) {
+            mImms.applyImeVisibility(mToken, setVisible);
+        }
     }
 }
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodUtils.java b/services/core/java/com/android/server/inputmethod/InputMethodUtils.java
index 326984c..4349b4a 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodUtils.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodUtils.java
@@ -872,7 +872,7 @@
         private int getInt(String key, int defaultValue) {
             if (mCopyOnWrite && mCopyOnWriteDataStore.containsKey(key)) {
                 final String result = mCopyOnWriteDataStore.get(key);
-                return result != null ? Integer.parseInt(result) : 0;
+                return result != null ? Integer.parseInt(result) : defaultValue;
             }
             return Settings.Secure.getIntForUser(mResolver, key, defaultValue, mCurrentUserId);
         }
diff --git a/services/core/java/com/android/server/job/JobSchedulerService.java b/services/core/java/com/android/server/job/JobSchedulerService.java
index 7625aaf..65a078b 100644
--- a/services/core/java/com/android/server/job/JobSchedulerService.java
+++ b/services/core/java/com/android/server/job/JobSchedulerService.java
@@ -508,7 +508,7 @@
         private static final int DEFAULT_STANDBY_RARE_BEATS = 130; // ~ 24 hours
         private static final float DEFAULT_CONN_CONGESTION_DELAY_FRAC = 0.5f;
         private static final float DEFAULT_CONN_PREFETCH_RELAX_FRAC = 0.5f;
-        private static final boolean DEFAULT_USE_HEARTBEATS = true;
+        private static final boolean DEFAULT_USE_HEARTBEATS = false;
         private static final boolean DEFAULT_TIME_CONTROLLER_SKIP_NOT_READY_JOBS = false;
         private static final long DEFAULT_QUOTA_CONTROLLER_ALLOWED_TIME_PER_PERIOD_MS =
                 10 * 60 * 1000L; // 10 minutes
@@ -2040,6 +2040,7 @@
                         if (DEBUG) {
                             Slog.d(TAG, "MSG_CHECK_JOB");
                         }
+                        removeMessages(MSG_CHECK_JOB);
                         if (mReportedActive) {
                             // if jobs are currently being run, queue all ready jobs for execution.
                             queueReadyJobsForExecutionLocked();
@@ -2099,7 +2100,6 @@
                 }
                 maybeRunPendingJobsLocked();
                 // Don't remove JOB_EXPIRED in case one came along while processing the queue.
-                removeMessages(MSG_CHECK_JOB);
             }
         }
     }
diff --git a/services/core/java/com/android/server/job/controllers/JobStatus.java b/services/core/java/com/android/server/job/controllers/JobStatus.java
index 82bfa51..ed1a6d0 100644
--- a/services/core/java/com/android/server/job/controllers/JobStatus.java
+++ b/services/core/java/com/android/server/job/controllers/JobStatus.java
@@ -33,6 +33,7 @@
 import android.util.ArraySet;
 import android.util.Pair;
 import android.util.Slog;
+import android.util.StatsLog;
 import android.util.TimeUtils;
 import android.util.proto.ProtoOutputStream;
 
@@ -40,6 +41,7 @@
 import com.android.server.job.GrantedUriPermissions;
 import com.android.server.job.JobSchedulerInternal;
 import com.android.server.job.JobSchedulerService;
+import com.android.server.job.JobServerProtoEnums;
 import com.android.server.job.JobStatusDumpProto;
 import com.android.server.job.JobStatusShortInfoProto;
 
@@ -80,6 +82,28 @@
     static final int CONSTRAINT_WITHIN_QUOTA = 1 << 24;
     static final int CONSTRAINT_BACKGROUND_NOT_RESTRICTED = 1<<22;
 
+    /**
+     * The constraints that we want to log to statsd.
+     *
+     * Constraints that can be inferred from other atoms have been excluded to avoid logging too
+     * much information and to reduce redundancy:
+     *
+     * * CONSTRAINT_CHARGING can be inferred with PluggedStateChanged (Atom #32)
+     * * CONSTRAINT_BATTERY_NOT_LOW can be inferred with BatteryLevelChanged (Atom #30)
+     * * CONSTRAINT_CONNECTIVITY can be partially inferred with ConnectivityStateChanged
+     * (Atom #98) and BatterySaverModeStateChanged (Atom #20).
+     * * CONSTRAINT_DEVICE_NOT_DOZING can be mostly inferred with DeviceIdleModeStateChanged
+     * (Atom #21)
+     * * CONSTRAINT_BACKGROUND_NOT_RESTRICTED can be inferred with BatterySaverModeStateChanged
+     * (Atom #20)
+     */
+    private static final int STATSD_CONSTRAINTS_TO_LOG = CONSTRAINT_CONTENT_TRIGGER
+            | CONSTRAINT_DEADLINE
+            | CONSTRAINT_IDLE
+            | CONSTRAINT_STORAGE_NOT_LOW
+            | CONSTRAINT_TIMING_DELAY
+            | CONSTRAINT_WITHIN_QUOTA;
+
     // Soft override: ignore constraints like time that don't affect API availability
     public static final int OVERRIDE_SOFT = 1;
     // Full override: ignore all constraints including API-affecting like connectivity
@@ -976,6 +1000,12 @@
         }
         satisfiedConstraints = (satisfiedConstraints&~constraint) | (state ? constraint : 0);
         mSatisfiedConstraintsOfInterest = satisfiedConstraints & CONSTRAINTS_OF_INTEREST;
+        if ((STATSD_CONSTRAINTS_TO_LOG & constraint) != 0) {
+            StatsLog.write_non_chained(StatsLog.SCHEDULED_JOB_CONSTRAINT_CHANGED,
+                    sourceUid, null, getBatteryName(), getProtoConstraint(constraint),
+                    state ? StatsLog.SCHEDULED_JOB_CONSTRAINT_CHANGED__STATE__SATISFIED
+                            : StatsLog.SCHEDULED_JOB_CONSTRAINT_CHANGED__STATE__UNSATISFIED);
+        }
         return true;
     }
 
@@ -1228,37 +1258,70 @@
         }
     }
 
+    /** Returns a {@link JobServerProtoEnums.Constraint} enum value for the given constraint. */
+    private int getProtoConstraint(int constraint) {
+        switch (constraint) {
+            case CONSTRAINT_BACKGROUND_NOT_RESTRICTED:
+                return JobServerProtoEnums.CONSTRAINT_BACKGROUND_NOT_RESTRICTED;
+            case CONSTRAINT_BATTERY_NOT_LOW:
+                return JobServerProtoEnums.CONSTRAINT_BATTERY_NOT_LOW;
+            case CONSTRAINT_CHARGING:
+                return JobServerProtoEnums.CONSTRAINT_CHARGING;
+            case CONSTRAINT_CONNECTIVITY:
+                return JobServerProtoEnums.CONSTRAINT_CONNECTIVITY;
+            case CONSTRAINT_CONTENT_TRIGGER:
+                return JobServerProtoEnums.CONSTRAINT_CONTENT_TRIGGER;
+            case CONSTRAINT_DEADLINE:
+                return JobServerProtoEnums.CONSTRAINT_DEADLINE;
+            case CONSTRAINT_DEVICE_NOT_DOZING:
+                return JobServerProtoEnums.CONSTRAINT_DEVICE_NOT_DOZING;
+            case CONSTRAINT_IDLE:
+                return JobServerProtoEnums.CONSTRAINT_IDLE;
+            case CONSTRAINT_STORAGE_NOT_LOW:
+                return JobServerProtoEnums.CONSTRAINT_STORAGE_NOT_LOW;
+            case CONSTRAINT_TIMING_DELAY:
+                return JobServerProtoEnums.CONSTRAINT_TIMING_DELAY;
+            case CONSTRAINT_WITHIN_QUOTA:
+                return JobServerProtoEnums.CONSTRAINT_WITHIN_QUOTA;
+            default:
+                return JobServerProtoEnums.CONSTRAINT_UNKNOWN;
+        }
+    }
+
     /** Writes constraints to the given repeating proto field. */
     void dumpConstraints(ProtoOutputStream proto, long fieldId, int constraints) {
         if ((constraints & CONSTRAINT_CHARGING) != 0) {
-            proto.write(fieldId, JobStatusDumpProto.CONSTRAINT_CHARGING);
+            proto.write(fieldId, JobServerProtoEnums.CONSTRAINT_CHARGING);
         }
         if ((constraints & CONSTRAINT_BATTERY_NOT_LOW) != 0) {
-            proto.write(fieldId, JobStatusDumpProto.CONSTRAINT_BATTERY_NOT_LOW);
+            proto.write(fieldId, JobServerProtoEnums.CONSTRAINT_BATTERY_NOT_LOW);
         }
         if ((constraints & CONSTRAINT_STORAGE_NOT_LOW) != 0) {
-            proto.write(fieldId, JobStatusDumpProto.CONSTRAINT_STORAGE_NOT_LOW);
+            proto.write(fieldId, JobServerProtoEnums.CONSTRAINT_STORAGE_NOT_LOW);
         }
         if ((constraints & CONSTRAINT_TIMING_DELAY) != 0) {
-            proto.write(fieldId, JobStatusDumpProto.CONSTRAINT_TIMING_DELAY);
+            proto.write(fieldId, JobServerProtoEnums.CONSTRAINT_TIMING_DELAY);
         }
         if ((constraints & CONSTRAINT_DEADLINE) != 0) {
-            proto.write(fieldId, JobStatusDumpProto.CONSTRAINT_DEADLINE);
+            proto.write(fieldId, JobServerProtoEnums.CONSTRAINT_DEADLINE);
         }
         if ((constraints & CONSTRAINT_IDLE) != 0) {
-            proto.write(fieldId, JobStatusDumpProto.CONSTRAINT_IDLE);
+            proto.write(fieldId, JobServerProtoEnums.CONSTRAINT_IDLE);
         }
         if ((constraints & CONSTRAINT_CONNECTIVITY) != 0) {
-            proto.write(fieldId, JobStatusDumpProto.CONSTRAINT_CONNECTIVITY);
+            proto.write(fieldId, JobServerProtoEnums.CONSTRAINT_CONNECTIVITY);
         }
         if ((constraints & CONSTRAINT_CONTENT_TRIGGER) != 0) {
-            proto.write(fieldId, JobStatusDumpProto.CONSTRAINT_CONTENT_TRIGGER);
+            proto.write(fieldId, JobServerProtoEnums.CONSTRAINT_CONTENT_TRIGGER);
         }
         if ((constraints & CONSTRAINT_DEVICE_NOT_DOZING) != 0) {
-            proto.write(fieldId, JobStatusDumpProto.CONSTRAINT_DEVICE_NOT_DOZING);
+            proto.write(fieldId, JobServerProtoEnums.CONSTRAINT_DEVICE_NOT_DOZING);
         }
         if ((constraints & CONSTRAINT_WITHIN_QUOTA) != 0) {
-            proto.write(fieldId, JobStatusDumpProto.CONSTRAINT_WITHIN_QUOTA);
+            proto.write(fieldId, JobServerProtoEnums.CONSTRAINT_WITHIN_QUOTA);
+        }
+        if ((constraints & CONSTRAINT_BACKGROUND_NOT_RESTRICTED) != 0) {
+            proto.write(fieldId, JobServerProtoEnums.CONSTRAINT_BACKGROUND_NOT_RESTRICTED);
         }
     }
 
diff --git a/services/core/java/com/android/server/media/MediaSessionServiceImpl.java b/services/core/java/com/android/server/media/MediaSessionServiceImpl.java
index dd26a29..94de49e 100644
--- a/services/core/java/com/android/server/media/MediaSessionServiceImpl.java
+++ b/services/core/java/com/android/server/media/MediaSessionServiceImpl.java
@@ -43,7 +43,6 @@
 import android.media.IAudioService;
 import android.media.IRemoteVolumeController;
 import android.media.Session2Token;
-import android.media.session.ControllerLink;
 import android.media.session.IActiveSessionsListener;
 import android.media.session.ICallback;
 import android.media.session.IOnMediaKeyListener;
@@ -1054,21 +1053,21 @@
         }
 
         @Override
-        public List<ControllerLink> getSessions(ComponentName componentName, int userId) {
+        public List<MediaSession.Token> getSessions(ComponentName componentName, int userId) {
             final int pid = Binder.getCallingPid();
             final int uid = Binder.getCallingUid();
             final long token = Binder.clearCallingIdentity();
 
             try {
                 int resolvedUserId = verifySessionsRequest(componentName, userId, pid, uid);
-                ArrayList<ControllerLink> binders = new ArrayList<>();
+                ArrayList<MediaSession.Token> tokens = new ArrayList<>();
                 synchronized (mLock) {
                     List<MediaSessionRecord> records = getActiveSessionsLocked(resolvedUserId);
                     for (MediaSessionRecord record : records) {
-                        binders.add(record.getControllerLink());
+                        tokens.add(record.getSessionToken());
                     }
                 }
-                return binders;
+                return tokens;
             } finally {
                 Binder.restoreCallingIdentity(token);
             }
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index de3f50a..1369f7b 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -121,6 +121,7 @@
 import android.content.pm.IPackageManager;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.pm.PackageManagerInternal;
 import android.content.pm.ParceledListSlice;
 import android.content.pm.UserInfo;
 import android.content.res.Resources;
@@ -2339,18 +2340,24 @@
         public boolean areBubblesAllowedForPackage(String pkg, int uid) {
             enforceSystemOrSystemUIOrSamePackage(pkg,
                     "Caller not system or systemui or same package");
-            return mPreferencesHelper.areBubblessAllowed(pkg, uid);
+            return mPreferencesHelper.areBubblesAllowed(pkg, uid);
         }
 
         @Override
         public void setBubblesAllowed(String pkg, int uid, boolean allowed) {
-            checkCallerIsSystem();
-
+            enforceSystemOrSystemUI("Caller not system or systemui");
             mPreferencesHelper.setBubblesAllowed(pkg, uid, allowed);
             handleSavePolicyFile();
         }
 
         @Override
+        public boolean hasUserApprovedBubblesForPackage(String pkg, int uid) {
+            enforceSystemOrSystemUI("Caller not system or systemui");
+            int lockedFields = mPreferencesHelper.getAppLockedFields(pkg, uid);
+            return (lockedFields & PreferencesHelper.LockableAppFields.USER_LOCKED_BUBBLE) != 0;
+        }
+
+        @Override
         public int getPackageImportance(String pkg) {
             checkCallerIsSystemOrSameApp(pkg);
             return mPreferencesHelper.getImportance(pkg, Binder.getCallingUid());
@@ -3859,6 +3866,24 @@
             return mLockScreenAllowSecureNotifications;
         }
 
+        @Override
+        public boolean isPackagePaused(String pkg) {
+            Preconditions.checkNotNull(pkg);
+            checkCallerIsSameApp(pkg);
+
+            boolean isPaused;
+
+            final PackageManagerInternal pmi = LocalServices.getService(
+                    PackageManagerInternal.class);
+            int flags = pmi.getDistractingPackageRestrictions(
+                    pkg, Binder.getCallingUserHandle().getIdentifier());
+            isPaused = ((flags & PackageManager.RESTRICTION_HIDE_NOTIFICATIONS) != 0);
+
+            isPaused |= isPackageSuspendedForUser(pkg, Binder.getCallingUid());
+
+            return isPaused;
+        }
+
         private void verifyPrivilegedListener(INotificationListener token, UserHandle user,
                 boolean assistantAllowed) {
             ManagedServiceInfo info;
diff --git a/services/core/java/com/android/server/notification/NotificationRecord.java b/services/core/java/com/android/server/notification/NotificationRecord.java
index ac965fa..ab49ebb 100644
--- a/services/core/java/com/android/server/notification/NotificationRecord.java
+++ b/services/core/java/com/android/server/notification/NotificationRecord.java
@@ -667,15 +667,15 @@
                                         getUserSentiment()));
                     }
                 }
-                if (signals.containsKey(Adjustment.KEY_SMART_ACTIONS)) {
+                if (signals.containsKey(Adjustment.KEY_CONTEXTUAL_ACTIONS)) {
                     setSystemGeneratedSmartActions(
-                            signals.getParcelableArrayList(Adjustment.KEY_SMART_ACTIONS));
+                            signals.getParcelableArrayList(Adjustment.KEY_CONTEXTUAL_ACTIONS));
                     MetricsLogger.action(getAdjustmentLogMaker()
                             .addTaggedData(MetricsEvent.ADJUSTMENT_KEY_SMART_ACTIONS,
                                     getSystemGeneratedSmartActions().size()));
                 }
-                if (signals.containsKey(Adjustment.KEY_SMART_REPLIES)) {
-                    setSmartReplies(signals.getCharSequenceArrayList(Adjustment.KEY_SMART_REPLIES));
+                if (signals.containsKey(Adjustment.KEY_TEXT_REPLIES)) {
+                    setSmartReplies(signals.getCharSequenceArrayList(Adjustment.KEY_TEXT_REPLIES));
                     MetricsLogger.action(getAdjustmentLogMaker()
                             .addTaggedData(MetricsEvent.ADJUSTMENT_KEY_SMART_REPLIES,
                                     getSmartReplies().size()));
diff --git a/services/core/java/com/android/server/notification/PreferencesHelper.java b/services/core/java/com/android/server/notification/PreferencesHelper.java
index 7a21aa2..3f0043c 100644
--- a/services/core/java/com/android/server/notification/PreferencesHelper.java
+++ b/services/core/java/com/android/server/notification/PreferencesHelper.java
@@ -473,7 +473,7 @@
      * @param uid the uid to check if bubbles are allowed for.
      * @return whether bubbles are allowed.
      */
-    public boolean areBubblessAllowed(String pkg, int uid) {
+    public boolean areBubblesAllowed(String pkg, int uid) {
         return getOrCreatePackagePreferences(pkg, uid).allowBubble;
     }
 
@@ -489,7 +489,6 @@
         return getOrCreatePackagePreferences(packageName, uid).importance;
     }
 
-
     /**
      * Returns whether the importance of the corresponding notification is user-locked and shouldn't
      * be adjusted by an assistant (via means of a blocking helper, for example). For the channel
diff --git a/services/core/java/com/android/server/pm/LauncherAppsService.java b/services/core/java/com/android/server/pm/LauncherAppsService.java
index d0ef4f1..d5089cb 100644
--- a/services/core/java/com/android/server/pm/LauncherAppsService.java
+++ b/services/core/java/com/android/server/pm/LauncherAppsService.java
@@ -696,7 +696,7 @@
                 return null;
             }
             return new LauncherApps.AppUsageLimit(
-                    data.isGroupLimit(), data.getTotalUsageLimit(), data.getUsageRemaining());
+                    data.getTotalUsageLimit(), data.getUsageRemaining());
         }
 
         private void ensureShortcutPermission(@NonNull String callingPackage) {
diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java
index eab5c8f..146a2f3 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerService.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerService.java
@@ -28,8 +28,10 @@
 import android.app.PackageDeleteObserver;
 import android.app.PackageInstallObserver;
 import android.app.admin.DevicePolicyManagerInternal;
+import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
+import android.content.IntentFilter;
 import android.content.IntentSender;
 import android.content.IntentSender.SendIntentException;
 import android.content.pm.ApplicationInfo;
@@ -138,6 +140,8 @@
 
     private final Callbacks mCallbacks;
 
+    private volatile boolean mBootCompleted = false;
+
     /**
      * File storing persisted {@link #mSessions} metadata.
      */
@@ -203,9 +207,20 @@
         mStagingManager = new StagingManager(pm);
     }
 
+    private void setBootCompleted()  {
+        mBootCompleted = true;
+    }
+
     public void systemReady() {
         mAppOps = mContext.getSystemService(AppOpsManager.class);
 
+        mContext.registerReceiver(new BroadcastReceiver() {
+            @Override
+            public void onReceive(Context context, Intent intent) {
+                setBootCompleted();
+                mContext.unregisterReceiver(this);
+            }
+        }, new IntentFilter(Intent.ACTION_BOOT_COMPLETED));
         synchronized (mSessions) {
             readSessionsLocked();
 
@@ -1126,8 +1141,10 @@
 
         public void onStagedSessionChanged(PackageInstallerSession session) {
             writeSessionsAsync();
-            // TODO(b/118865310): don't send broadcast if system is not ready.
-            mPm.sendSessionUpdatedBroadcast(session.generateInfo(false), session.userId);
+            if (mBootCompleted) {
+                mPm.sendSessionUpdatedBroadcast(session.generateInfo(false),
+                        session.userId);
+            }
         }
 
         public void onSessionFinished(final PackageInstallerSession session, boolean success) {
diff --git a/services/core/java/com/android/server/pm/ShortcutService.java b/services/core/java/com/android/server/pm/ShortcutService.java
index 792b34c..ff6d7a8 100644
--- a/services/core/java/com/android/server/pm/ShortcutService.java
+++ b/services/core/java/com/android/server/pm/ShortcutService.java
@@ -2154,6 +2154,8 @@
     public ParceledListSlice<ShortcutManager.ShareShortcutInfo> getShareTargets(String packageName,
             IntentFilter filter, @UserIdInt int userId) {
         verifyCaller(packageName, userId);
+        enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_APP_PREDICTIONS,
+                "getShareTargets");
 
         synchronized (mLock) {
             throwIfUserLockedL(userId);
diff --git a/services/core/java/com/android/server/pm/UserRestrictionsUtils.java b/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
index 2455113..8d64b81 100644
--- a/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
+++ b/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
@@ -16,10 +16,6 @@
 
 package com.android.server.pm;
 
-import com.google.android.collect.Sets;
-
-import com.android.internal.util.Preconditions;
-
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.app.ActivityManager;
@@ -42,6 +38,10 @@
 import android.util.Slog;
 import android.util.SparseArray;
 
+import com.android.internal.util.Preconditions;
+
+import com.google.android.collect.Sets;
+
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlSerializer;
 
@@ -666,6 +666,7 @@
 
             case android.provider.Settings.Secure.ALWAYS_ON_VPN_APP:
             case android.provider.Settings.Secure.ALWAYS_ON_VPN_LOCKDOWN:
+            case android.provider.Settings.Secure.ALWAYS_ON_VPN_LOCKDOWN_WHITELIST:
                 // Whitelist system uid (ConnectivityService) and root uid to change always-on vpn
                 final int appId = UserHandle.getAppId(callingUid);
                 if (appId == Process.SYSTEM_UID || appId == Process.ROOT_UID) {
diff --git a/services/core/java/com/android/server/pm/dex/ArtManagerService.java b/services/core/java/com/android/server/pm/dex/ArtManagerService.java
index 863bfd5..a8be07d 100644
--- a/services/core/java/com/android/server/pm/dex/ArtManagerService.java
+++ b/services/core/java/com/android/server/pm/dex/ArtManagerService.java
@@ -480,6 +480,10 @@
             final String apkPath = pkg.baseCodePath;
             final ApplicationInfo appInfo = pkg.applicationInfo;
             final String outDexFile = appInfo.dataDir + "/code_cache/compiled_view.dex";
+            if (appInfo.isPrivilegedApp()) {
+                // Privileged apps prefer to load trusted code so they don't use compiled views.
+                return false;
+            }
             Log.i("PackageManager", "Compiling layouts in " + packageName + " (" + apkPath +
                     ") to " + outDexFile);
             long callingId = Binder.clearCallingIdentity();
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 30b5e49..3c89d78 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
@@ -1049,6 +1049,8 @@
                     updatedUserIds);
             updatedUserIds = setInitialGrantForNewImplicitPermissionsLocked(origPermissions,
                     permissionsState, pkg, updatedUserIds);
+
+            setAppOpsLocked(permissionsState, pkg);
         }
 
         // Persist the runtime permissions state for users with changes. If permissions
@@ -1387,6 +1389,60 @@
         return updatedUserIds;
     }
 
+    /**
+     * Fix app-op modes for runtime permissions.
+     *
+     * @param permsState The state of the permissions of the package
+     * @param pkg The package information
+     */
+    private void setAppOpsLocked(@NonNull PermissionsState permsState,
+            @NonNull PackageParser.Package pkg) {
+        for (int userId : UserManagerService.getInstance().getUserIds()) {
+            int numPerms = pkg.requestedPermissions.size();
+            for (int i = 0; i < numPerms; i++) {
+                String permission = pkg.requestedPermissions.get(i);
+
+                int op = permissionToOpCode(permission);
+                if (op == OP_NONE) {
+                    continue;
+                }
+
+                // Runtime permissions are per uid, not per package, hence per package app-op
+                // modes should never have been set. It is possible to set them via the shell
+                // though. Revert such settings during boot to get the device back into a good
+                // state.
+                LocalServices.getService(AppOpsManagerInternal.class).setAllPkgModesToDefault(
+                        op, getUid(userId, getAppId(pkg.applicationInfo.uid)));
+
+                // For pre-M apps the runtime permission do not store the state
+                if (pkg.applicationInfo.targetSdkVersion < Build.VERSION_CODES.M) {
+                    continue;
+                }
+
+                PermissionState state = permsState.getRuntimePermissionState(permission, userId);
+                if (state == null) {
+                    continue;
+                }
+
+                // Adjust app-op mods for foreground/background permissions. If an package used to
+                // have both fg and bg permission granted and it lost the bg permission during an
+                // upgrade the app-op mode should get downgraded to foreground.
+                if (state.isGranted()) {
+                    BasePermission bp = mSettings.getPermission(permission);
+
+                    if (bp != null && bp.perm != null && bp.perm.info != null
+                            && bp.perm.info.backgroundPermission != null) {
+                        PermissionState bgState = permsState.getRuntimePermissionState(
+                                bp.perm.info.backgroundPermission, userId);
+
+                        setAppOpMode(permission, pkg, userId, bgState != null && bgState.isGranted()
+                                        ? MODE_ALLOWED : MODE_FOREGROUND);
+                    }
+                }
+            }
+        }
+    }
+
     private boolean isNewPlatformPermissionForPackage(String perm, PackageParser.Package pkg) {
         boolean allowed = false;
         final int NP = PackageParser.NEW_PERMISSIONS.length;
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 076c94c..09bacd6 100644
--- a/services/core/java/com/android/server/pm/permission/TEST_MAPPING
+++ b/services/core/java/com/android/server/pm/permission/TEST_MAPPING
@@ -7,6 +7,17 @@
                     "include-filter": "com.google.android.permission.gts.DefaultPermissionGrantPolicyTest"
                 }
             ]
+        },
+        {
+            "name": "CtsPermissionTestCases",
+            "options": [
+                {
+                    "include-filter": "android.permission.cts.BackgroundPermissionsTest"
+                },
+                {
+                    "include-filter": "android.permission.cts.SplitPermissionTest"
+                }
+            ]
         }
     ]
 }
\ No newline at end of file
diff --git a/services/core/java/com/android/server/role/FinancialSmsManager.java b/services/core/java/com/android/server/role/FinancialSmsManager.java
new file mode 100644
index 0000000..2ec3993
--- /dev/null
+++ b/services/core/java/com/android/server/role/FinancialSmsManager.java
@@ -0,0 +1,218 @@
+/*
+ * 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.role;
+
+import android.Manifest;
+import android.annotation.MainThread;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.content.pm.ServiceInfo;
+import android.os.Binder;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.os.RemoteCallback;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.service.sms.FinancialSmsService;
+import android.service.sms.IFinancialSmsService;
+import android.util.Slog;
+
+import com.android.internal.annotations.GuardedBy;
+
+import java.io.PrintWriter;
+import java.util.ArrayList;
+
+/**
+ * This class binds to {@code FinancialSmsService}.
+ */
+final class FinancialSmsManager {
+
+    private static final String TAG = "FinancialSmsManager";
+
+    private final Context mContext;
+    private final Object mLock = new Object();
+
+    @GuardedBy("mLock")
+    private ServiceConnection mServiceConnection;
+
+    @GuardedBy("mLock")
+    private IFinancialSmsService mRemoteService;
+
+    @GuardedBy("mLock")
+    private ArrayList<Command> mQueuedCommands;
+
+    FinancialSmsManager(Context context) {
+        mContext = context;
+    }
+
+    @Nullable
+    ServiceInfo getServiceInfo() {
+        final String packageName =
+                mContext.getPackageManager().getServicesSystemSharedLibraryPackageName();
+        if (packageName == null) {
+            Slog.w(TAG, "no external services package!");
+            return null;
+        }
+
+        final Intent intent = new Intent(FinancialSmsService.ACTION_FINANCIAL_SERVICE_INTENT);
+        intent.setPackage(packageName);
+        final ResolveInfo resolveInfo = mContext.getPackageManager().resolveService(intent,
+                PackageManager.GET_SERVICES);
+        if (resolveInfo == null || resolveInfo.serviceInfo == null) {
+            Slog.w(TAG, "No valid components found.");
+            return null;
+        }
+        return resolveInfo.serviceInfo;
+    }
+
+    @Nullable
+    private ComponentName getServiceComponentName() {
+        final ServiceInfo serviceInfo = getServiceInfo();
+        if (serviceInfo == null) return null;
+
+        final ComponentName name = new ComponentName(serviceInfo.packageName, serviceInfo.name);
+        if (!Manifest.permission.BIND_FINANCIAL_SMS_SERVICE.equals(serviceInfo.permission)) {
+            Slog.w(TAG, name.flattenToShortString() + " does not require permission "
+                    + Manifest.permission.BIND_FINANCIAL_SMS_SERVICE);
+            return null;
+        }
+
+        return name;
+    }
+
+    void reset() {
+        synchronized (mLock) {
+            if (mServiceConnection != null) {
+                mContext.unbindService(mServiceConnection);
+                mServiceConnection = null;
+            } else {
+                Slog.d(TAG, "reset(): service is not bound. Do nothing.");
+            }
+        }
+    }
+
+    /**
+     * Run a command, starting the service connection if necessary.
+     */
+    private void connectAndRun(@NonNull Command command) {
+        synchronized (mLock) {
+            if (mRemoteService != null) {
+                try {
+                    command.run(mRemoteService);
+                } catch (RemoteException e) {
+                    Slog.w(TAG, "exception calling service: " + e);
+                }
+                return;
+            } else {
+                if (mQueuedCommands == null) {
+                    mQueuedCommands = new ArrayList<>(1);
+                }
+                mQueuedCommands.add(command);
+                // If we're already connected, don't create a new connection, just leave - the
+                // command will be run when the service connects
+                if (mServiceConnection != null) return;
+            }
+
+            // Create the connection
+            mServiceConnection = new ServiceConnection() {
+                @Override
+                public void onServiceConnected(ComponentName name, IBinder service) {
+                    synchronized (mLock) {
+                        mRemoteService = IFinancialSmsService.Stub.asInterface(service);
+                        if (mQueuedCommands != null) {
+                            final int size = mQueuedCommands.size();
+                            for (int i = 0; i < size; i++) {
+                                final Command queuedCommand = mQueuedCommands.get(i);
+                                try {
+                                    queuedCommand.run(mRemoteService);
+                                } catch (RemoteException e) {
+                                    Slog.w(TAG, "exception calling " + name + ": " + e);
+                                }
+                            }
+                            mQueuedCommands = null;
+                        }
+                    }
+                }
+
+                @Override
+                @MainThread
+                public void onServiceDisconnected(ComponentName name) {
+                    synchronized (mLock) {
+                        mRemoteService = null;
+                    }
+                }
+
+                @Override
+                public void onBindingDied(ComponentName name) {
+                    synchronized (mLock) {
+                        mRemoteService = null;
+                    }
+                }
+
+                @Override
+                public void onNullBinding(ComponentName name) {
+                    synchronized (mLock) {
+                        mRemoteService = null;
+                    }
+                }
+            };
+
+            final ComponentName component = getServiceComponentName();
+            if (component != null) {
+                final Intent intent = new Intent();
+                intent.setComponent(component);
+                final long token = Binder.clearCallingIdentity();
+                try {
+                    mContext.bindServiceAsUser(intent, mServiceConnection, Context.BIND_AUTO_CREATE,
+                            UserHandle.getUserHandleForUid(UserHandle.getCallingUserId()));
+                } finally {
+                    Binder.restoreCallingIdentity(token);
+                }
+            }
+        }
+    }
+
+    void getSmsMessages(RemoteCallback callback, @Nullable Bundle params) {
+        connectAndRun((service) -> service.getSmsMessages(callback, params));
+    }
+
+    void dump(String prefix, PrintWriter pw) {
+        final ComponentName impl = getServiceComponentName();
+        pw.print(prefix); pw.print("User ID: "); pw.println(UserHandle.getCallingUserId());
+        pw.print(prefix); pw.print("Queued commands: ");
+        if (mQueuedCommands == null) {
+            pw.println("N/A");
+        } else {
+            pw.println(mQueuedCommands.size());
+        }
+        pw.print(prefix); pw.print("Implementation: ");
+        if (impl == null) {
+            pw.println("N/A");
+            return;
+        }
+        pw.println(impl.flattenToShortString());
+    }
+
+    private interface Command {
+        void run(IFinancialSmsService service) throws RemoteException;
+    }
+}
diff --git a/services/core/java/com/android/server/role/RoleManagerService.java b/services/core/java/com/android/server/role/RoleManagerService.java
index 1c7596b..7d8c7c9 100644
--- a/services/core/java/com/android/server/role/RoleManagerService.java
+++ b/services/core/java/com/android/server/role/RoleManagerService.java
@@ -33,16 +33,24 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
+import android.content.PermissionChecker;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.pm.PackageManagerInternal;
 import android.content.pm.Signature;
+import android.database.CursorWindow;
 import android.os.Binder;
+import android.os.Bundle;
 import android.os.Handler;
+import android.os.RemoteCallback;
 import android.os.RemoteCallbackList;
 import android.os.RemoteException;
 import android.os.ResultReceiver;
 import android.os.ShellCallback;
 import android.os.UserHandle;
 import android.os.UserManagerInternal;
+import android.service.sms.FinancialSmsService;
+import android.telephony.IFinancialSmsCallback;
 import android.text.TextUtils;
 import android.util.ArraySet;
 import android.util.PackageUtils;
@@ -620,5 +628,51 @@
 
             dumpOutputStream.flush();
         }
+
+        /**
+         * Get filtered SMS messages for financial app.
+         */
+        @Override
+        public void getSmsMessagesForFinancialApp(
+                String callingPkg, Bundle params, IFinancialSmsCallback callback) {
+            int mode = PermissionChecker.checkCallingOrSelfPermission(
+                    getContext(),
+                    AppOpsManager.OPSTR_SMS_FINANCIAL_TRANSACTIONS);
+
+            if (mode == PermissionChecker.PERMISSION_GRANTED) {
+                FinancialSmsManager financialSmsManager = new FinancialSmsManager(getContext());
+                financialSmsManager.getSmsMessages(new RemoteCallback((result) -> {
+                    CursorWindow messages = null;
+                    if (result == null) {
+                        Slog.w(LOG_TAG, "result is null.");
+                    } else {
+                        messages = result.getParcelable(FinancialSmsService.EXTRA_SMS_MSGS);
+                    }
+                    try {
+                        callback.onGetSmsMessagesForFinancialApp(messages);
+                    } catch (RemoteException e) {
+                        // do nothing
+                    }
+                }), params);
+            } else {
+                try {
+                    callback.onGetSmsMessagesForFinancialApp(null);
+                } catch (RemoteException e) {
+                    // do nothing
+                }
+            }
+        }
+
+        private int getUidForPackage(String packageName) {
+            long ident = Binder.clearCallingIdentity();
+            try {
+                return getContext().getPackageManager().getApplicationInfo(packageName,
+                        PackageManager.MATCH_ANY_USER).uid;
+            } catch (NameNotFoundException nnfe) {
+                return -1;
+            } finally {
+                Binder.restoreCallingIdentity(ident);
+            }
+        }
     }
 }
diff --git a/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java b/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
index 6487bd7..e59228a 100644
--- a/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
+++ b/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
@@ -227,7 +227,7 @@
     }
 
     @Override
-    public void executeRollback(RollbackInfo rollback, String callerPackageName,
+    public void commitRollback(int rollbackId, String callerPackageName,
             IntentSender statusReceiver) {
         mContext.enforceCallingOrSelfPermission(
                 android.Manifest.permission.MANAGE_ROLLBACKS,
@@ -238,19 +238,19 @@
         appOps.checkPackage(callingUid, callerPackageName);
 
         getHandler().post(() ->
-                executeRollbackInternal(rollback, callerPackageName, statusReceiver));
+                commitRollbackInternal(rollbackId, callerPackageName, statusReceiver));
     }
 
     /**
-     * Performs the actual work to execute a rollback.
+     * Performs the actual work to commit a rollback.
      * The work is done on the current thread. This may be a long running
      * operation.
      */
-    private void executeRollbackInternal(RollbackInfo rollback,
+    private void commitRollbackInternal(int rollbackId,
             String callerPackageName, IntentSender statusReceiver) {
         Log.i(TAG, "Initiating rollback");
 
-        RollbackData data = getRollbackForId(rollback.getRollbackId());
+        RollbackData data = getRollbackForId(rollbackId);
         if (data == null) {
             sendFailure(statusReceiver, "Rollback unavailable");
             return;
@@ -350,7 +350,8 @@
                                 return;
                             }
 
-                            addRecentlyExecutedRollback(rollback);
+                            addRecentlyExecutedRollback(
+                                    new RollbackInfo(data.rollbackId, data.packages));
                             sendSuccess(statusReceiver);
 
                             Intent broadcast = new Intent(Intent.ACTION_ROLLBACK_COMMITTED);
diff --git a/services/core/java/com/android/server/rollback/RollbackPackageHealthObserver.java b/services/core/java/com/android/server/rollback/RollbackPackageHealthObserver.java
index 3954a11..fcae618 100644
--- a/services/core/java/com/android/server/rollback/RollbackPackageHealthObserver.java
+++ b/services/core/java/com/android/server/rollback/RollbackPackageHealthObserver.java
@@ -27,6 +27,7 @@
 
 import com.android.server.PackageWatchdog;
 import com.android.server.PackageWatchdog.PackageHealthObserver;
+import com.android.server.PackageWatchdog.PackageHealthObserverImpact;
 
 import java.util.List;
 
@@ -39,10 +40,12 @@
     private static final String TAG = "RollbackPackageHealthObserver";
     private static final String NAME = "rollback-observer";
     private Context mContext;
+    private RollbackManager mRollbackManager;
     private Handler mHandler;
 
     RollbackPackageHealthObserver(Context context) {
         mContext = context;
+        mRollbackManager = mContext.getSystemService(RollbackManager.class);
         HandlerThread handlerThread = new HandlerThread("RollbackPackageHealthObserver");
         handlerThread.start();
         mHandler = handlerThread.getThreadHandler();
@@ -50,19 +53,48 @@
     }
 
     @Override
-    public boolean onHealthCheckFailed(String packageName) {
-        RollbackManager rollbackManager = mContext.getSystemService(RollbackManager.class);
-        for (RollbackInfo rollback : rollbackManager.getAvailableRollbacks()) {
-            for (PackageRollbackInfo packageRollback : rollback.getPackages()) {
-                if (packageName.equals(packageRollback.getPackageName())) {
-                    // TODO(zezeozue): Only rollback if rollback version == failed package version
-                    mHandler.post(() -> executeRollback(rollbackManager, rollback));
-                    return true;
-                }
-            }
+    public int onHealthCheckFailed(String packageName) {
+        RollbackInfo rollback = getAvailableRollback(packageName);
+        if (rollback == null) {
+            // Don't handle the notification, no rollbacks available for the package
+            return PackageHealthObserverImpact.USER_IMPACT_NONE;
         }
-        // Don't handle the notification, no rollbacks available
-        return false;
+        // Rollback is available, we may get a callback into #execute
+        return PackageHealthObserverImpact.USER_IMPACT_MEDIUM;
+    }
+
+    @Override
+    public boolean execute(String packageName) {
+        RollbackInfo rollback = getAvailableRollback(packageName);
+        if (rollback == null) {
+            // Expected a rollback to be available, what happened?
+            return false;
+        }
+
+        // TODO(zezeozue): Only rollback if rollback version == failed package version
+        LocalIntentReceiver rollbackReceiver = new LocalIntentReceiver((Intent result) -> {
+            int status = result.getIntExtra(PackageInstaller.EXTRA_STATUS,
+                    PackageInstaller.STATUS_FAILURE);
+            if (status == PackageInstaller.STATUS_SUCCESS) {
+                // TODO(zezeozue); Log success metrics
+                // Rolledback successfully, no action required by other observers
+            } else {
+                // TODO(zezeozue); Log failure metrics
+                // Rollback failed other observers should have a shot
+            }
+        });
+
+        // TODO(zezeozue): Log initiated metrics
+        mHandler.post(() ->
+                mRollbackManager.commitRollback(rollback.getRollbackId(),
+                    rollbackReceiver.getIntentSender()));
+        // Assume rollback executed successfully
+        return true;
+    }
+
+    @Override
+    public String getName() {
+        return NAME;
     }
 
     /**
@@ -73,26 +105,15 @@
         PackageWatchdog.getInstance(mContext).startObservingHealth(this, packages, durationMs);
     }
 
-    private void executeRollback(RollbackManager manager, RollbackInfo rollback) {
-        // TODO(zezeozue): Log initiated metrics
-        LocalIntentReceiver rollbackReceiver = new LocalIntentReceiver((Intent result) -> {
-            mHandler.post(() -> {
-                int status = result.getIntExtra(PackageInstaller.EXTRA_STATUS,
-                        PackageInstaller.STATUS_FAILURE);
-                if (status == PackageInstaller.STATUS_SUCCESS) {
-                    // TODO(zezeozue); Log success metrics
-                    // Rolledback successfully, no action required by other observers
-                } else {
-                    // TODO(zezeozue); Log failure metrics
-                    // Rollback failed other observers should have a shot
+    private RollbackInfo getAvailableRollback(String packageName) {
+        for (RollbackInfo rollback : mRollbackManager.getAvailableRollbacks()) {
+            for (PackageRollbackInfo packageRollback : rollback.getPackages()) {
+                if (packageName.equals(packageRollback.getPackageName())) {
+                    // TODO(zezeozue): Only rollback if rollback version == failed package version
+                    return rollback;
                 }
-            });
-        });
-        manager.commitRollback(rollback, rollbackReceiver.getIntentSender());
-    }
-
-    @Override
-    public String getName() {
-        return NAME;
+            }
+        }
+        return null;
     }
 }
diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java b/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java
index a66f0ca..b9b5aae 100644
--- a/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java
+++ b/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java
@@ -100,4 +100,11 @@
      * @param rotation rotation suggestion
      */
     void onProposedRotationChanged(int rotation, boolean isValid);
+
+    /**
+     * Notifies System UI that the display is ready to show system decorations.
+     *
+     * @param displayId display ID
+     */
+    void onDisplayReady(int displayId);
 }
diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
index 8d2bab4..7e87c29 100644
--- a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
+++ b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
@@ -443,6 +443,15 @@
                 } catch (RemoteException ex) {}
             }
         }
+
+        @Override
+        public void onDisplayReady(int displayId) {
+            if (mBar != null) {
+                try {
+                    mBar.onDisplayReady(displayId);
+                } catch (RemoteException ex) { }
+            }
+        }
     };
 
     private final GlobalActionsProvider mGlobalActionsProvider = new GlobalActionsProvider() {
diff --git a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
index 69040a2..b0ef8a0 100644
--- a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
+++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
@@ -469,6 +469,7 @@
      */
     private void extractColors(WallpaperData wallpaper) {
         String cropFile = null;
+        boolean defaultImageWallpaper = false;
         int wallpaperId;
 
         if (wallpaper.equals(mFallbackWallpaper)) {
@@ -482,6 +483,8 @@
                     || wallpaper.wallpaperComponent == null;
             if (imageWallpaper && wallpaper.cropFile != null && wallpaper.cropFile.exists()) {
                 cropFile = wallpaper.cropFile.getAbsolutePath();
+            } else if (imageWallpaper && !wallpaper.cropExists() && !wallpaper.sourceExists()) {
+                defaultImageWallpaper = true;
             }
             wallpaperId = wallpaper.wallpaperId;
         }
@@ -493,6 +496,25 @@
                 colors = WallpaperColors.fromBitmap(bitmap);
                 bitmap.recycle();
             }
+        } else if (defaultImageWallpaper) {
+            // There is no crop and source file because this is default image wallpaper.
+            try (final InputStream is =
+                         WallpaperManager.openDefaultWallpaper(mContext, FLAG_SYSTEM)) {
+                if (is != null) {
+                    try {
+                        final BitmapFactory.Options options = new BitmapFactory.Options();
+                        final Bitmap bitmap = BitmapFactory.decodeStream(is, null, options);
+                        if (bitmap != null) {
+                            colors = WallpaperColors.fromBitmap(bitmap);
+                            bitmap.recycle();
+                        }
+                    } catch (OutOfMemoryError e) {
+                        Slog.w(TAG, "Can't decode default wallpaper stream", e);
+                    }
+                }
+            } catch (IOException e) {
+                Slog.w(TAG, "Can't close default wallpaper stream", e);
+            }
         }
 
         if (colors == null) {
diff --git a/services/core/java/com/android/server/wm/ActivityMetricsLogger.java b/services/core/java/com/android/server/wm/ActivityMetricsLogger.java
index 1023182..2d89bc7 100644
--- a/services/core/java/com/android/server/wm/ActivityMetricsLogger.java
+++ b/services/core/java/com/android/server/wm/ActivityMetricsLogger.java
@@ -544,6 +544,16 @@
         mHandler.obtainMessage(MSG_CHECK_VISIBILITY, args).sendToTarget();
     }
 
+    private boolean hasVisibleNonFinishingActivity(TaskRecord t) {
+        for (int i = t.mActivities.size() - 1; i >= 0; --i) {
+            final ActivityRecord r = t.mActivities.get(i);
+            if (r.visible && !r.finishing) {
+                return true;
+            }
+        }
+        return false;
+    }
+
     private void checkVisibility(TaskRecord t, ActivityRecord r) {
         synchronized (mSupervisor.mService.mGlobalLock) {
 
@@ -552,7 +562,7 @@
 
             // If we have an active transition that's waiting on a certain activity that will be
             // invisible now, we'll never get onWindowsDrawn, so abort the transition if necessary.
-            if (info != null && !t.isVisible()) {
+            if (info != null && !hasVisibleNonFinishingActivity(t)) {
                 if (DEBUG_METRICS) Slog.i(TAG, "notifyVisibilityChanged to invisible"
                         + " activity=" + r);
                 logAppTransitionCancel(info);
@@ -841,13 +851,11 @@
         Log.i(TAG, sb.toString());
     }
 
-    void logActivityStart(Intent intent, WindowProcessController callerApp, ActivityRecord r,
+    void logAbortedBgActivityStart(Intent intent, WindowProcessController callerApp,
             int callingUid, String callingPackage, int callingUidProcState,
             boolean callingUidHasAnyVisibleWindow,
             int realCallingUid, int realCallingUidProcState,
             boolean realCallingUidHasAnyVisibleWindow,
-            int targetUid, String targetPackage, int targetUidProcState,
-            boolean targetUidHasAnyVisibleWindow, String targetWhitelistTag,
             boolean comingFromPendingIntent) {
 
         final long nowElapsed = SystemClock.elapsedRealtime();
@@ -865,13 +873,6 @@
                 processStateAmToProto(realCallingUidProcState));
         builder.addTaggedData(FIELD_REAL_CALLING_UID_HAS_ANY_VISIBLE_WINDOW,
                 realCallingUidHasAnyVisibleWindow ? 1 : 0);
-        builder.addTaggedData(FIELD_TARGET_UID, targetUid);
-        builder.addTaggedData(FIELD_TARGET_PACKAGE_NAME, targetPackage);
-        builder.addTaggedData(FIELD_TARGET_UID_PROC_STATE,
-                processStateAmToProto(targetUidProcState));
-        builder.addTaggedData(FIELD_TARGET_UID_HAS_ANY_VISIBLE_WINDOW,
-                targetUidHasAnyVisibleWindow ? 1 : 0);
-        builder.addTaggedData(FIELD_TARGET_WHITELIST_TAG, targetWhitelistTag);
         builder.addTaggedData(FIELD_COMING_FROM_PENDING_INTENT, comingFromPendingIntent ? 1 : 0);
         if (intent != null) {
             builder.addTaggedData(FIELD_INTENT_ACTION, intent.getAction());
@@ -904,35 +905,6 @@
                         (nowUptime - callerApp.getWhenUnimportant()));
             }
         }
-        if (r != null) {
-            builder.addTaggedData(FIELD_TARGET_SHORT_COMPONENT_NAME, r.shortComponentName);
-            builder.addTaggedData(FIELD_ACTIVITY_RECORD_LAUNCH_MODE, r.info.launchMode);
-            builder.addTaggedData(FIELD_ACTIVITY_RECORD_TARGET_ACTIVITY, r.info.targetActivity);
-            builder.addTaggedData(FIELD_ACTIVITY_RECORD_FLAGS, r.info.flags);
-            builder.addTaggedData(FIELD_ACTIVITY_RECORD_REAL_ACTIVITY,
-                    r.mActivityComponent.toShortString());
-            builder.addTaggedData(FIELD_ACTIVITY_RECORD_SHORT_COMPONENT_NAME, r.shortComponentName);
-            builder.addTaggedData(FIELD_ACTIVITY_RECORD_PROCESS_NAME, r.processName);
-            builder.addTaggedData(FIELD_ACTIVITY_RECORD_IS_FULLSCREEN, r.fullscreen ? 1 : 0);
-            builder.addTaggedData(FIELD_ACTIVITY_RECORD_IS_NO_DISPLAY, r.noDisplay ? 1 : 0);
-            if (r.lastVisibleTime != 0) {
-                builder.addTaggedData(FIELD_ACTIVITY_RECORD_MILLIS_SINCE_LAST_VISIBLE,
-                        (nowUptime - r.lastVisibleTime));
-            }
-            if (r.resultTo != null) {
-                builder.addTaggedData(FIELD_ACTIVITY_RECORD_RESULT_TO_PKG_NAME,
-                        r.resultTo.packageName);
-                builder.addTaggedData(FIELD_ACTIVITY_RECORD_RESULT_TO_SHORT_COMPONENT_NAME,
-                        r.resultTo.shortComponentName);
-            }
-            builder.addTaggedData(FIELD_ACTIVITY_RECORD_IS_VISIBLE, r.visible ? 1 : 0);
-            builder.addTaggedData(FIELD_ACTIVITY_RECORD_IS_VISIBLE_IGNORING_KEYGUARD,
-                    r.visibleIgnoringKeyguard ? 1 : 0);
-            if (r.lastLaunchTime != 0) {
-                builder.addTaggedData(FIELD_ACTIVITY_RECORD_MILLIS_SINCE_LAST_LAUNCH,
-                        (nowUptime - r.lastLaunchTime));
-            }
-        }
         mMetricsLogger.write(builder);
     }
 
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index b7c35c0..8f39f3d 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -161,6 +161,7 @@
 import android.app.servertransaction.PauseActivityItem;
 import android.app.servertransaction.PipModeChangeItem;
 import android.app.servertransaction.ResumeActivityItem;
+import android.app.servertransaction.TopResumedActivityChangeItem;
 import android.app.servertransaction.WindowVisibilityItem;
 import android.app.usage.UsageEvents.Event;
 import android.content.ComponentName;
@@ -692,6 +693,26 @@
         }
     }
 
+    void scheduleTopResumedActivityChanged(boolean onTop) {
+        if (!attachedToProcess()) {
+            if (DEBUG_CONFIGURATION) {
+                Slog.w(TAG, "Can't report activity position update - client not running"
+                                + ", activityRecord=" + this);
+            }
+            return;
+        }
+        try {
+            if (DEBUG_CONFIGURATION) {
+                Slog.v(TAG, "Sending position change to " + this + ", onTop: " + onTop);
+            }
+
+            mAtmService.getLifecycleManager().scheduleTransaction(app.getThread(), appToken,
+                    TopResumedActivityChangeItem.obtain(onTop));
+        } catch (RemoteException e) {
+            // If process died, whatever.
+        }
+    }
+
     void updateMultiWindowMode() {
         if (task == null || task.getStack() == null || !attachedToProcess()) {
             return;
@@ -3099,6 +3120,7 @@
             transaction.addCallback(callbackItem);
             transaction.setLifecycleStateRequest(lifecycleItem);
             mAtmService.getLifecycleManager().scheduleTransaction(transaction);
+            mRootActivityContainer.updateTopResumedActivityIfNeeded();
             // Note: don't need to call pauseIfSleepingLocked() here, because the caller will only
             // request resume if this activity is currently resumed, which implies we aren't
             // sleeping.
diff --git a/services/core/java/com/android/server/wm/ActivityStack.java b/services/core/java/com/android/server/wm/ActivityStack.java
index c97e4e8..549567a 100644
--- a/services/core/java/com/android/server/wm/ActivityStack.java
+++ b/services/core/java/com/android/server/wm/ActivityStack.java
@@ -2524,6 +2524,7 @@
             // Protect against recursion.
             mInResumeTopActivity = true;
             result = resumeTopActivityInnerLocked(prev, options);
+            mRootActivityContainer.updateTopResumedActivityIfNeeded();
 
             // When resuming the top activity, it may be necessary to pause the top activity (for
             // example, returning to the lock screen. We suppress the normal pause logic in
diff --git a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
index a83ef34..c8a150b 100644
--- a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
@@ -840,6 +840,7 @@
 
                 // Schedule transaction.
                 mService.getLifecycleManager().scheduleTransaction(clientTransaction);
+                mRootActivityContainer.updateTopResumedActivityIfNeeded();
 
                 if ((proc.mInfo.privateFlags & ApplicationInfo.PRIVATE_FLAG_CANT_SAVE_STATE) != 0
                         && mService.mHasHeavyWeightFeature) {
diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java
index 22a81ef..95a6f71 100644
--- a/services/core/java/com/android/server/wm/ActivityStarter.java
+++ b/services/core/java/com/android/server/wm/ActivityStarter.java
@@ -749,9 +749,15 @@
 
         boolean abortBackgroundStart = false;
         if (!abort) {
-            abortBackgroundStart = shouldAbortBackgroundActivityStart(callingUid, callingPid,
-                    callingPackage, realCallingUid, callerApp, originatingPendingIntent,
-                    allowBackgroundActivityStart, intent);
+            try {
+                Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER,
+                        "shouldAbortBackgroundActivityStart");
+                abortBackgroundStart = shouldAbortBackgroundActivityStart(callingUid, callingPid,
+                        callingPackage, realCallingUid, callerApp, originatingPendingIntent,
+                        allowBackgroundActivityStart, intent);
+            } finally {
+                Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
+            }
             abort |= (abortBackgroundStart && !mService.isBackgroundActivityStartsEnabled());
             // TODO: remove this toast after feature development is done
             if (abortBackgroundStart) {
@@ -903,12 +909,6 @@
         mService.onStartActivitySetDidAppSwitch();
         mController.doPendingActivityLaunches(false);
 
-        // maybe log to TRON, but only if we haven't already in shouldAbortBackgroundActivityStart()
-        if (!abortBackgroundStart) {
-            maybeLogActivityStart(callingUid, callingPackage, realCallingUid, intent, callerApp, r,
-                    originatingPendingIntent, false /*abortedStart*/);
-        }
-
         return startActivity(r, sourceRecord, voiceSession, voiceInteractor, startFlags,
                 true /* doResume */, checkedOptions, inTask, outActivity);
     }
@@ -927,17 +927,31 @@
             return false;
         }
         // don't abort if the callingUid is in the foreground or is a persistent system process
-        final boolean isCallingUidForeground = mService.isUidForeground(callingUid);
-        final boolean isCallingUidPersistentSystemProcess = isUidPersistentSystemProcess(
-                callingUid);
+        final int callingUidProcState = mService.getUidStateLocked(callingUid);
+        final boolean callingUidHasAnyVisibleWindow =
+                mService.mWindowManager.mRoot.isAnyNonToastWindowVisibleForUid(callingUid);
+        final boolean isCallingUidForeground = callingUidHasAnyVisibleWindow
+                || callingUidProcState == ActivityManager.PROCESS_STATE_TOP;
+        final boolean isCallingUidPersistentSystemProcess = (callingUid == Process.SYSTEM_UID)
+                || callingUidProcState <= ActivityManager.PROCESS_STATE_PERSISTENT_UI;
         if (isCallingUidForeground || isCallingUidPersistentSystemProcess) {
             return false;
         }
         // take realCallingUid into consideration
-        final boolean isRealCallingUidForeground = mService.isUidForeground(
-                realCallingUid);
-        final boolean isRealCallingUidPersistentSystemProcess = isUidPersistentSystemProcess(
-                realCallingUid);
+        final int realCallingUidProcState = (callingUid == realCallingUid)
+                ? callingUidProcState
+                : mService.getUidStateLocked(realCallingUid);
+        final boolean realCallingUidHasAnyVisibleWindow = (callingUid == realCallingUid)
+                ? callingUidHasAnyVisibleWindow
+                : mService.mWindowManager.mRoot.isAnyNonToastWindowVisibleForUid(realCallingUid);
+        final boolean isRealCallingUidForeground = (callingUid == realCallingUid)
+                ? isCallingUidForeground
+                : realCallingUidHasAnyVisibleWindow
+                        || realCallingUidProcState == ActivityManager.PROCESS_STATE_TOP;
+        final boolean isRealCallingUidPersistentSystemProcess = (callingUid == realCallingUid)
+                ? isCallingUidPersistentSystemProcess
+                : (realCallingUid == Process.SYSTEM_UID)
+                        || realCallingUidProcState <= ActivityManager.PROCESS_STATE_PERSISTENT_UI;
         if (realCallingUid != callingUid) {
             // don't abort if the realCallingUid is in the foreground and callingUid isn't
             if (isRealCallingUidForeground) {
@@ -975,60 +989,14 @@
                 + "; isBgStartWhitelisted: " + allowBackgroundActivityStart
                 + "; intent: " + intent
                 + "]");
-        maybeLogActivityStart(callingUid, callingPackage, realCallingUid, intent, callerApp,
-                null /*r*/, originatingPendingIntent, true /*abortedStart*/);
-        return true;
-    }
-
-    /** Returns true if uid is in a persistent state. */
-    private boolean isUidPersistentSystemProcess(int uid) {
-        return (mService.getUidStateLocked(uid) <= ActivityManager.PROCESS_STATE_PERSISTENT_UI);
-    }
-
-    private void maybeLogActivityStart(int callingUid, String callingPackage, int realCallingUid,
-            Intent intent, WindowProcessController callerApp, ActivityRecord r,
-            PendingIntentRecord originatingPendingIntent, boolean abortedStart) {
-        boolean callerAppHasForegroundActivity =
-                callerApp != null && callerApp.hasForegroundActivities();
-        if (!mService.isActivityStartsLoggingEnabled() || callerAppHasForegroundActivity
-                || (!abortedStart && r == null)) {
-            // skip logging in this case
-            return;
-        }
-
-        try {
-            Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "logActivityStart");
-            final int callingUidProcState = mService.getUidStateLocked(callingUid);
-            final boolean callingUidHasAnyVisibleWindow =
-                    mService.mWindowManager.mRoot.isAnyNonToastWindowVisibleForUid(callingUid);
-            final int realCallingUidProcState = (callingUid == realCallingUid)
-                    ? callingUidProcState
-                    : mService.getUidStateLocked(realCallingUid);
-            final boolean realCallingUidHasAnyVisibleWindow = (callingUid == realCallingUid)
-                    ? callingUidHasAnyVisibleWindow
-                    : mService.mWindowManager.mRoot.isAnyNonToastWindowVisibleForUid(
-                            realCallingUid);
-            final String targetPackage = (r != null) ? r.packageName : null;
-            final int targetUid = (r!= null) ? ((r.appInfo != null) ? r.appInfo.uid : -1) : -1;
-            final int targetUidProcState = mService.getUidStateLocked(targetUid);
-            final boolean targetUidHasAnyVisibleWindow = (targetUid != -1)
-                    ? mService.mWindowManager.mRoot.isAnyNonToastWindowVisibleForUid(targetUid)
-                    : false;
-            final String targetWhitelistTag = (targetUid != -1)
-                    ? mService.getPendingTempWhitelistTagForUidLocked(targetUid)
-                    : null;
-
-            mSupervisor.getActivityMetricsLogger().logActivityStart(intent, callerApp, r,
-                    callingUid, callingPackage, callingUidProcState,
-                    callingUidHasAnyVisibleWindow,
-                    realCallingUid, realCallingUidProcState,
-                    realCallingUidHasAnyVisibleWindow,
-                    targetUid, targetPackage, targetUidProcState,
-                    targetUidHasAnyVisibleWindow, targetWhitelistTag,
+        // log aborted activity start to TRON
+        if (mService.isActivityStartsLoggingEnabled()) {
+            mSupervisor.getActivityMetricsLogger().logAbortedBgActivityStart(intent, callerApp,
+                    callingUid, callingPackage, callingUidProcState, callingUidHasAnyVisibleWindow,
+                    realCallingUid, realCallingUidProcState, realCallingUidHasAnyVisibleWindow,
                     (originatingPendingIntent != null));
-        } finally {
-            Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
         }
+        return true;
     }
 
     /**
diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java
index 4006332..bbf115f 100644
--- a/services/core/java/com/android/server/wm/DisplayPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayPolicy.java
@@ -2574,6 +2574,10 @@
         }
     }
 
+    void notifyDisplayReady() {
+        mHandler.post(() -> getStatusBarManagerInternal().onDisplayReady(getDisplayId()));
+    }
+
     /**
      * Return the display width available after excluding any screen
      * decorations that could never be removed in Honeycomb. That is, system bar or
diff --git a/services/core/java/com/android/server/wm/InsetsSourceProvider.java b/services/core/java/com/android/server/wm/InsetsSourceProvider.java
index e798203..66666e6 100644
--- a/services/core/java/com/android/server/wm/InsetsSourceProvider.java
+++ b/services/core/java/com/android/server/wm/InsetsSourceProvider.java
@@ -69,7 +69,7 @@
 
     InsetsSourceProvider(InsetsSource source, InsetsStateController stateController,
             DisplayContent displayContent) {
-        mClientVisible = InsetsState.getDefaultVisibly(source.getType());
+        mClientVisible = InsetsState.getDefaultVisibility(source.getType());
         mSource = source;
         mDisplayContent = displayContent;
         mStateController = stateController;
@@ -153,6 +153,7 @@
             return;
         }
         mAdapter = new ControlAdapter();
+        setClientVisible(InsetsState.getDefaultVisibility(mSource.getType()));
         mWin.startAnimation(mDisplayContent.getPendingTransaction(), mAdapter,
                 !mClientVisible /* hidden */);
         mControllingWin = target;
@@ -219,7 +220,7 @@
         public void onAnimationCancelled(SurfaceControl animationLeash) {
             if (mAdapter == this) {
                 mStateController.notifyControlRevoked(mControllingWin, InsetsSourceProvider.this);
-                setClientVisible(InsetsState.getDefaultVisibly(mSource.getType()));
+                setClientVisible(InsetsState.getDefaultVisibility(mSource.getType()));
                 mControl = null;
                 mControllingWin = null;
                 mAdapter = null;
diff --git a/services/core/java/com/android/server/wm/RootActivityContainer.java b/services/core/java/com/android/server/wm/RootActivityContainer.java
index c4a853d..624fdc2 100644
--- a/services/core/java/com/android/server/wm/RootActivityContainer.java
+++ b/services/core/java/com/android/server/wm/RootActivityContainer.java
@@ -175,6 +175,12 @@
     private ActivityDisplay mDefaultDisplay;
     private final SparseArray<IntArray> mDisplayAccessUIDs = new SparseArray<>();
 
+    /**
+     * Cached value of the topmost resumed activity in the system. Updated when new activity is
+     * resumed.
+     */
+    private ActivityRecord mTopResumedActivity;
+
     /** The current user */
     int mCurrentUser;
     /** Stack id of the front stack when user switched, indexed by userId. */
@@ -1145,6 +1151,23 @@
         return result;
     }
 
+    void updateTopResumedActivityIfNeeded() {
+        final ActivityRecord prevTopActivity = mTopResumedActivity;
+        final ActivityStack topStack = getTopDisplayFocusedStack();
+        if (topStack == null || topStack.mResumedActivity == prevTopActivity) {
+            return;
+        }
+        // Clear previous top state
+        if (prevTopActivity != null) {
+            prevTopActivity.scheduleTopResumedActivityChanged(false /* onTop */);
+        }
+        // Update the current top activity
+        mTopResumedActivity = topStack.mResumedActivity;
+        if (mTopResumedActivity != null) {
+            mTopResumedActivity.scheduleTopResumedActivityChanged(true /* onTop */);
+        }
+    }
+
     void applySleepTokens(boolean applyToStacks) {
         for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
             // Set the sleeping state of the display.
@@ -1296,16 +1319,21 @@
     public void onDisplayAdded(int displayId) {
         if (DEBUG_STACK) Slog.v(TAG, "Display added displayId=" + displayId);
         synchronized (mService.mGlobalLock) {
-            getActivityDisplayOrCreate(displayId);
+            final ActivityDisplay display = getActivityDisplayOrCreate(displayId);
             // Do not start home before booting, or it may accidentally finish booting before it
             // starts. Instead, we expect home activities to be launched when the system is ready
             // (ActivityManagerService#systemReady).
             if (mService.isBooted() || mService.isBooting()) {
-                startHomeOnDisplay(mCurrentUser, "displayAdded", displayId);
+                startSystemDecorations(display.mDisplayContent);
             }
         }
     }
 
+    private void startSystemDecorations(final DisplayContent displayContent) {
+        startHomeOnDisplay(mCurrentUser, "displayAdded", displayContent.getDisplayId());
+        displayContent.getDisplayPolicy().notifyDisplayReady();
+    }
+
     @Override
     public void onDisplayRemoved(int displayId) {
         if (DEBUG_STACK) Slog.v(TAG, "Display removed displayId=" + displayId);
@@ -1399,6 +1427,7 @@
             mActivityDisplays.remove(display);
             mActivityDisplays.add(position, display);
         }
+        updateTopResumedActivityIfNeeded();
     }
 
     @VisibleForTesting
diff --git a/services/core/jni/com_android_server_security_VerityUtils.cpp b/services/core/jni/com_android_server_security_VerityUtils.cpp
index 7dd30bd..0d888dc 100644
--- a/services/core/jni/com_android_server_security_VerityUtils.cpp
+++ b/services/core/jni/com_android_server_security_VerityUtils.cpp
@@ -29,12 +29,9 @@
 
 #include <android-base/unique_fd.h>
 
-// TODO(112037636): Always include once fsverity.h is upstreamed and backported.
-#define HAS_FSVERITY 0
-
-#if HAS_FSVERITY
+// TODO(112037636): Always include once fsverity.h is upstreamed.
+#if __has_include(<linux/fsverity.h>)
 #include <linux/fsverity.h>
-
 const int kSha256Bytes = 32;
 #endif
 
@@ -76,7 +73,7 @@
 };
 
 int enableFsverity(JNIEnv* env, jobject /* clazz */, jstring filePath) {
-#if HAS_FSVERITY
+#if __has_include(<linux/fsverity.h>)
     const char* path = env->GetStringUTFChars(filePath, nullptr);
     ::android::base::unique_fd rfd(open(path, O_RDONLY | O_CLOEXEC));
     if (rfd.get() < 0) {
@@ -89,11 +86,11 @@
 #else
     LOG_ALWAYS_FATAL("fs-verity is used while not enabled");
     return ENOSYS;
-#endif  // HAS_FSVERITY
+#endif
 }
 
 int measureFsverity(JNIEnv* env, jobject /* clazz */, jstring filePath) {
-#if HAS_FSVERITY
+#if __has_include(<linux/fsverity.h>)
     auto raii = JavaByteArrayHolder::newArray(env, sizeof(fsverity_digest) + kSha256Bytes);
     fsverity_digest* data = reinterpret_cast<fsverity_digest*>(raii->getRaw());
     data->digest_size = kSha256Bytes;  // the only input/output parameter
@@ -110,11 +107,11 @@
 #else
     LOG_ALWAYS_FATAL("fs-verity is used while not enabled");
     return ENOSYS;
-#endif  // HAS_FSVERITY
+#endif
 }
 
 jbyteArray constructFsveritySignedData(JNIEnv* env, jobject /* clazz */, jbyteArray digest) {
-#if HAS_FSVERITY
+#if __has_include(<linux/fsverity.h>)
     auto raii = JavaByteArrayHolder::newArray(env, sizeof(fsverity_digest_disk) + kSha256Bytes);
     fsverity_digest_disk* data = reinterpret_cast<fsverity_digest_disk*>(raii->getRaw());
 
@@ -132,12 +129,12 @@
 #else
     LOG_ALWAYS_FATAL("fs-verity is used while not enabled");
     return 0;
-#endif  // HAS_FSVERITY
+#endif
 }
 
 
 jbyteArray constructFsverityDescriptor(JNIEnv* env, jobject /* clazz */, jlong fileSize) {
-#if HAS_FSVERITY
+#if __has_include(<linux/fsverity.h>)
     auto raii = JavaByteArrayHolder::newArray(env, sizeof(fsverity_descriptor));
     fsverity_descriptor* desc = reinterpret_cast<fsverity_descriptor*>(raii->getRaw());
 
@@ -156,12 +153,12 @@
 #else
     LOG_ALWAYS_FATAL("fs-verity is used while not enabled");
     return 0;
-#endif  // HAS_FSVERITY
+#endif
 }
 
 jbyteArray constructFsverityExtension(JNIEnv* env, jobject /* clazz */, jshort extensionId,
         jint extensionDataSize) {
-#if HAS_FSVERITY
+#if __has_include(<linux/fsverity.h>)
     auto raii = JavaByteArrayHolder::newArray(env, sizeof(fsverity_extension));
     fsverity_extension* ext = reinterpret_cast<fsverity_extension*>(raii->getRaw());
 
@@ -172,12 +169,12 @@
 #else
     LOG_ALWAYS_FATAL("fs-verity is used while not enabled");
     return 0;
-#endif  // HAS_FSVERITY
+#endif
 }
 
 jbyteArray constructFsverityFooter(JNIEnv* env, jobject /* clazz */,
         jint offsetToDescriptorHead) {
-#if HAS_FSVERITY
+#if __has_include(<linux/fsverity.h>)
     auto raii = JavaByteArrayHolder::newArray(env, sizeof(fsverity_footer));
     fsverity_footer* footer = reinterpret_cast<fsverity_footer*>(raii->getRaw());
 
@@ -188,7 +185,7 @@
 #else
     LOG_ALWAYS_FATAL("fs-verity is used while not enabled");
     return 0;
-#endif  // HAS_FSVERITY
+#endif
 }
 
 const JNINativeMethod sMethods[] = {
diff --git a/services/ipmemorystore/java/com/android/server/net/ipmemorystore/IpMemoryStoreDatabase.java b/services/ipmemorystore/java/com/android/server/net/ipmemorystore/IpMemoryStoreDatabase.java
index e99dd4f..bbecc63 100644
--- a/services/ipmemorystore/java/com/android/server/net/ipmemorystore/IpMemoryStoreDatabase.java
+++ b/services/ipmemorystore/java/com/android/server/net/ipmemorystore/IpMemoryStoreDatabase.java
@@ -16,6 +16,9 @@
 
 package com.android.server.net.ipmemorystore;
 
+import static android.net.shared.Inet4AddressUtils.inet4AddressToIntHTH;
+import static android.net.shared.Inet4AddressUtils.intToInet4AddressHTH;
+
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.content.ContentValues;
@@ -27,7 +30,6 @@
 import android.database.sqlite.SQLiteException;
 import android.database.sqlite.SQLiteOpenHelper;
 import android.database.sqlite.SQLiteQuery;
-import android.net.NetworkUtils;
 import android.net.ipmemorystore.NetworkAttributes;
 import android.net.ipmemorystore.Status;
 import android.util.Log;
@@ -200,7 +202,7 @@
         if (null == attributes) return values;
         if (null != attributes.assignedV4Address) {
             values.put(NetworkAttributesContract.COLNAME_ASSIGNEDV4ADDRESS,
-                    NetworkUtils.inet4AddressToIntHTH(attributes.assignedV4Address));
+                    inet4AddressToIntHTH(attributes.assignedV4Address));
         }
         if (null != attributes.groupHint) {
             values.put(NetworkAttributesContract.COLNAME_GROUPHINT, attributes.groupHint);
@@ -254,7 +256,7 @@
                 getBlob(cursor, NetworkAttributesContract.COLNAME_DNSADDRESSES);
         final int mtu = getInt(cursor, NetworkAttributesContract.COLNAME_MTU, -1);
         if (0 != assignedV4AddressInt) {
-            builder.setAssignedV4Address(NetworkUtils.intToInet4AddressHTH(assignedV4AddressInt));
+            builder.setAssignedV4Address(intToInet4AddressHTH(assignedV4AddressInt));
         }
         builder.setGroupHint(groupHint);
         if (null != dnsAddressesBlob) {
diff --git a/services/net/java/android/net/dhcp/DhcpServingParamsParcelExt.java b/services/net/java/android/net/dhcp/DhcpServingParamsParcelExt.java
index f068c3a..1fe2328 100644
--- a/services/net/java/android/net/dhcp/DhcpServingParamsParcelExt.java
+++ b/services/net/java/android/net/dhcp/DhcpServingParamsParcelExt.java
@@ -16,7 +16,7 @@
 
 package android.net.dhcp;
 
-import static android.net.NetworkUtils.inet4AddressToIntHTH;
+import static android.net.shared.Inet4AddressUtils.inet4AddressToIntHTH;
 
 import android.annotation.NonNull;
 import android.net.LinkAddress;
diff --git a/services/net/java/android/net/shared/IpConfigurationParcelableUtil.java b/services/net/java/android/net/shared/IpConfigurationParcelableUtil.java
index 2c368c8..0007350 100644
--- a/services/net/java/android/net/shared/IpConfigurationParcelableUtil.java
+++ b/services/net/java/android/net/shared/IpConfigurationParcelableUtil.java
@@ -73,7 +73,7 @@
     public static DhcpResultsParcelable toStableParcelable(@Nullable DhcpResults results) {
         if (results == null) return null;
         final DhcpResultsParcelable p = new DhcpResultsParcelable();
-        p.baseConfiguration = toStableParcelable((StaticIpConfiguration) results);
+        p.baseConfiguration = toStableParcelable(results.toStaticIpConfiguration());
         p.leaseDuration = results.leaseDuration;
         p.mtu = results.mtu;
         p.serverAddress = parcelAddress(results.serverAddress);
diff --git a/services/net/java/android/net/shared/NetdService.java b/services/net/java/android/net/shared/NetdService.java
index be0f5f2..f5ae725 100644
--- a/services/net/java/android/net/shared/NetdService.java
+++ b/services/net/java/android/net/shared/NetdService.java
@@ -16,6 +16,7 @@
 
 package android.net.shared;
 
+import android.content.Context;
 import android.net.INetd;
 import android.os.RemoteException;
 import android.os.ServiceManager;
@@ -28,7 +29,6 @@
  */
 public class NetdService {
     private static final String TAG = NetdService.class.getSimpleName();
-    private static final String NETD_SERVICE_NAME = "netd";
     private static final long BASE_TIMEOUT_MS = 100;
     private static final long MAX_TIMEOUT_MS = 1000;
 
@@ -48,7 +48,7 @@
         // NOTE: ServiceManager does no caching for the netd service,
         // because netd is not one of the defined common services.
         final INetd netdInstance = INetd.Stub.asInterface(
-                ServiceManager.getService(NETD_SERVICE_NAME));
+                ServiceManager.getService(Context.NETD_SERVICE));
         if (netdInstance == null) {
             Log.w(TAG, "WARNING: returning null INetd instance.");
         }
diff --git a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java
index 3172afb..76beb8f 100644
--- a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java
+++ b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java
@@ -75,6 +75,7 @@
 import android.content.ActivityNotFoundException;
 import android.content.ComponentName;
 import android.content.Intent;
+import android.content.IntentFilter;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.LauncherApps;
 import android.content.pm.LauncherApps.PinItemRequest;
@@ -6274,6 +6275,17 @@
         mManager.onApplicationActive(CALLING_PACKAGE_1, USER_0);
     }
 
+    public void testGetShareTargets_permission() {
+        IntentFilter filter = new IntentFilter();
+
+        assertExpectException(SecurityException.class, "Missing permission", () ->
+                mManager.getShareTargets(filter));
+
+        // Has permission, now it should pass.
+        mCallerPermissions.add(permission.MANAGE_APP_PREDICTIONS);
+        mManager.getShareTargets(filter);
+    }
+
     public void testDumpsys_crossProfile() {
         prepareCrossProfileDataSet();
         dumpsysOnLogcat("test1", /* force= */ true);
diff --git a/services/tests/servicestests/src/com/android/server/usage/AppTimeLimitControllerTests.java b/services/tests/servicestests/src/com/android/server/usage/AppTimeLimitControllerTests.java
index 5d69bbd..4e43d00 100644
--- a/services/tests/servicestests/src/com/android/server/usage/AppTimeLimitControllerTests.java
+++ b/services/tests/servicestests/src/com/android/server/usage/AppTimeLimitControllerTests.java
@@ -964,26 +964,6 @@
         assertFalse(hasAppUsageObserver(UID, OBS_ID1));
     }
 
-    /** Verify app usage limit observer added correctly reports it being a group limit */
-    @Test
-    public void testAppUsageLimitObserver_IsGroupLimit() {
-        addAppUsageLimitObserver(OBS_ID1, GROUP1, TIME_30_MIN);
-        AppTimeLimitController.AppUsageLimitGroup group = getAppUsageLimitObserver(UID, OBS_ID1);
-        assertNotNull("Observer wasn't added", group);
-        assertTrue("Observer didn't correctly report being a group limit",
-                group.isGroupLimit());
-    }
-
-    /** Verify app usage limit observer added correctly reports it being not a group limit */
-    @Test
-    public void testAppUsageLimitObserver_IsNotGroupLimit() {
-        addAppUsageLimitObserver(OBS_ID1, new String[]{PKG_PROD}, TIME_30_MIN);
-        AppTimeLimitController.AppUsageLimitGroup group = getAppUsageLimitObserver(UID, OBS_ID1);
-        assertNotNull("Observer wasn't added", group);
-        assertFalse("Observer didn't correctly report not being a group limit",
-                group.isGroupLimit());
-    }
-
     /** Verify app usage limit observer added correctly reports its total usage limit */
     @Test
     public void testAppUsageLimitObserver_GetTotalUsageLimit() {
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationAdjustmentExtractorTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationAdjustmentExtractorTest.java
index 410ab87..e658d17 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationAdjustmentExtractorTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationAdjustmentExtractorTest.java
@@ -59,7 +59,7 @@
         signals.putStringArrayList(Adjustment.KEY_PEOPLE, people);
         ArrayList<Notification.Action> smartActions = new ArrayList<>();
         smartActions.add(createAction());
-        signals.putParcelableArrayList(Adjustment.KEY_SMART_ACTIONS, smartActions);
+        signals.putParcelableArrayList(Adjustment.KEY_CONTEXTUAL_ACTIONS, smartActions);
         Adjustment adjustment = new Adjustment("pkg", r.getKey(), signals, "", 0);
         r.addAdjustment(adjustment);
 
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 9c6ab0a..4a4fece 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -3595,6 +3595,22 @@
     }
 
     @Test
+    public void testUserApprovedBubblesForPackage() throws Exception {
+        assertFalse(mBinderService.hasUserApprovedBubblesForPackage(PKG, mUid));
+        mBinderService.setBubblesAllowed(PKG, mUid, true);
+        assertTrue(mBinderService.hasUserApprovedBubblesForPackage(PKG, mUid));
+        assertTrue(mBinderService.areBubblesAllowedForPackage(PKG, mUid));
+    }
+
+    @Test
+    public void testUserRejectsBubblesForPackage() throws Exception {
+        assertFalse(mBinderService.hasUserApprovedBubblesForPackage(PKG, mUid));
+        mBinderService.setBubblesAllowed(PKG, mUid, false);
+        assertTrue(mBinderService.hasUserApprovedBubblesForPackage(PKG, mUid));
+        assertFalse(mBinderService.areBubblesAllowedForPackage(PKG, mUid));
+    }
+
+    @Test
     public void testIsCallerInstantApp_primaryUser() throws Exception {
         ApplicationInfo info = new ApplicationInfo();
         info.privateFlags = ApplicationInfo.PRIVATE_FLAG_INSTANT;
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
index 24a1f8c..bde9dde 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
@@ -2162,20 +2162,20 @@
 
     @Test
     public void testAllowBubbles_defaults() throws Exception {
-        assertTrue(mHelper.areBubblessAllowed(PKG_O, UID_O));
+        assertTrue(mHelper.areBubblesAllowed(PKG_O, UID_O));
 
         ByteArrayOutputStream baos = writeXmlAndPurge(PKG_O, UID_O, false);
         mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper);
         loadStreamXml(baos, false);
 
-        assertTrue(mHelper.areBubblessAllowed(PKG_O, UID_O));
+        assertTrue(mHelper.areBubblesAllowed(PKG_O, UID_O));
         assertEquals(0, mHelper.getAppLockedFields(PKG_O, UID_O));
     }
 
     @Test
     public void testAllowBubbles_xml() throws Exception {
         mHelper.setBubblesAllowed(PKG_O, UID_O, false);
-        assertFalse(mHelper.areBubblessAllowed(PKG_O, UID_O));
+        assertFalse(mHelper.areBubblesAllowed(PKG_O, UID_O));
         assertEquals(PreferencesHelper.LockableAppFields.USER_LOCKED_BUBBLE,
                 mHelper.getAppLockedFields(PKG_O, UID_O));
 
@@ -2183,7 +2183,7 @@
         mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper);
         loadStreamXml(baos, false);
 
-        assertFalse(mHelper.areBubblessAllowed(PKG_O, UID_O));
+        assertFalse(mHelper.areBubblesAllowed(PKG_O, UID_O));
         assertEquals(PreferencesHelper.LockableAppFields.USER_LOCKED_BUBBLE,
                 mHelper.getAppLockedFields(PKG_O, UID_O));
     }
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
index 056568a..ace965b 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
@@ -523,9 +523,8 @@
         starter.setReason("testActivityStartsLogging_noLoggingWhenDisabled").execute();
 
         // verify logging wasn't done
-        verify(mActivityMetricsLogger, never()).logActivityStart(any(), any(), any(), anyInt(),
-                any(), anyInt(), anyBoolean(), anyInt(), anyInt(), anyBoolean(), anyInt(), any(),
-                anyInt(), anyBoolean(), any(), anyBoolean());
+        verify(mActivityMetricsLogger, never()).logAbortedBgActivityStart(any(), any(), anyInt(),
+                any(), anyInt(), anyBoolean(), anyInt(), anyInt(), anyBoolean(), anyBoolean());
     }
 
     /**
@@ -546,10 +545,9 @@
         starter.setReason("testActivityStartsLogging_logsWhenEnabled").execute();
 
         // verify the above activity start was logged
-        verify(mActivityMetricsLogger, times(1)).logActivityStart(any(), any(), any(),
+        verify(mActivityMetricsLogger, times(1)).logAbortedBgActivityStart(any(), any(),
                 eq(FAKE_CALLING_UID), eq(FAKE_CALLING_PACKAGE), anyInt(), anyBoolean(),
-                eq(FAKE_REAL_CALLING_UID), anyInt(), anyBoolean(), anyInt(),
-                any(), anyInt(), anyBoolean(), any(), eq(false));
+                eq(FAKE_REAL_CALLING_UID), anyInt(), anyBoolean(), eq(false));
     }
 
     /**
diff --git a/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java b/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java
index e3bacf9..67ee4ad 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java
@@ -395,8 +395,8 @@
     /**
      * Tests that home activities can be started on the displays that supports system decorations.
      */
-    // TODO (b/118206886): Will add it back once launcher's patch is merged into master.
-    private void testStartHomeOnAllDisplays() {
+    @Test
+    public void testStartHomeOnAllDisplays() {
         // Create secondary displays.
         final TestActivityDisplay secondDisplay = spy(createNewActivityDisplay());
         mRootActivityContainer.addChild(secondDisplay, POSITION_TOP);
diff --git a/services/usage/java/com/android/server/usage/AppTimeLimitController.java b/services/usage/java/com/android/server/usage/AppTimeLimitController.java
index fa472e2..873ada0 100644
--- a/services/usage/java/com/android/server/usage/AppTimeLimitController.java
+++ b/services/usage/java/com/android/server/usage/AppTimeLimitController.java
@@ -510,12 +510,9 @@
     }
 
     class AppUsageLimitGroup extends UsageGroup {
-        private boolean mGroupLimit;
-
         public AppUsageLimitGroup(UserData user, ObserverAppData observerApp, int observerId,
                 String[] observed, long timeLimitMs, PendingIntent limitReachedCallback) {
             super(user, observerApp, observerId, observed, timeLimitMs, limitReachedCallback);
-            mGroupLimit = observed.length > 1;
         }
 
         @Override
@@ -529,11 +526,6 @@
         }
 
         @GuardedBy("mLock")
-        boolean isGroupLimit() {
-            return mGroupLimit;
-        }
-
-        @GuardedBy("mLock")
         long getTotaUsageLimit() {
             return mTimeLimitMs;
         }
@@ -547,14 +539,6 @@
                 return mTimeLimitMs - mUsageTimeMs;
             }
         }
-
-        @Override
-        @GuardedBy("mLock")
-        void dump(PrintWriter pw) {
-            super.dump(pw);
-            pw.print(" groupLimit=");
-            pw.print(mGroupLimit);
-        }
     }
 
 
@@ -692,7 +676,7 @@
                     smallestGroup = otherGroup;
                 }
             }
-            return new UsageStatsManagerInternal.AppUsageLimitData(smallestGroup.isGroupLimit(),
+            return new UsageStatsManagerInternal.AppUsageLimitData(
                     smallestGroup.getTotaUsageLimit(), smallestGroup.getUsageRemaining());
         }
     }
diff --git a/startop/view_compiler/Android.bp b/startop/view_compiler/Android.bp
index 7dc83c3..f5b4308 100644
--- a/startop/view_compiler/Android.bp
+++ b/startop/view_compiler/Android.bp
@@ -16,12 +16,12 @@
 
 cc_defaults {
     name: "viewcompiler_defaults",
+    defaults: ["libdexfile_static_defaults"],
     header_libs: [
         "libbase_headers",
     ],
     shared_libs: [
         "libbase",
-        "libdexfile",
         "libz",
         "slicer",
     ],
diff --git a/telephony/java/android/telephony/CallQuality.java b/telephony/java/android/telephony/CallQuality.java
index b27f6b4..cbe62284 100644
--- a/telephony/java/android/telephony/CallQuality.java
+++ b/telephony/java/android/telephony/CallQuality.java
@@ -92,6 +92,10 @@
         mCodecType = in.readInt();
     }
 
+    /** @hide **/
+    public CallQuality() {
+    }
+
     /**
      * Constructor.
      *
diff --git a/telephony/java/android/telephony/IFinancialSmsCallback.aidl b/telephony/java/android/telephony/IFinancialSmsCallback.aidl
new file mode 100644
index 0000000..aa88615
--- /dev/null
+++ b/telephony/java/android/telephony/IFinancialSmsCallback.aidl
@@ -0,0 +1,34 @@
+/*
+** 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.telephony;
+
+import android.app.PendingIntent;
+import android.database.CursorWindow;
+import android.net.Uri;
+import android.os.Bundle;
+import com.android.internal.telephony.SmsRawData;
+
+/** Interface for returning back the financial sms messages asynchrously.
+ *  @hide
+ */
+interface IFinancialSmsCallback {
+    /**
+     * Return sms messages back to calling financial app.
+     *
+     * @param messages the sms messages returned for cinancial app.
+     */
+    oneway void onGetSmsMessagesForFinancialApp(in CursorWindow messages);
+}
diff --git a/telephony/java/android/telephony/PhoneStateListener.java b/telephony/java/android/telephony/PhoneStateListener.java
index 9fee593..af324de 100644
--- a/telephony/java/android/telephony/PhoneStateListener.java
+++ b/telephony/java/android/telephony/PhoneStateListener.java
@@ -701,7 +701,7 @@
      * @hide
      */
     @SystemApi
-    public void onCallAttributesChanged(CallAttributes callAttributes) {
+    public void onCallAttributesChanged(@NonNull CallAttributes callAttributes) {
         // default implementation empty
     }
 
diff --git a/telephony/java/android/telephony/ServiceState.java b/telephony/java/android/telephony/ServiceState.java
index bf9bf9a..4475630 100644
--- a/telephony/java/android/telephony/ServiceState.java
+++ b/telephony/java/android/telephony/ServiceState.java
@@ -1631,8 +1631,9 @@
 
     /** @hide */
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
-    public static boolean bearerBitmapHasCdma(int radioTechnologyBitmap) {
-        return (RIL_RADIO_CDMA_TECHNOLOGY_BITMASK & radioTechnologyBitmap) != 0;
+    public static boolean bearerBitmapHasCdma(int networkTypeBitmask) {
+        return (RIL_RADIO_CDMA_TECHNOLOGY_BITMASK
+                & convertNetworkTypeBitmaskToBearerBitmask(networkTypeBitmask)) != 0;
     }
 
     /** @hide */
diff --git a/telephony/java/android/telephony/SmsManager.java b/telephony/java/android/telephony/SmsManager.java
index aaca18a..fae7920 100644
--- a/telephony/java/android/telephony/SmsManager.java
+++ b/telephony/java/android/telephony/SmsManager.java
@@ -16,6 +16,7 @@
 
 package android.telephony;
 
+import android.annotation.CallbackExecutor;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.RequiresPermission;
@@ -32,8 +33,10 @@
 import android.content.ContentValues;
 import android.content.Context;
 import android.content.Intent;
+import android.database.CursorWindow;
 import android.net.Uri;
 import android.os.BaseBundle;
+import android.os.Binder;
 import android.os.Build;
 import android.os.Bundle;
 import android.os.RemoteException;
@@ -51,6 +54,7 @@
 import java.util.Arrays;
 import java.util.List;
 import java.util.Map;
+import java.util.concurrent.Executor;
 
 /*
  * TODO(code review): Curious question... Why are a lot of these
@@ -2146,6 +2150,43 @@
         }
     }
 
+    /** callback for providing asynchronous sms messages for financial app. */
+    public abstract static class FinancialSmsCallback {
+        /**
+         * Callback to send sms messages back to financial app asynchronously.
+         *
+         * @param msgs SMS messages.
+         */
+        public abstract void onFinancialSmsMessages(CursorWindow msgs);
+    };
+
+    /**
+     * Get SMS messages for the calling financial app.
+     * The result will be delivered asynchronously in the passing in callback interface.
+     *
+     * @param params the parameters to filter SMS messages returned.
+     * @param executor the executor on which callback will be invoked.
+     * @param callback a callback to receive CursorWindow with SMS messages.
+     */
+    @RequiresPermission(android.Manifest.permission.SMS_FINANCIAL_TRANSACTIONS)
+    public void getSmsMessagesForFinancialApp(
+            Bundle params,
+            @NonNull @CallbackExecutor Executor executor,
+            @NonNull FinancialSmsCallback callback) {
+        try {
+            ISms iccSms = getISmsServiceOrThrow();
+            iccSms.getSmsMessagesForFinancialApp(
+                    getSubscriptionId(), ActivityThread.currentPackageName(), params,
+                    new IFinancialSmsCallback.Stub() {
+                        public void onGetSmsMessagesForFinancialApp(CursorWindow msgs) {
+                            Binder.withCleanCallingIdentity(() -> executor.execute(
+                                    () -> callback.onFinancialSmsMessages(msgs)));
+                        }});
+        } catch (RemoteException ex) {
+            ex.rethrowFromSystemServer();
+        }
+    }
+
     /**
      * @see #createAppSpecificSmsTokenWithPackageInfo().
      * The prefixes is a list of prefix {@code String} separated by this delimiter.
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 98fc725..80ee0a7 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -10134,4 +10134,26 @@
         }
         return ret;
     }
+
+    /**
+     * Broadcast intent action for network country code changes.
+     *
+     * <p>
+     * The {@link #EXTRA_NETWORK_COUNTRY} extra indicates the country code of the current
+     * network returned by {@link #getNetworkCountryIso()}.
+     *
+     * @see #EXTRA_NETWORK_COUNTRY
+     * @see #getNetworkCountryIso()
+     */
+    public static final String ACTION_NETWORK_COUNTRY_CHANGED =
+            "android.telephony.action.NETWORK_COUNTRY_CHANGED";
+
+    /**
+     * The extra used with an {@link #ACTION_NETWORK_COUNTRY_CHANGED} to specify the
+     * the country code in ISO 3166 format.
+     * <p class="note">
+     * Retrieve with {@link android.content.Intent#getStringExtra(String)}.
+     */
+    public static final String EXTRA_NETWORK_COUNTRY =
+            "android.telephony.extra.NETWORK_COUNTRY";
 }
diff --git a/telephony/java/android/telephony/data/DataCallResponse.java b/telephony/java/android/telephony/data/DataCallResponse.java
index 294c79b..3d2fe5f 100644
--- a/telephony/java/android/telephony/data/DataCallResponse.java
+++ b/telephony/java/android/telephony/data/DataCallResponse.java
@@ -23,6 +23,7 @@
 import android.net.LinkAddress;
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.telephony.data.ApnSetting.ProtocolType;
 
 import java.net.InetAddress;
 import java.util.ArrayList;
@@ -40,7 +41,7 @@
     private final int mSuggestedRetryTime;
     private final int mCid;
     private final int mActive;
-    private final String mType;
+    private final int mProtocolType;
     private final String mIfname;
     private final List<LinkAddress> mAddresses;
     private final List<InetAddress> mDnses;
@@ -53,8 +54,8 @@
      * @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 type The connection protocol, should be one of the PDP_type values in TS 27.007
-     *             section 10.1.1. For example, "IP", "IPV6", "IPV4V6", or "PPP".
+     * @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.
      * @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
@@ -71,7 +72,7 @@
      *            either not sent a value or sent an invalid value.
      */
     public DataCallResponse(int status, int suggestedRetryTime, int cid, int active,
-                            @Nullable String type, @Nullable String ifname,
+                            @ProtocolType int protocolType, @Nullable String ifname,
                             @Nullable List<LinkAddress> addresses,
                             @Nullable List<InetAddress> dnses,
                             @Nullable List<InetAddress> gateways,
@@ -80,7 +81,7 @@
         mSuggestedRetryTime = suggestedRetryTime;
         mCid = cid;
         mActive = active;
-        mType = (type == null) ? "" : type;
+        mProtocolType = protocolType;
         mIfname = (ifname == null) ? "" : ifname;
         mAddresses = (addresses == null) ? new ArrayList<>() : addresses;
         mDnses = (dnses == null) ? new ArrayList<>() : dnses;
@@ -94,7 +95,7 @@
         mSuggestedRetryTime = source.readInt();
         mCid = source.readInt();
         mActive = source.readInt();
-        mType = source.readString();
+        mProtocolType = source.readInt();
         mIfname = source.readString();
         mAddresses = new ArrayList<>();
         source.readList(mAddresses, LinkAddress.class.getClassLoader());
@@ -128,11 +129,10 @@
     public int getActive() { return mActive; }
 
     /**
-     * @return The connection protocol, should be one of the PDP_type values in TS 27.007 section
-     * 10.1.1. For example, "IP", "IPV6", "IPV4V6", or "PPP".
+     * @return The connection protocol type.
      */
-    @NonNull
-    public String getType() { return mType; }
+    @ProtocolType
+    public int getProtocolType() { return mProtocolType; }
 
     /**
      * @return The network interface name.
@@ -181,7 +181,7 @@
            .append(" retry=").append(mSuggestedRetryTime)
            .append(" cid=").append(mCid)
            .append(" active=").append(mActive)
-           .append(" type=").append(mType)
+           .append(" protocolType=").append(mProtocolType)
            .append(" ifname=").append(mIfname)
            .append(" addresses=").append(mAddresses)
            .append(" dnses=").append(mDnses)
@@ -205,7 +205,7 @@
                 && this.mSuggestedRetryTime == other.mSuggestedRetryTime
                 && this.mCid == other.mCid
                 && this.mActive == other.mActive
-                && this.mType.equals(other.mType)
+                && this.mProtocolType == other.mProtocolType
                 && this.mIfname.equals(other.mIfname)
                 && mAddresses.size() == other.mAddresses.size()
                 && mAddresses.containsAll(other.mAddresses)
@@ -220,8 +220,8 @@
 
     @Override
     public int hashCode() {
-        return Objects.hash(mStatus, mSuggestedRetryTime, mCid, mActive, mType, mIfname, mAddresses,
-                mDnses, mGateways, mPcscfs, mMtu);
+        return Objects.hash(mStatus, mSuggestedRetryTime, mCid, mActive, mProtocolType, mIfname,
+                mAddresses, mDnses, mGateways, mPcscfs, mMtu);
     }
 
     @Override
@@ -235,7 +235,7 @@
         dest.writeInt(mSuggestedRetryTime);
         dest.writeInt(mCid);
         dest.writeInt(mActive);
-        dest.writeString(mType);
+        dest.writeInt(mProtocolType);
         dest.writeString(mIfname);
         dest.writeList(mAddresses);
         dest.writeList(mDnses);
diff --git a/telephony/java/android/telephony/data/DataProfile.java b/telephony/java/android/telephony/data/DataProfile.java
index da4822c..1d196f9 100644
--- a/telephony/java/android/telephony/data/DataProfile.java
+++ b/telephony/java/android/telephony/data/DataProfile.java
@@ -16,14 +16,23 @@
 
 package android.telephony.data;
 
+import static android.telephony.data.ApnSetting.ProtocolType;
+
+import android.annotation.IntDef;
 import android.annotation.SystemApi;
 import android.os.Build;
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.telephony.TelephonyManager.NetworkTypeBitMask;
+import android.telephony.data.ApnSetting.ApnType;
+import android.telephony.data.ApnSetting.AuthType;
 import android.text.TextUtils;
 
 import com.android.internal.telephony.RILConstants;
 
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
 /**
  * Description of a mobile data profile used for establishing
  * data connections.
@@ -32,24 +41,39 @@
  */
 @SystemApi
 public final class DataProfile implements Parcelable {
+    /** @hide */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(prefix = {"TYPE_"},
+            value = {
+                    TYPE_COMMON,
+                    TYPE_3GPP,
+                    TYPE_3GPP2})
+    public @interface DataProfileType {}
 
-    // The types indicating the data profile is used on GSM (3GPP) or CDMA (3GPP2) network.
+    /** Common data profile */
     public static final int TYPE_COMMON = 0;
+
+    /** 3GPP type data profile */
     public static final int TYPE_3GPP = 1;
+
+    /** 3GPP2 type data profile */
     public static final int TYPE_3GPP2 = 2;
 
     private final int mProfileId;
 
     private final String mApn;
 
-    private final String mProtocol;
+    @ProtocolType
+    private final int mProtocolType;
 
+    @AuthType
     private final int mAuthType;
 
     private final String mUserName;
 
     private final String mPassword;
 
+    @DataProfileType
     private final int mType;
 
     private final int mMaxConnsTime;
@@ -60,10 +84,13 @@
 
     private final boolean mEnabled;
 
+    @ApnType
     private final int mSupportedApnTypesBitmap;
 
-    private final String mRoamingProtocol;
+    @ProtocolType
+    private final int mRoamingProtocolType;
 
+    @NetworkTypeBitMask
     private final int mBearerBitmap;
 
     private final int mMtu;
@@ -73,14 +100,14 @@
     private final boolean mPreferred;
 
     /** @hide */
-    public DataProfile(int profileId, String apn, String protocol, int authType, String userName,
-                       String password, int type, int maxConnsTime, int maxConns, int waitTime,
-                       boolean enabled, int supportedApnTypesBitmap, String roamingProtocol,
-                       int bearerBitmap, int mtu, boolean persistent, boolean preferred) {
-
+    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) {
         this.mProfileId = profileId;
         this.mApn = apn;
-        this.mProtocol = protocol;
+        this.mProtocolType = protocolType;
         if (authType == -1) {
             authType = TextUtils.isEmpty(userName) ? RILConstants.SETUP_DATA_AUTH_NONE
                     : RILConstants.SETUP_DATA_AUTH_PAP_CHAP;
@@ -95,7 +122,7 @@
         this.mEnabled = enabled;
 
         this.mSupportedApnTypesBitmap = supportedApnTypesBitmap;
-        this.mRoamingProtocol = roamingProtocol;
+        this.mRoamingProtocolType = roamingProtocolType;
         this.mBearerBitmap = bearerBitmap;
         this.mMtu = mtu;
         this.mPersistent = persistent;
@@ -106,7 +133,7 @@
     public DataProfile(Parcel source) {
         mProfileId = source.readInt();
         mApn = source.readString();
-        mProtocol = source.readString();
+        mProtocolType = source.readInt();
         mAuthType = source.readInt();
         mUserName = source.readString();
         mPassword = source.readString();
@@ -116,7 +143,7 @@
         mWaitTime = source.readInt();
         mEnabled = source.readBoolean();
         mSupportedApnTypesBitmap = source.readInt();
-        mRoamingProtocol = source.readString();
+        mRoamingProtocolType = source.readInt();
         mBearerBitmap = source.readInt();
         mMtu = source.readInt();
         mPersistent = source.readBoolean();
@@ -134,16 +161,14 @@
     public String getApn() { return mApn; }
 
     /**
-     * @return The connection protocol, should be one of the PDP_type values in TS 27.007 section
-     * 10.1.1. For example, "IP", "IPV6", "IPV4V6", or "PPP".
+     * @return The connection protocol defined in 3GPP TS 27.007 section 10.1.1.
      */
-    public String getProtocol() { return mProtocol; }
+    public @ProtocolType int getProtocol() { return mProtocolType; }
 
     /**
-     * @return The authentication protocol used for this PDP context
-     * (None: 0, PAP: 1, CHAP: 2, PAP&CHAP: 3)
+     * @return The authentication protocol used for this PDP context.
      */
-    public int getAuthType() { return mAuthType; }
+    public @AuthType int getAuthType() { return mAuthType; }
 
     /**
      * @return The username for APN. Can be null.
@@ -156,9 +181,9 @@
     public String getPassword() { return mPassword; }
 
     /**
-     * @return The profile type. Could be one of TYPE_COMMON, TYPE_3GPP, or TYPE_3GPP2.
+     * @return The profile type.
      */
-    public int getType() { return mType; }
+    public @DataProfileType int getType() { return mType; }
 
     /**
      * @return The period in seconds to limit the maximum connections.
@@ -183,20 +208,19 @@
     public boolean isEnabled() { return mEnabled; }
 
     /**
-     * @return The supported APN types bitmap. See RIL_ApnTypes for the value of each bit.
+     * @return The supported APN types bitmap.
      */
-    public int getSupportedApnTypesBitmap() { return mSupportedApnTypesBitmap; }
+    public @ApnType int getSupportedApnTypesBitmap() { return mSupportedApnTypesBitmap; }
 
     /**
-     * @return  The connection protocol on roaming network, should be one of the PDP_type values in
-     * TS 27.007 section 10.1.1. For example, "IP", "IPV6", "IPV4V6", or "PPP".
+     * @return The connection protocol on roaming network defined in 3GPP TS 27.007 section 10.1.1.
      */
-    public String getRoamingProtocol() { return mRoamingProtocol; }
+    public @ProtocolType int getRoamingProtocol() { return mRoamingProtocolType; }
 
     /**
-     * @return The bearer bitmap. See RIL_RadioAccessFamily for the value of each bit.
+     * @return The bearer bitmap indicating the applicable networks for this data profile.
      */
-    public int getBearerBitmap() { return mBearerBitmap; }
+    public @NetworkTypeBitMask int getBearerBitmap() { return mBearerBitmap; }
 
     /**
      * @return The maximum transmission unit (MTU) size in bytes.
@@ -222,12 +246,12 @@
 
     @Override
     public String toString() {
-        return "DataProfile=" + mProfileId + "/" + mProtocol + "/" + mAuthType
+        return "DataProfile=" + mProfileId + "/" + mProtocolType + "/" + mAuthType
                 + "/" + (Build.IS_USER ? "***/***/***" :
                          (mApn + "/" + mUserName + "/" + mPassword)) + "/" + mType + "/"
                 + mMaxConnsTime + "/" + mMaxConns + "/"
                 + mWaitTime + "/" + mEnabled + "/" + mSupportedApnTypesBitmap + "/"
-                + mRoamingProtocol + "/" + mBearerBitmap + "/" + mMtu + "/" + mPersistent + "/"
+                + mRoamingProtocolType + "/" + mBearerBitmap + "/" + mMtu + "/" + mPersistent + "/"
                 + mPreferred;
     }
 
@@ -242,7 +266,7 @@
     public void writeToParcel(Parcel dest, int flags) {
         dest.writeInt(mProfileId);
         dest.writeString(mApn);
-        dest.writeString(mProtocol);
+        dest.writeInt(mProtocolType);
         dest.writeInt(mAuthType);
         dest.writeString(mUserName);
         dest.writeString(mPassword);
@@ -252,7 +276,7 @@
         dest.writeInt(mWaitTime);
         dest.writeBoolean(mEnabled);
         dest.writeInt(mSupportedApnTypesBitmap);
-        dest.writeString(mRoamingProtocol);
+        dest.writeInt(mRoamingProtocolType);
         dest.writeInt(mBearerBitmap);
         dest.writeInt(mMtu);
         dest.writeBoolean(mPersistent);
diff --git a/telephony/java/com/android/ims/internal/uce/common/StatusCode.java b/telephony/java/com/android/ims/internal/uce/common/StatusCode.java
index 3921cfb..7250eee 100644
--- a/telephony/java/com/android/ims/internal/uce/common/StatusCode.java
+++ b/telephony/java/com/android/ims/internal/uce/common/StatusCode.java
@@ -64,6 +64,10 @@
     public static final int UCE_NO_CHANGE_IN_CAP = 13;
     /**  Service is unknown. */
     public static final int UCE_SERVICE_UNKNOWN = 14;
+     /** Service cannot support Invalid Feature Tag   */
+    public static final int UCE_INVALID_FEATURE_TAG = 15;
+    /** Service is Available   */
+    public static final int UCE_SERVICE_AVAILABLE = 16;
 
 
     private int mStatusCode = UCE_SUCCESS;
diff --git a/telephony/java/com/android/ims/internal/uce/uceservice/IUceService.aidl b/telephony/java/com/android/ims/internal/uce/uceservice/IUceService.aidl
index 43f83cd..1fb8513 100644
--- a/telephony/java/com/android/ims/internal/uce/uceservice/IUceService.aidl
+++ b/telephony/java/com/android/ims/internal/uce/uceservice/IUceService.aidl
@@ -66,10 +66,30 @@
      * service the client created.
      *
      * @return  optionsServiceHandle
+     *
      * @hide
+     *
+     * @deprecated This is replaced with new API createOptionsServiceForSubscription()
      */
     int createOptionsService(IOptionsListener optionsListener,
                              inout UceLong optionsServiceListenerHdl);
+    /**
+     * Creates a options service for Capability Discovery.
+     * @param optionsListener IOptionsListener object.
+     * @param optionsServiceListenerHdl wrapper for client's listener handle to be stored.
+     * @param iccId the ICC-ID derived from SubscriptionInfo for the Service requested
+     *
+     * The service will fill UceLong.mUceLong with presenceListenerHandle allocated and
+     * used to validate callbacks received in IPresenceListener are indeed from the
+     * service the client created.
+     *
+     * @return  optionsServiceHandle
+     *
+     * @hide
+     */
+    int createOptionsServiceForSubscription(IOptionsListener optionsListener,
+                             inout UceLong optionsServiceListenerHdl,
+                             in String iccId);
 
     /**
      * Destroys a Options service.
@@ -89,14 +109,36 @@
      * service the client created.
      *
      * @return  presenceServiceHdl
+     *
      * @hide
+     *
+     * @deprecated This is replaced with new API createPresenceServiceForSubscription()
      */
     int createPresenceService(IPresenceListener presenceServiceListener,
                               inout UceLong presenceServiceListenerHdl);
+    /**
+     * Creates a presence service.
+     * @param presenceServiceListener IPresenceListener object
+     * @param presenceServiceListenerHdl wrapper for client's listener handle to be stored.
+     * @param iccId the ICC-ID derived from SubscriptionInfo for the Service requested
+     *
+     * The service will fill UceLong.mUceLong with presenceListenerHandle allocated and
+     * used to validate callbacks received in IPresenceListener are indeed from the
+     * service the client created.
+     *
+     * @return  presenceServiceHdl
+     *
+     * @hide
+     */
+    int createPresenceServiceForSubscription(IPresenceListener presenceServiceListener,
+                              inout UceLong presenceServiceListenerHdl,
+                              in String iccId);
 
     /**
      * Destroys a presence service.
+     *
      * @param presenceServiceHdl handle returned during createPresenceService()
+     *
      * @hide
      */
     void destroyPresenceService(int presenceServiceHdl);
@@ -105,23 +147,55 @@
 
     /**
      * Query the UCE Service for information to know whether the is registered.
+     *
      * @return boolean, true if Registered to for network events else false.
+     *
      * @hide
      */
     boolean getServiceStatus();
 
     /**
      * Query the UCE Service for presence Service.
+     *
      * @return IPresenceService object.
+     *
      * @hide
+     *
+     * @deprecated use API getPresenceServiceForSubscription()
      */
     IPresenceService getPresenceService();
 
     /**
+     * Query the UCE Service for presence Service.
+     *
+     * @param iccId the ICC-ID derived from SubscriptionInfo for the Service requested
+     *
+     * @return IPresenceService object.
+     *
+     * @hide
+     */
+    IPresenceService getPresenceServiceForSubscription(in String iccId);
+
+    /**
      * Query the UCE Service for options service object.
+     *
      * @return IOptionsService object.
+     *
+     * @deprecated use API getOptionsServiceForSubscription()
+     *
      * @hide
      */
     IOptionsService getOptionsService();
 
+    /**
+     * Query the UCE Service for options service object.
+     *
+     * @param iccId the ICC-ID derived from SubscriptionInfo for the Service requested
+     *
+     * @return IOptionsService object.
+     *
+     * @hide
+     */
+    IOptionsService getOptionsServiceForSubscription(in String iccId);
+
 }
diff --git a/telephony/java/com/android/ims/internal/uce/uceservice/UceServiceBase.java b/telephony/java/com/android/ims/internal/uce/uceservice/UceServiceBase.java
index 3660e03..ceb1919 100644
--- a/telephony/java/com/android/ims/internal/uce/uceservice/UceServiceBase.java
+++ b/telephony/java/com/android/ims/internal/uce/uceservice/UceServiceBase.java
@@ -56,6 +56,14 @@
             return onCreateOptionsService(optionsListener, optionsServiceListenerHdl);
         }
 
+        @Override
+        public int createOptionsServiceForSubscription(IOptionsListener optionsListener,
+                                      UceLong optionsServiceListenerHdl,
+                                      String iccId) {
+            return onCreateOptionsService(optionsListener, optionsServiceListenerHdl,
+                                          iccId);
+        }
+
 
         @Override
         public void destroyOptionsService(int optionsServiceHandle) {
@@ -70,6 +78,14 @@
         }
 
         @Override
+        public int createPresenceServiceForSubscription(IPresenceListener presServiceListener,
+                                         UceLong presServiceListenerHdl,
+                                         String iccId) {
+            return onCreatePresService(presServiceListener, presServiceListenerHdl,
+                                       iccId);
+        }
+
+        @Override
         public void destroyPresenceService(int presServiceHdl) {
             onDestroyPresService(presServiceHdl);
         }
@@ -85,9 +101,19 @@
         }
 
         @Override
+        public IPresenceService getPresenceServiceForSubscription(String iccId) {
+            return onGetPresenceService(iccId);
+        }
+
+        @Override
         public IOptionsService getOptionsService() {
             return onGetOptionsService();
         }
+
+        @Override
+        public IOptionsService getOptionsServiceForSubscription(String iccId) {
+            return onGetOptionsService(iccId);
+        }
     }
 
     private UceServiceBinder mBinder;
@@ -120,6 +146,13 @@
         return 0;
     }
 
+    protected int onCreateOptionsService(IOptionsListener optionsListener,
+                                         UceLong optionsServiceListenerHdl,
+                                         String iccId) {
+        //no-op
+        return 0;
+    }
+
     protected void onDestroyOptionsService(int cdServiceHandle) {
         //no-op
         return;
@@ -131,6 +164,13 @@
         return 0;
     }
 
+    protected int onCreatePresService(IPresenceListener presServiceListener,
+                                      UceLong presServiceListenerHdl,
+                                      String iccId) {
+        //no-op
+        return 0;
+    }
+
     protected void onDestroyPresService(int presServiceHdl) {
         //no-op
         return;
@@ -146,8 +186,18 @@
         return null;
     }
 
+    protected IPresenceService onGetPresenceService(String iccId) {
+        //no-op
+        return null;
+    }
+
     protected IOptionsService onGetOptionsService () {
         //no-op
         return null;
     }
+
+    protected IOptionsService onGetOptionsService (String iccId) {
+        //no-op
+        return null;
+    }
 }
diff --git a/telephony/java/com/android/internal/telephony/ISms.aidl b/telephony/java/com/android/internal/telephony/ISms.aidl
index 58ebb15..b51eda3 100644
--- a/telephony/java/com/android/internal/telephony/ISms.aidl
+++ b/telephony/java/com/android/internal/telephony/ISms.aidl
@@ -18,6 +18,8 @@
 
 import android.app.PendingIntent;
 import android.net.Uri;
+import android.os.Bundle;
+import android.telephony.IFinancialSmsCallback;
 import com.android.internal.telephony.SmsRawData;
 
 /** Interface for applications to access the ICC phone book.
@@ -575,4 +577,15 @@
      */
     String createAppSpecificSmsTokenWithPackageInfo(
             int subId, String callingPkg, String prefixes, in PendingIntent intent);
+
+    /**
+     * Get sms inbox messages for the calling financial app.
+     *
+     * @param subId the SIM id.
+     * @param callingPkg the package name of the calling app.
+     * @param params parameters to filter the sms messages.
+     * @param callback the callback interface to deliver the result.
+     */
+    void getSmsMessagesForFinancialApp(
+        int subId, String callingPkg, in Bundle params, in IFinancialSmsCallback callback);
 }
diff --git a/telephony/java/com/android/internal/telephony/ISmsImplBase.java b/telephony/java/com/android/internal/telephony/ISmsImplBase.java
index f2f2960..12c5c30 100644
--- a/telephony/java/com/android/internal/telephony/ISmsImplBase.java
+++ b/telephony/java/com/android/internal/telephony/ISmsImplBase.java
@@ -18,6 +18,8 @@
 
 import android.app.PendingIntent;
 import android.net.Uri;
+import android.os.Bundle;
+import android.telephony.IFinancialSmsCallback;
 
 import java.util.List;
 
@@ -194,4 +196,10 @@
             int subId, String callingPkg, String prefixes, PendingIntent intent) {
         throw new UnsupportedOperationException();
     }
+
+    @Override
+    public void getSmsMessagesForFinancialApp(
+            int subId, String callingPkg, Bundle params, IFinancialSmsCallback callback) {
+        throw new UnsupportedOperationException();
+    }
 }
diff --git a/telephony/java/com/android/internal/telephony/RILConstants.java b/telephony/java/com/android/internal/telephony/RILConstants.java
index 9300034..d9b206f 100644
--- a/telephony/java/com/android/internal/telephony/RILConstants.java
+++ b/telephony/java/com/android/internal/telephony/RILConstants.java
@@ -268,31 +268,11 @@
     int LTE_ON_CDMA_FALSE = 0;
     int LTE_ON_CDMA_TRUE = 1;
 
-    int CDM_TTY_MODE_DISABLED = 0;
-    int CDM_TTY_MODE_ENABLED = 1;
-
-    int CDM_TTY_FULL_MODE = 1;
-    int CDM_TTY_HCO_MODE = 2;
-    int CDM_TTY_VCO_MODE = 3;
-
-    /* Setup a packet data connection. See ril.h RIL_REQUEST_SETUP_DATA_CALL */
-    int SETUP_DATA_TECH_CDMA      = 0;
-    int SETUP_DATA_TECH_GSM       = 1;
-
     int SETUP_DATA_AUTH_NONE      = 0;
     int SETUP_DATA_AUTH_PAP       = 1;
     int SETUP_DATA_AUTH_CHAP      = 2;
     int SETUP_DATA_AUTH_PAP_CHAP  = 3;
 
-    String SETUP_DATA_PROTOCOL_IP     = "IP";
-    String SETUP_DATA_PROTOCOL_IPV6   = "IPV6";
-    String SETUP_DATA_PROTOCOL_IPV4V6 = "IPV4V6";
-
-    /* NV config radio reset types. */
-    int NV_CONFIG_RELOAD_RESET = 1;
-    int NV_CONFIG_ERASE_RESET = 2;
-    int NV_CONFIG_FACTORY_RESET = 3;
-
     /* LCE service related constants. */
     int LCE_NOT_AVAILABLE = -1;
     int LCE_STOPPED = 0;
diff --git a/tests/ActivityTests/AndroidManifest.xml b/tests/ActivityTests/AndroidManifest.xml
index b381cbf..0b3bd70 100644
--- a/tests/ActivityTests/AndroidManifest.xml
+++ b/tests/ActivityTests/AndroidManifest.xml
@@ -79,6 +79,7 @@
             android:singleUser="true" android:exported="true" />
         <receiver android:name="TrackTimeReceiver" />
         <receiver android:name="AlarmSpamReceiver" />
+        <receiver android:name="SlowReceiver" />
         <activity android:name="DisableScreenshotsActivity"
                 android:label="DisableScreenshots"
                 android:theme="@style/DisableScreenshots">
diff --git a/tests/ActivityTests/src/com/google/android/test/activity/ActivityTestMain.java b/tests/ActivityTests/src/com/google/android/test/activity/ActivityTestMain.java
index 0f49608..2581e08 100644
--- a/tests/ActivityTests/src/com/google/android/test/activity/ActivityTestMain.java
+++ b/tests/ActivityTests/src/com/google/android/test/activity/ActivityTestMain.java
@@ -16,21 +16,21 @@
 
 package com.google.android.test.activity;
 
-import java.util.ArrayList;
-import java.util.List;
-
 import android.app.Activity;
 import android.app.ActivityManager;
 import android.app.ActivityOptions;
 import android.app.AlarmManager;
 import android.app.AlertDialog;
 import android.app.PendingIntent;
-import android.content.ActivityNotFoundException;
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
 import android.content.ContentProviderClient;
+import android.content.Context;
 import android.content.Intent;
 import android.content.ServiceConnection;
+import android.content.pm.UserInfo;
+import android.content.res.Configuration;
+import android.graphics.Bitmap;
 import android.graphics.BitmapFactory;
 import android.net.Uri;
 import android.os.Bundle;
@@ -42,21 +42,18 @@
 import android.os.SystemClock;
 import android.os.UserHandle;
 import android.os.UserManager;
-import android.graphics.Bitmap;
 import android.provider.Settings;
-import android.widget.ImageView;
-import android.widget.LinearLayout;
-import android.widget.TextView;
-import android.widget.ScrollView;
-import android.widget.Toast;
+import android.util.Log;
 import android.view.Menu;
 import android.view.MenuItem;
 import android.view.View;
-import android.content.Context;
-import android.content.pm.UserInfo;
-import android.content.res.Configuration;
-import android.util.Log;
+import android.widget.LinearLayout;
+import android.widget.ScrollView;
+import android.widget.TextView;
+import android.widget.Toast;
 
+import java.util.ArrayList;
+import java.util.List;
 
 public class ActivityTestMain extends Activity {
     static final String TAG = "ActivityTest";
@@ -73,8 +70,13 @@
 
     ServiceConnection mIsolatedConnection;
 
+    static final String SLOW_RECEIVER_ACTION = "com.google.android.test.activity.SLOW_ACTION";
+    static final String SLOW_RECEIVER_EXTRA = "slow_ordinal";
+
     static final int MSG_SPAM = 1;
     static final int MSG_SPAM_ALARM = 2;
+    static final int MSG_SLOW_RECEIVER = 3;
+    static final int MSG_SLOW_ALARM_RECEIVER = 4;
 
     final Handler mHandler = new Handler() {
         @Override
@@ -100,11 +102,58 @@
                     mAlarm.setAndAllowWhileIdle(AlarmManager.ELAPSED_REALTIME, when+(30*1000), pi);
                     scheduleSpamAlarm(30*1000);
                 } break;
+                case MSG_SLOW_RECEIVER: {
+                    // Several back to back, to illustrate dispatch policy
+                    Intent intent = new Intent(ActivityTestMain.this, SlowReceiver.class);
+                    intent.setAction(SLOW_RECEIVER_ACTION);
+                    intent.putExtra(SLOW_RECEIVER_EXTRA, 1);
+                    sendOrderedBroadcast(intent, null, mSlowReceiverCompletion, mHandler,
+                            Activity.RESULT_OK, null, null);
+                    intent.putExtra(SLOW_RECEIVER_EXTRA, 2);
+                    sendOrderedBroadcast(intent, null, mSlowReceiverCompletion, mHandler,
+                            Activity.RESULT_OK, null, null);
+                    intent.putExtra(SLOW_RECEIVER_EXTRA, 3);
+                    sendOrderedBroadcast(intent, null, mSlowReceiverCompletion, mHandler,
+                            Activity.RESULT_OK, null, null);
+                } break;
+                case MSG_SLOW_ALARM_RECEIVER: {
+                    // Several back to back, to illustrate dispatch policy
+                    Intent intent = new Intent(ActivityTestMain.this, SlowReceiver.class);
+                    intent.setAction(SLOW_RECEIVER_ACTION);
+                    intent.putExtra(SLOW_RECEIVER_EXTRA, 1);
+                    sendOrderedBroadcast(intent, null, mSlowReceiverCompletion, mHandler,
+                            Activity.RESULT_OK, null, null);
+                    intent.putExtra(SLOW_RECEIVER_EXTRA, 2);
+                    sendOrderedBroadcast(intent, null, mSlowReceiverCompletion, mHandler,
+                            Activity.RESULT_OK, null, null);
+                    intent.putExtra(SLOW_RECEIVER_EXTRA, 3);
+                    sendOrderedBroadcast(intent, null, mSlowReceiverCompletion, mHandler,
+                            Activity.RESULT_OK, null, null);
+
+                    // Also send a broadcast alarm to evaluate the alarm fast-forward policy
+                    intent.putExtra(SLOW_RECEIVER_EXTRA, 4);
+                    PendingIntent pi = PendingIntent.getBroadcast(ActivityTestMain.this, 1, intent, 0);
+                    AlarmManager am = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
+                    long now = SystemClock.elapsedRealtime();
+                    Log.i(TAG, "Setting alarm for now + 5 seconds");
+                    am.setExact(AlarmManager.ELAPSED_REALTIME, now + 5_000, pi);
+                } break;
             }
             super.handleMessage(msg);
         }
     };
 
+    final BroadcastReceiver mSlowReceiverCompletion = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            final int extra = intent.getIntExtra(SLOW_RECEIVER_EXTRA, -1);
+            final String msg = "Slow receiver " + extra + " completed";
+            Toast.makeText(ActivityTestMain.this, msg, Toast.LENGTH_LONG)
+                    .show();
+            Log.i(TAG, msg);
+        }
+    };
+
     class BroadcastResultReceiver extends BroadcastReceiver {
         @Override
         public void onReceive(Context context, Intent intent) {
@@ -387,6 +436,18 @@
                 return true;
             }
         });
+        menu.add("Slow receiver").setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
+            @Override public boolean onMenuItemClick(MenuItem item) {
+                scheduleSlowReceiver();
+                return true;
+            }
+        });
+        menu.add("Slow alarm receiver").setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
+            @Override public boolean onMenuItemClick(MenuItem item) {
+                scheduleSlowAlarmReceiver();
+                return true;
+            }
+        });
         menu.add("Spam!").setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
             @Override public boolean onMenuItemClick(MenuItem item) {
                 scheduleSpam(false);
@@ -469,6 +530,7 @@
     protected void onStop() {
         super.onStop();
         mHandler.removeMessages(MSG_SPAM_ALARM);
+        mHandler.removeMessages(MSG_SLOW_RECEIVER);
         for (ServiceConnection conn : mConnections) {
             unbindService(conn);
         }
@@ -544,6 +606,16 @@
         mHandler.sendMessageDelayed(msg, delay);
     }
 
+    void scheduleSlowReceiver() {
+        mHandler.removeMessages(MSG_SLOW_RECEIVER);
+        mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_SLOW_RECEIVER), 500);
+    }
+
+    void scheduleSlowAlarmReceiver() {
+        mHandler.removeMessages(MSG_SLOW_ALARM_RECEIVER);
+        mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_SLOW_ALARM_RECEIVER), 500);
+    }
+
     private View scrollWrap(View view) {
         ScrollView scroller = new ScrollView(this);
         scroller.addView(view, new ScrollView.LayoutParams(ScrollView.LayoutParams.MATCH_PARENT,
diff --git a/tests/ActivityTests/src/com/google/android/test/activity/SlowReceiver.java b/tests/ActivityTests/src/com/google/android/test/activity/SlowReceiver.java
new file mode 100644
index 0000000..0437a28
--- /dev/null
+++ b/tests/ActivityTests/src/com/google/android/test/activity/SlowReceiver.java
@@ -0,0 +1,47 @@
+/*
+ * 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.google.android.test.activity;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.os.SystemClock;
+import android.util.Log;
+
+public class SlowReceiver extends BroadcastReceiver {
+    private static final String TAG = "SlowReceiver";
+    private static final long RECEIVER_DELAY = 6_000;
+
+    @Override
+    public void onReceive(Context context, Intent intent) {
+        final int extra = intent.getIntExtra(ActivityTestMain.SLOW_RECEIVER_EXTRA, -1);
+        if (extra == 1) {
+            Log.i(TAG, "Received broadcast 1; delaying return by " + RECEIVER_DELAY + " ms");
+            long now = SystemClock.elapsedRealtime();
+            final long end = now + RECEIVER_DELAY;
+            while (now < end) {
+                try {
+                    Thread.sleep(end - now);
+                } catch (InterruptedException e) { }
+                now = SystemClock.elapsedRealtime();
+            }
+        } else {
+            Log.i(TAG, "Extra parameter not 1, returning immediately");
+        }
+        Log.i(TAG, "Returning from onReceive()");
+    }
+}
diff --git a/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java b/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java
index ec07037..86af642 100644
--- a/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java
+++ b/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java
@@ -26,8 +26,8 @@
 import android.support.test.InstrumentationRegistry;
 
 import com.android.server.PackageWatchdog.PackageHealthObserver;
+import com.android.server.PackageWatchdog.PackageHealthObserverImpact;
 
-import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 
@@ -45,23 +45,22 @@
 public class PackageWatchdogTest {
     private static final String APP_A = "com.package.a";
     private static final String APP_B = "com.package.b";
+    private static final String APP_C = "com.package.c";
+    private static final String APP_D = "com.package.d";
     private static final String OBSERVER_NAME_1 = "observer1";
     private static final String OBSERVER_NAME_2 = "observer2";
     private static final String OBSERVER_NAME_3 = "observer3";
+    private static final String OBSERVER_NAME_4 = "observer4";
     private static final long SHORT_DURATION = TimeUnit.SECONDS.toMillis(1);
     private static final long LONG_DURATION = TimeUnit.SECONDS.toMillis(5);
     private TestLooper mTestLooper;
 
     @Before
     public void setUp() throws Exception {
-        mTestLooper = new TestLooper();
-        mTestLooper.startAutoDispatch();
-    }
-
-    @After
-    public void tearDown() throws Exception {
         new File(InstrumentationRegistry.getContext().getFilesDir(),
                 "package-watchdog.xml").delete();
+        mTestLooper = new TestLooper();
+        mTestLooper.startAutoDispatch();
     }
 
     /**
@@ -154,7 +153,6 @@
         assertTrue(watchdog1.getPackages(observer2).contains(APP_A));
         assertTrue(watchdog1.getPackages(observer2).contains(APP_B));
 
-
         // Then advance time and run IO Handler so file is saved
         mTestLooper.dispatchAll();
 
@@ -198,47 +196,191 @@
             watchdog.onPackageFailure(new String[]{APP_A});
         }
 
+        // Run handler so package failures are dispatched to observers
+        mTestLooper.dispatchAll();
+
         // Verify that observers are not notified
         assertEquals(0, observer1.mFailedPackages.size());
         assertEquals(0, observer2.mFailedPackages.size());
     }
 
     /**
-     * Test package failure and notifies all observer since none handles the failure
+     * Test package failure and does not notify any observer because they are not observing
+     * the failed packages.
      */
     @Test
-    public void testPackageFailureNotifyAll() throws Exception {
+    public void testPackageFailureNotifyNone() throws Exception {
         PackageWatchdog watchdog = createWatchdog();
-        TestObserver observer1 = new TestObserver(OBSERVER_NAME_1);
-        TestObserver observer2 = new TestObserver(OBSERVER_NAME_2);
+        TestObserver observer1 = new TestObserver(OBSERVER_NAME_1,
+                PackageHealthObserverImpact.USER_IMPACT_HIGH);
+        TestObserver observer2 = new TestObserver(OBSERVER_NAME_2,
+                PackageHealthObserverImpact.USER_IMPACT_HIGH);
 
-        // Start observing for observer1 and observer2 without handling failures
+
         watchdog.startObservingHealth(observer2, Arrays.asList(APP_A), SHORT_DURATION);
-        watchdog.startObservingHealth(observer1, Arrays.asList(APP_A, APP_B), SHORT_DURATION);
+        watchdog.startObservingHealth(observer1, Arrays.asList(APP_B), SHORT_DURATION);
 
-        // Then fail APP_A and APP_B above the threshold
+        // Then fail APP_C (not observed) above the threshold
         for (int i = 0; i < TRIGGER_FAILURE_COUNT; i++) {
-            watchdog.onPackageFailure(new String[]{APP_A, APP_B});
+            watchdog.onPackageFailure(new String[]{APP_C});
         }
 
-        // Verify all observers are notifed of all package failures
-        List<String> observer1Packages = observer1.mFailedPackages;
-        List<String> observer2Packages = observer2.mFailedPackages;
-        assertEquals(2, observer1Packages.size());
-        assertEquals(1, observer2Packages.size());
-        assertEquals(APP_A, observer1Packages.get(0));
-        assertEquals(APP_B, observer1Packages.get(1));
-        assertEquals(APP_A, observer2Packages.get(0));
+        // Run handler so package failures are dispatched to observers
+        mTestLooper.dispatchAll();
+
+        // Verify that observers are not notified
+        assertEquals(0, observer1.mFailedPackages.size());
+        assertEquals(0, observer2.mFailedPackages.size());
     }
 
     /**
-     * Test package failure and notifies only one observer because it handles the failure
+     * Test package failure and notifies only least impact observers.
      */
     @Test
-    public void testPackageFailureNotifyOne() throws Exception {
+    public void testPackageFailureNotifyAllDifferentImpacts() throws Exception {
         PackageWatchdog watchdog = createWatchdog();
-        TestObserver observer1 = new TestObserver(OBSERVER_NAME_1, true /* shouldHandle */);
-        TestObserver observer2 = new TestObserver(OBSERVER_NAME_2, true /* shouldHandle */);
+        TestObserver observerNone = new TestObserver(OBSERVER_NAME_1,
+                PackageHealthObserverImpact.USER_IMPACT_NONE);
+        TestObserver observerHigh = new TestObserver(OBSERVER_NAME_2,
+                PackageHealthObserverImpact.USER_IMPACT_HIGH);
+        TestObserver observerMid = new TestObserver(OBSERVER_NAME_3,
+                PackageHealthObserverImpact.USER_IMPACT_MEDIUM);
+        TestObserver observerLow = new TestObserver(OBSERVER_NAME_4,
+                PackageHealthObserverImpact.USER_IMPACT_LOW);
+
+        // Start observing for all impact observers
+        watchdog.startObservingHealth(observerNone, Arrays.asList(APP_A, APP_B, APP_C, APP_D),
+                SHORT_DURATION);
+        watchdog.startObservingHealth(observerHigh, Arrays.asList(APP_A, APP_B, APP_C),
+                SHORT_DURATION);
+        watchdog.startObservingHealth(observerMid, Arrays.asList(APP_A, APP_B),
+                SHORT_DURATION);
+        watchdog.startObservingHealth(observerLow, Arrays.asList(APP_A),
+                SHORT_DURATION);
+
+        // Then fail all apps above the threshold
+        for (int i = 0; i < TRIGGER_FAILURE_COUNT; i++) {
+            watchdog.onPackageFailure(new String[]{APP_A, APP_B, APP_C, APP_D});
+        }
+
+        // Run handler so package failures are dispatched to observers
+        mTestLooper.dispatchAll();
+
+        // Verify least impact observers are notifed of package failures
+        List<String> observerNonePackages = observerNone.mFailedPackages;
+        List<String> observerHighPackages = observerHigh.mFailedPackages;
+        List<String> observerMidPackages = observerMid.mFailedPackages;
+        List<String> observerLowPackages = observerLow.mFailedPackages;
+
+        // APP_D failure observed by only observerNone is not caught cos its impact is none
+        assertEquals(0, observerNonePackages.size());
+        // APP_C failure is caught by observerHigh cos it's the lowest impact observer
+        assertEquals(1, observerHighPackages.size());
+        assertEquals(APP_C, observerHighPackages.get(0));
+        // APP_B failure is caught by observerMid cos it's the lowest impact observer
+        assertEquals(1, observerMidPackages.size());
+        assertEquals(APP_B, observerMidPackages.get(0));
+        // APP_A failure is caught by observerLow cos it's the lowest impact observer
+        assertEquals(1, observerLowPackages.size());
+        assertEquals(APP_A, observerLowPackages.get(0));
+    }
+
+    /**
+     * Test package failure and least impact observers are notified successively.
+     * State transistions:
+     *
+     * <ul>
+     * <li>(observer1:low, observer2:mid) -> {observer1}
+     * <li>(observer1:high, observer2:mid) -> {observer2}
+     * <li>(observer1:high, observer2:none) -> {observer1}
+     * <li>(observer1:none, observer2:none) -> {}
+     * <ul>
+     */
+    @Test
+    public void testPackageFailureNotifyLeastSuccessively() throws Exception {
+        PackageWatchdog watchdog = createWatchdog();
+        TestObserver observerFirst = new TestObserver(OBSERVER_NAME_1,
+                PackageHealthObserverImpact.USER_IMPACT_LOW);
+        TestObserver observerSecond = new TestObserver(OBSERVER_NAME_2,
+                PackageHealthObserverImpact.USER_IMPACT_MEDIUM);
+
+        // Start observing for observerFirst and observerSecond with failure handling
+        watchdog.startObservingHealth(observerFirst, Arrays.asList(APP_A), LONG_DURATION);
+        watchdog.startObservingHealth(observerSecond, Arrays.asList(APP_A), LONG_DURATION);
+
+        // Then fail APP_A above the threshold
+        for (int i = 0; i < TRIGGER_FAILURE_COUNT; i++) {
+            watchdog.onPackageFailure(new String[]{APP_A});
+        }
+        // Run handler so package failures are dispatched to observers
+        mTestLooper.dispatchAll();
+
+        // Verify only observerFirst is notifed
+        assertEquals(1, observerFirst.mFailedPackages.size());
+        assertEquals(APP_A, observerFirst.mFailedPackages.get(0));
+        assertEquals(0, observerSecond.mFailedPackages.size());
+
+        // After observerFirst handles failure, next action it has is high impact
+        observerFirst.mImpact = PackageHealthObserverImpact.USER_IMPACT_HIGH;
+        observerFirst.mFailedPackages.clear();
+        observerSecond.mFailedPackages.clear();
+
+        // Then fail APP_A again above the threshold
+        for (int i = 0; i < TRIGGER_FAILURE_COUNT; i++) {
+            watchdog.onPackageFailure(new String[]{APP_A});
+        }
+        // Run handler so package failures are dispatched to observers
+        mTestLooper.dispatchAll();
+
+        // Verify only observerSecond is notifed cos it has least impact
+        assertEquals(1, observerSecond.mFailedPackages.size());
+        assertEquals(APP_A, observerSecond.mFailedPackages.get(0));
+        assertEquals(0, observerFirst.mFailedPackages.size());
+
+        // After observerSecond handles failure, it has no further actions
+        observerSecond.mImpact = PackageHealthObserverImpact.USER_IMPACT_NONE;
+        observerFirst.mFailedPackages.clear();
+        observerSecond.mFailedPackages.clear();
+
+        // Then fail APP_A again above the threshold
+        for (int i = 0; i < TRIGGER_FAILURE_COUNT; i++) {
+            watchdog.onPackageFailure(new String[]{APP_A});
+        }
+        // Run handler so package failures are dispatched to observers
+        mTestLooper.dispatchAll();
+
+        // Verify only observerFirst is notifed cos it has the only action
+        assertEquals(1, observerFirst.mFailedPackages.size());
+        assertEquals(APP_A, observerFirst.mFailedPackages.get(0));
+        assertEquals(0, observerSecond.mFailedPackages.size());
+
+        // After observerFirst handles failure, it too has no further actions
+        observerFirst.mImpact = PackageHealthObserverImpact.USER_IMPACT_NONE;
+        observerFirst.mFailedPackages.clear();
+        observerSecond.mFailedPackages.clear();
+
+        // Then fail APP_A again above the threshold
+        for (int i = 0; i < TRIGGER_FAILURE_COUNT; i++) {
+            watchdog.onPackageFailure(new String[]{APP_A});
+        }
+        // Run handler so package failures are dispatched to observers
+        mTestLooper.dispatchAll();
+
+        // Verify no observer is notified cos no actions left
+        assertEquals(0, observerFirst.mFailedPackages.size());
+        assertEquals(0, observerSecond.mFailedPackages.size());
+    }
+
+    /**
+     * Test package failure and notifies only one observer even with observer impact tie.
+     */
+    @Test
+    public void testPackageFailureNotifyOneSameImpact() throws Exception {
+        PackageWatchdog watchdog = createWatchdog();
+        TestObserver observer1 = new TestObserver(OBSERVER_NAME_1,
+                PackageHealthObserverImpact.USER_IMPACT_HIGH);
+        TestObserver observer2 = new TestObserver(OBSERVER_NAME_2,
+                PackageHealthObserverImpact.USER_IMPACT_HIGH);
 
         // Start observing for observer1 and observer2 with failure handling
         watchdog.startObservingHealth(observer2, Arrays.asList(APP_A), SHORT_DURATION);
@@ -249,6 +391,9 @@
             watchdog.onPackageFailure(new String[]{APP_A});
         }
 
+        // Run handler so package failures are dispatched to observers
+        mTestLooper.dispatchAll();
+
         // Verify only one observer is notifed
         assertEquals(1, observer1.mFailedPackages.size());
         assertEquals(APP_A, observer1.mFailedPackages.get(0));
@@ -262,21 +407,26 @@
 
     private static class TestObserver implements PackageHealthObserver {
         private final String mName;
-        private boolean mShouldHandle;
+        private int mImpact;
         final List<String> mFailedPackages = new ArrayList<>();
 
         TestObserver(String name) {
             mName = name;
+            mImpact = PackageHealthObserverImpact.USER_IMPACT_MEDIUM;
         }
 
-        TestObserver(String name, boolean shouldHandle) {
+        TestObserver(String name, int impact) {
             mName = name;
-            mShouldHandle = shouldHandle;
+            mImpact = impact;
         }
 
-        public boolean onHealthCheckFailed(String packageName) {
+        public int onHealthCheckFailed(String packageName) {
+            return mImpact;
+        }
+
+        public boolean execute(String packageName) {
             mFailedPackages.add(packageName);
-            return mShouldHandle;
+            return true;
         }
 
         public String getName() {
diff --git a/tests/RollbackTest/src/com/android/tests/rollback/RollbackTest.java b/tests/RollbackTest/src/com/android/tests/rollback/RollbackTest.java
index 7ab716f..0493ef8 100644
--- a/tests/RollbackTest/src/com/android/tests/rollback/RollbackTest.java
+++ b/tests/RollbackTest/src/com/android/tests/rollback/RollbackTest.java
@@ -139,7 +139,7 @@
             assertNull(broadcastReceiver.poll(0, TimeUnit.SECONDS));
 
             // Roll back the app.
-            RollbackTestUtils.rollback(rollback);
+            RollbackTestUtils.rollback(rollback.getRollbackId());
             assertEquals(1, RollbackTestUtils.getInstalledVersion(TEST_APP_A));
 
             // Verify we received a broadcast for the rollback.
@@ -211,7 +211,7 @@
             assertRollbackInfoEquals(TEST_APP_B, 2, 1, rollbackB);
 
             // Rollback of B should not rollback A
-            RollbackTestUtils.rollback(rollbackB);
+            RollbackTestUtils.rollback(rollbackB.getRollbackId());
             assertEquals(2, RollbackTestUtils.getInstalledVersion(TEST_APP_A));
             assertEquals(1, RollbackTestUtils.getInstalledVersion(TEST_APP_B));
         } finally {
@@ -268,7 +268,7 @@
             assertRollbackInfoForAandB(rollbackB);
 
             // Rollback of B should rollback A as well
-            RollbackTestUtils.rollback(rollbackB);
+            RollbackTestUtils.rollback(rollbackB.getRollbackId());
             assertEquals(1, RollbackTestUtils.getInstalledVersion(TEST_APP_A));
             assertEquals(1, RollbackTestUtils.getInstalledVersion(TEST_APP_B));
         } finally {
@@ -303,7 +303,7 @@
                     rm.getAvailableRollbacks(), TEST_APP_A);
 
             // Roll back the app.
-            RollbackTestUtils.rollback(rollback);
+            RollbackTestUtils.rollback(rollback.getRollbackId());
             assertEquals(1, RollbackTestUtils.getInstalledVersion(TEST_APP_A));
 
             // Verify the recent rollback has been recorded.
@@ -430,7 +430,7 @@
             RollbackManager rm = RollbackTestUtils.getRollbackManager();
             RollbackInfo rollback = getUniqueRollbackInfoForPackage(
                     rm.getAvailableRollbacks(), TEST_APP_A);
-            RollbackTestUtils.rollback(rollback);
+            RollbackTestUtils.rollback(rollback.getRollbackId());
             processUserData(TEST_APP_A);
         } finally {
             RollbackTestUtils.dropShellPermissionIdentity();
@@ -500,7 +500,7 @@
             assertRollbackInfoEquals(TEST_APP_B, 2, 1, rollbackB);
 
             // Executing rollback should roll back the correct package.
-            RollbackTestUtils.rollback(rollbackA);
+            RollbackTestUtils.rollback(rollbackA.getRollbackId());
             assertEquals(1, RollbackTestUtils.getInstalledVersion(TEST_APP_A));
             assertEquals(2, RollbackTestUtils.getInstalledVersion(TEST_APP_B));
 
@@ -509,7 +509,7 @@
             RollbackTestUtils.install("RollbackTestAppAv2.apk", true);
             assertEquals(2, RollbackTestUtils.getInstalledVersion(TEST_APP_A));
 
-            RollbackTestUtils.rollback(rollbackB);
+            RollbackTestUtils.rollback(rollbackB.getRollbackId());
             assertEquals(2, RollbackTestUtils.getInstalledVersion(TEST_APP_A));
             assertEquals(1, RollbackTestUtils.getInstalledVersion(TEST_APP_B));
         } finally {
@@ -544,7 +544,7 @@
         try {
             // TODO: What if the implementation checks arguments for non-null
             // first? Then this test isn't valid.
-            rm.commitRollback(null, null);
+            rm.commitRollback(0, null);
             fail("expected SecurityException");
         } catch (SecurityException e) {
             // Expected.
@@ -598,7 +598,7 @@
 
             // Rollback the app. It should cause both test apps to be rolled
             // back.
-            RollbackTestUtils.rollback(rollback);
+            RollbackTestUtils.rollback(rollback.getRollbackId());
             assertEquals(1, RollbackTestUtils.getInstalledVersion(TEST_APP_A));
             assertEquals(1, RollbackTestUtils.getInstalledVersion(TEST_APP_B));
 
diff --git a/tests/RollbackTest/src/com/android/tests/rollback/RollbackTestUtils.java b/tests/RollbackTest/src/com/android/tests/rollback/RollbackTestUtils.java
index f481897..1478657 100644
--- a/tests/RollbackTest/src/com/android/tests/rollback/RollbackTestUtils.java
+++ b/tests/RollbackTest/src/com/android/tests/rollback/RollbackTestUtils.java
@@ -21,7 +21,6 @@
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageInstaller;
 import android.content.pm.PackageManager;
-import android.content.rollback.RollbackInfo;
 import android.content.rollback.RollbackManager;
 import android.support.test.InstrumentationRegistry;
 
@@ -93,9 +92,9 @@
      * Commit the given rollback.
      * @throws AssertionError if the rollback fails.
      */
-    static void rollback(RollbackInfo rollback) throws InterruptedException {
+    static void rollback(int rollbackId) throws InterruptedException {
         RollbackManager rm = getRollbackManager();
-        rm.commitRollback(rollback, LocalIntentSender.getIntentSender());
+        rm.commitRollback(rollbackId, LocalIntentSender.getIntentSender());
         assertStatusSuccess(LocalIntentSender.getIntentSenderResult());
     }
 
diff --git a/tests/net/java/android/net/NetworkUtilsTest.java b/tests/net/java/android/net/NetworkUtilsTest.java
index 3452819..ba6e0f2 100644
--- a/tests/net/java/android/net/NetworkUtilsTest.java
+++ b/tests/net/java/android/net/NetworkUtilsTest.java
@@ -16,161 +16,19 @@
 
 package android.net;
 
-import static android.net.NetworkUtils.getImplicitNetmask;
-import static android.net.NetworkUtils.inet4AddressToIntHTH;
-import static android.net.NetworkUtils.inet4AddressToIntHTL;
-import static android.net.NetworkUtils.intToInet4AddressHTH;
-import static android.net.NetworkUtils.intToInet4AddressHTL;
-import static android.net.NetworkUtils.netmaskToPrefixLength;
-import static android.net.NetworkUtils.prefixLengthToV4NetmaskIntHTH;
-import static android.net.NetworkUtils.prefixLengthToV4NetmaskIntHTL;
-import static android.net.NetworkUtils.getBroadcastAddress;
-import static android.net.NetworkUtils.getPrefixMaskAsInet4Address;
-
 import static junit.framework.Assert.assertEquals;
 
-import static org.junit.Assert.fail;
-
 import android.support.test.runner.AndroidJUnit4;
 
-import java.math.BigInteger;
-import java.net.Inet4Address;
-import java.net.InetAddress;
-import java.util.TreeSet;
-
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
+import java.math.BigInteger;
+import java.util.TreeSet;
+
 @RunWith(AndroidJUnit4.class)
 @android.support.test.filters.SmallTest
 public class NetworkUtilsTest {
-
-    private InetAddress Address(String addr) {
-        return InetAddress.parseNumericAddress(addr);
-    }
-
-    private Inet4Address IPv4Address(String addr) {
-        return (Inet4Address) Address(addr);
-    }
-
-    @Test
-    public void testGetImplicitNetmask() {
-        assertEquals(8, getImplicitNetmask(IPv4Address("4.2.2.2")));
-        assertEquals(8, getImplicitNetmask(IPv4Address("10.5.6.7")));
-        assertEquals(16, getImplicitNetmask(IPv4Address("173.194.72.105")));
-        assertEquals(16, getImplicitNetmask(IPv4Address("172.23.68.145")));
-        assertEquals(24, getImplicitNetmask(IPv4Address("192.0.2.1")));
-        assertEquals(24, getImplicitNetmask(IPv4Address("192.168.5.1")));
-        assertEquals(32, getImplicitNetmask(IPv4Address("224.0.0.1")));
-        assertEquals(32, getImplicitNetmask(IPv4Address("255.6.7.8")));
-    }
-
-    private void assertInvalidNetworkMask(Inet4Address addr) {
-        try {
-            netmaskToPrefixLength(addr);
-            fail("Invalid netmask " + addr.getHostAddress() + " did not cause exception");
-        } catch (IllegalArgumentException expected) {
-        }
-    }
-
-    @Test
-    public void testInet4AddressToIntHTL() {
-        assertEquals(0, inet4AddressToIntHTL(IPv4Address("0.0.0.0")));
-        assertEquals(0x000080ff, inet4AddressToIntHTL(IPv4Address("255.128.0.0")));
-        assertEquals(0x0080ff0a, inet4AddressToIntHTL(IPv4Address("10.255.128.0")));
-        assertEquals(0x00feff0a, inet4AddressToIntHTL(IPv4Address("10.255.254.0")));
-        assertEquals(0xfeffa8c0, inet4AddressToIntHTL(IPv4Address("192.168.255.254")));
-        assertEquals(0xffffa8c0, inet4AddressToIntHTL(IPv4Address("192.168.255.255")));
-    }
-
-    @Test
-    public void testIntToInet4AddressHTL() {
-        assertEquals(IPv4Address("0.0.0.0"), intToInet4AddressHTL(0));
-        assertEquals(IPv4Address("255.128.0.0"), intToInet4AddressHTL(0x000080ff));
-        assertEquals(IPv4Address("10.255.128.0"), intToInet4AddressHTL(0x0080ff0a));
-        assertEquals(IPv4Address("10.255.254.0"), intToInet4AddressHTL(0x00feff0a));
-        assertEquals(IPv4Address("192.168.255.254"), intToInet4AddressHTL(0xfeffa8c0));
-        assertEquals(IPv4Address("192.168.255.255"), intToInet4AddressHTL(0xffffa8c0));
-    }
-
-    @Test
-    public void testInet4AddressToIntHTH() {
-        assertEquals(0, inet4AddressToIntHTH(IPv4Address("0.0.0.0")));
-        assertEquals(0xff800000, inet4AddressToIntHTH(IPv4Address("255.128.0.0")));
-        assertEquals(0x0aff8000, inet4AddressToIntHTH(IPv4Address("10.255.128.0")));
-        assertEquals(0x0afffe00, inet4AddressToIntHTH(IPv4Address("10.255.254.0")));
-        assertEquals(0xc0a8fffe, inet4AddressToIntHTH(IPv4Address("192.168.255.254")));
-        assertEquals(0xc0a8ffff, inet4AddressToIntHTH(IPv4Address("192.168.255.255")));
-    }
-
-    @Test
-    public void testIntToInet4AddressHTH() {
-        assertEquals(IPv4Address("0.0.0.0"), intToInet4AddressHTH(0));
-        assertEquals(IPv4Address("255.128.0.0"), intToInet4AddressHTH(0xff800000));
-        assertEquals(IPv4Address("10.255.128.0"), intToInet4AddressHTH(0x0aff8000));
-        assertEquals(IPv4Address("10.255.254.0"), intToInet4AddressHTH(0x0afffe00));
-        assertEquals(IPv4Address("192.168.255.254"), intToInet4AddressHTH(0xc0a8fffe));
-        assertEquals(IPv4Address("192.168.255.255"), intToInet4AddressHTH(0xc0a8ffff));
-    }
-
-    @Test
-    public void testNetmaskToPrefixLength() {
-        assertEquals(0, netmaskToPrefixLength(IPv4Address("0.0.0.0")));
-        assertEquals(9, netmaskToPrefixLength(IPv4Address("255.128.0.0")));
-        assertEquals(17, netmaskToPrefixLength(IPv4Address("255.255.128.0")));
-        assertEquals(23, netmaskToPrefixLength(IPv4Address("255.255.254.0")));
-        assertEquals(31, netmaskToPrefixLength(IPv4Address("255.255.255.254")));
-        assertEquals(32, netmaskToPrefixLength(IPv4Address("255.255.255.255")));
-
-        assertInvalidNetworkMask(IPv4Address("0.0.0.1"));
-        assertInvalidNetworkMask(IPv4Address("255.255.255.253"));
-        assertInvalidNetworkMask(IPv4Address("255.255.0.255"));
-    }
-
-    @Test
-    public void testPrefixLengthToV4NetmaskIntHTL() {
-        assertEquals(0, prefixLengthToV4NetmaskIntHTL(0));
-        assertEquals(0x000080ff /* 255.128.0.0 */, prefixLengthToV4NetmaskIntHTL(9));
-        assertEquals(0x0080ffff /* 255.255.128.0 */, prefixLengthToV4NetmaskIntHTL(17));
-        assertEquals(0x00feffff /* 255.255.254.0 */, prefixLengthToV4NetmaskIntHTL(23));
-        assertEquals(0xfeffffff /* 255.255.255.254 */, prefixLengthToV4NetmaskIntHTL(31));
-        assertEquals(0xffffffff /* 255.255.255.255 */, prefixLengthToV4NetmaskIntHTL(32));
-    }
-
-    @Test
-    public void testPrefixLengthToV4NetmaskIntHTH() {
-        assertEquals(0, prefixLengthToV4NetmaskIntHTH(0));
-        assertEquals(0xff800000 /* 255.128.0.0 */, prefixLengthToV4NetmaskIntHTH(9));
-        assertEquals(0xffff8000 /* 255.255.128.0 */, prefixLengthToV4NetmaskIntHTH(17));
-        assertEquals(0xfffffe00 /* 255.255.254.0 */, prefixLengthToV4NetmaskIntHTH(23));
-        assertEquals(0xfffffffe /* 255.255.255.254 */, prefixLengthToV4NetmaskIntHTH(31));
-        assertEquals(0xffffffff /* 255.255.255.255 */, prefixLengthToV4NetmaskIntHTH(32));
-    }
-
-    @Test(expected = IllegalArgumentException.class)
-    public void testPrefixLengthToV4NetmaskIntHTH_NegativeLength() {
-        prefixLengthToV4NetmaskIntHTH(-1);
-    }
-
-    @Test(expected = IllegalArgumentException.class)
-    public void testPrefixLengthToV4NetmaskIntHTH_LengthTooLarge() {
-        prefixLengthToV4NetmaskIntHTH(33);
-    }
-
-    private void checkAddressMasking(String expectedAddr, String addr, int prefixLength) {
-        final int prefix = prefixLengthToV4NetmaskIntHTH(prefixLength);
-        final int addrInt = inet4AddressToIntHTH(IPv4Address(addr));
-        assertEquals(IPv4Address(expectedAddr), intToInet4AddressHTH(prefix & addrInt));
-    }
-
-    @Test
-    public void testPrefixLengthToV4NetmaskIntHTH_MaskAddr() {
-        checkAddressMasking("192.168.0.0", "192.168.128.1", 16);
-        checkAddressMasking("255.240.0.0", "255.255.255.255", 12);
-        checkAddressMasking("255.255.255.255", "255.255.255.255", 32);
-        checkAddressMasking("0.0.0.0", "255.255.255.255", 0);
-    }
-
     @Test
     public void testRoutedIPv4AddressCount() {
         final TreeSet<IpPrefix> set = new TreeSet<>(IpPrefix.lengthComparator());
@@ -267,44 +125,4 @@
         assertEquals(BigInteger.valueOf(7l - 4 + 4 + 16 + 65536),
                 NetworkUtils.routedIPv6AddressCount(set));
     }
-
-    @Test
-    public void testGetPrefixMaskAsAddress() {
-        assertEquals("255.255.240.0", getPrefixMaskAsInet4Address(20).getHostAddress());
-        assertEquals("255.0.0.0", getPrefixMaskAsInet4Address(8).getHostAddress());
-        assertEquals("0.0.0.0", getPrefixMaskAsInet4Address(0).getHostAddress());
-        assertEquals("255.255.255.255", getPrefixMaskAsInet4Address(32).getHostAddress());
-    }
-
-    @Test(expected = IllegalArgumentException.class)
-    public void testGetPrefixMaskAsAddress_PrefixTooLarge() {
-        getPrefixMaskAsInet4Address(33);
-    }
-
-    @Test(expected = IllegalArgumentException.class)
-    public void testGetPrefixMaskAsAddress_NegativePrefix() {
-        getPrefixMaskAsInet4Address(-1);
-    }
-
-    @Test
-    public void testGetBroadcastAddress() {
-        assertEquals("192.168.15.255",
-                getBroadcastAddress(IPv4Address("192.168.0.123"), 20).getHostAddress());
-        assertEquals("192.255.255.255",
-                getBroadcastAddress(IPv4Address("192.168.0.123"), 8).getHostAddress());
-        assertEquals("192.168.0.123",
-                getBroadcastAddress(IPv4Address("192.168.0.123"), 32).getHostAddress());
-        assertEquals("255.255.255.255",
-                getBroadcastAddress(IPv4Address("192.168.0.123"), 0).getHostAddress());
-    }
-
-    @Test(expected = IllegalArgumentException.class)
-    public void testGetBroadcastAddress_PrefixTooLarge() {
-        getBroadcastAddress(IPv4Address("192.168.0.123"), 33);
-    }
-
-    @Test(expected = IllegalArgumentException.class)
-    public void testGetBroadcastAddress_NegativePrefix() {
-        getBroadcastAddress(IPv4Address("192.168.0.123"), -1);
-    }
 }
diff --git a/tests/net/java/android/net/StaticIpConfigurationTest.java b/tests/net/java/android/net/StaticIpConfigurationTest.java
index 5bb5734..2b5ad37 100644
--- a/tests/net/java/android/net/StaticIpConfigurationTest.java
+++ b/tests/net/java/android/net/StaticIpConfigurationTest.java
@@ -26,13 +26,13 @@
 import android.support.test.filters.SmallTest;
 import android.support.test.runner.AndroidJUnit4;
 
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
 import java.net.InetAddress;
 import java.util.HashSet;
 import java.util.Objects;
 
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
 @RunWith(AndroidJUnit4.class)
 @SmallTest
 public class StaticIpConfigurationTest {
@@ -203,7 +203,7 @@
         try {
             s.writeToParcel(p, 0);
             p.setDataPosition(0);
-            s2 = StaticIpConfiguration.CREATOR.createFromParcel(p);
+            s2 = StaticIpConfiguration.readFromParcel(p);
         } finally {
             p.recycle();
         }
diff --git a/tests/net/java/android/net/ip/IpServerTest.java b/tests/net/java/android/net/ip/IpServerTest.java
index 80aac04..f7542a7 100644
--- a/tests/net/java/android/net/ip/IpServerTest.java
+++ b/tests/net/java/android/net/ip/IpServerTest.java
@@ -22,11 +22,11 @@
 import static android.net.ConnectivityManager.TETHER_ERROR_ENABLE_NAT_ERROR;
 import static android.net.ConnectivityManager.TETHER_ERROR_NO_ERROR;
 import static android.net.ConnectivityManager.TETHER_ERROR_TETHER_IFACE_ERROR;
-import static android.net.NetworkUtils.intToInet4AddressHTH;
 import static android.net.dhcp.IDhcpServer.STATUS_SUCCESS;
 import static android.net.ip.IpServer.STATE_AVAILABLE;
 import static android.net.ip.IpServer.STATE_TETHERED;
 import static android.net.ip.IpServer.STATE_UNAVAILABLE;
+import static android.net.shared.Inet4AddressUtils.intToInet4AddressHTH;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
diff --git a/tests/net/java/android/net/shared/Inet4AddressUtilsTest.java b/tests/net/java/android/net/shared/Inet4AddressUtilsTest.java
new file mode 100644
index 0000000..6da8514
--- /dev/null
+++ b/tests/net/java/android/net/shared/Inet4AddressUtilsTest.java
@@ -0,0 +1,209 @@
+/*
+ * 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.shared;
+
+import static android.net.shared.Inet4AddressUtils.getBroadcastAddress;
+import static android.net.shared.Inet4AddressUtils.getImplicitNetmask;
+import static android.net.shared.Inet4AddressUtils.getPrefixMaskAsInet4Address;
+import static android.net.shared.Inet4AddressUtils.inet4AddressToIntHTH;
+import static android.net.shared.Inet4AddressUtils.inet4AddressToIntHTL;
+import static android.net.shared.Inet4AddressUtils.intToInet4AddressHTH;
+import static android.net.shared.Inet4AddressUtils.intToInet4AddressHTL;
+import static android.net.shared.Inet4AddressUtils.netmaskToPrefixLength;
+import static android.net.shared.Inet4AddressUtils.prefixLengthToV4NetmaskIntHTH;
+import static android.net.shared.Inet4AddressUtils.prefixLengthToV4NetmaskIntHTL;
+
+import static junit.framework.Assert.assertEquals;
+
+import static org.junit.Assert.fail;
+
+import android.net.InetAddresses;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.net.Inet4Address;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class Inet4AddressUtilsTest {
+
+    @Test
+    public void testInet4AddressToIntHTL() {
+        assertEquals(0, inet4AddressToIntHTL(ipv4Address("0.0.0.0")));
+        assertEquals(0x000080ff, inet4AddressToIntHTL(ipv4Address("255.128.0.0")));
+        assertEquals(0x0080ff0a, inet4AddressToIntHTL(ipv4Address("10.255.128.0")));
+        assertEquals(0x00feff0a, inet4AddressToIntHTL(ipv4Address("10.255.254.0")));
+        assertEquals(0xfeffa8c0, inet4AddressToIntHTL(ipv4Address("192.168.255.254")));
+        assertEquals(0xffffa8c0, inet4AddressToIntHTL(ipv4Address("192.168.255.255")));
+    }
+
+    @Test
+    public void testIntToInet4AddressHTL() {
+        assertEquals(ipv4Address("0.0.0.0"), intToInet4AddressHTL(0));
+        assertEquals(ipv4Address("255.128.0.0"), intToInet4AddressHTL(0x000080ff));
+        assertEquals(ipv4Address("10.255.128.0"), intToInet4AddressHTL(0x0080ff0a));
+        assertEquals(ipv4Address("10.255.254.0"), intToInet4AddressHTL(0x00feff0a));
+        assertEquals(ipv4Address("192.168.255.254"), intToInet4AddressHTL(0xfeffa8c0));
+        assertEquals(ipv4Address("192.168.255.255"), intToInet4AddressHTL(0xffffa8c0));
+    }
+
+    @Test
+    public void testInet4AddressToIntHTH() {
+        assertEquals(0, inet4AddressToIntHTH(ipv4Address("0.0.0.0")));
+        assertEquals(0xff800000, inet4AddressToIntHTH(ipv4Address("255.128.0.0")));
+        assertEquals(0x0aff8000, inet4AddressToIntHTH(ipv4Address("10.255.128.0")));
+        assertEquals(0x0afffe00, inet4AddressToIntHTH(ipv4Address("10.255.254.0")));
+        assertEquals(0xc0a8fffe, inet4AddressToIntHTH(ipv4Address("192.168.255.254")));
+        assertEquals(0xc0a8ffff, inet4AddressToIntHTH(ipv4Address("192.168.255.255")));
+    }
+
+    @Test
+    public void testIntToInet4AddressHTH() {
+        assertEquals(ipv4Address("0.0.0.0"), intToInet4AddressHTH(0));
+        assertEquals(ipv4Address("255.128.0.0"), intToInet4AddressHTH(0xff800000));
+        assertEquals(ipv4Address("10.255.128.0"), intToInet4AddressHTH(0x0aff8000));
+        assertEquals(ipv4Address("10.255.254.0"), intToInet4AddressHTH(0x0afffe00));
+        assertEquals(ipv4Address("192.168.255.254"), intToInet4AddressHTH(0xc0a8fffe));
+        assertEquals(ipv4Address("192.168.255.255"), intToInet4AddressHTH(0xc0a8ffff));
+    }
+
+
+    @Test
+    public void testPrefixLengthToV4NetmaskIntHTL() {
+        assertEquals(0, prefixLengthToV4NetmaskIntHTL(0));
+        assertEquals(0x000080ff /* 255.128.0.0 */, prefixLengthToV4NetmaskIntHTL(9));
+        assertEquals(0x0080ffff /* 255.255.128.0 */, prefixLengthToV4NetmaskIntHTL(17));
+        assertEquals(0x00feffff /* 255.255.254.0 */, prefixLengthToV4NetmaskIntHTL(23));
+        assertEquals(0xfeffffff /* 255.255.255.254 */, prefixLengthToV4NetmaskIntHTL(31));
+        assertEquals(0xffffffff /* 255.255.255.255 */, prefixLengthToV4NetmaskIntHTL(32));
+    }
+
+    @Test
+    public void testPrefixLengthToV4NetmaskIntHTH() {
+        assertEquals(0, prefixLengthToV4NetmaskIntHTH(0));
+        assertEquals(0xff800000 /* 255.128.0.0 */, prefixLengthToV4NetmaskIntHTH(9));
+        assertEquals(0xffff8000 /* 255.255.128.0 */, prefixLengthToV4NetmaskIntHTH(17));
+        assertEquals(0xfffffe00 /* 255.255.254.0 */, prefixLengthToV4NetmaskIntHTH(23));
+        assertEquals(0xfffffffe /* 255.255.255.254 */, prefixLengthToV4NetmaskIntHTH(31));
+        assertEquals(0xffffffff /* 255.255.255.255 */, prefixLengthToV4NetmaskIntHTH(32));
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testPrefixLengthToV4NetmaskIntHTH_NegativeLength() {
+        prefixLengthToV4NetmaskIntHTH(-1);
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testPrefixLengthToV4NetmaskIntHTH_LengthTooLarge() {
+        prefixLengthToV4NetmaskIntHTH(33);
+    }
+
+    private void checkAddressMasking(String expectedAddr, String addr, int prefixLength) {
+        final int prefix = prefixLengthToV4NetmaskIntHTH(prefixLength);
+        final int addrInt = inet4AddressToIntHTH(ipv4Address(addr));
+        assertEquals(ipv4Address(expectedAddr), intToInet4AddressHTH(prefix & addrInt));
+    }
+
+    @Test
+    public void testPrefixLengthToV4NetmaskIntHTH_MaskAddr() {
+        checkAddressMasking("192.168.0.0", "192.168.128.1", 16);
+        checkAddressMasking("255.240.0.0", "255.255.255.255", 12);
+        checkAddressMasking("255.255.255.255", "255.255.255.255", 32);
+        checkAddressMasking("0.0.0.0", "255.255.255.255", 0);
+    }
+
+    @Test
+    public void testGetImplicitNetmask() {
+        assertEquals(8, getImplicitNetmask(ipv4Address("4.2.2.2")));
+        assertEquals(8, getImplicitNetmask(ipv4Address("10.5.6.7")));
+        assertEquals(16, getImplicitNetmask(ipv4Address("173.194.72.105")));
+        assertEquals(16, getImplicitNetmask(ipv4Address("172.23.68.145")));
+        assertEquals(24, getImplicitNetmask(ipv4Address("192.0.2.1")));
+        assertEquals(24, getImplicitNetmask(ipv4Address("192.168.5.1")));
+        assertEquals(32, getImplicitNetmask(ipv4Address("224.0.0.1")));
+        assertEquals(32, getImplicitNetmask(ipv4Address("255.6.7.8")));
+    }
+
+    private void assertInvalidNetworkMask(Inet4Address addr) {
+        try {
+            netmaskToPrefixLength(addr);
+            fail("Invalid netmask " + addr.getHostAddress() + " did not cause exception");
+        } catch (IllegalArgumentException expected) {
+        }
+    }
+
+    @Test
+    public void testNetmaskToPrefixLength() {
+        assertEquals(0, netmaskToPrefixLength(ipv4Address("0.0.0.0")));
+        assertEquals(9, netmaskToPrefixLength(ipv4Address("255.128.0.0")));
+        assertEquals(17, netmaskToPrefixLength(ipv4Address("255.255.128.0")));
+        assertEquals(23, netmaskToPrefixLength(ipv4Address("255.255.254.0")));
+        assertEquals(31, netmaskToPrefixLength(ipv4Address("255.255.255.254")));
+        assertEquals(32, netmaskToPrefixLength(ipv4Address("255.255.255.255")));
+
+        assertInvalidNetworkMask(ipv4Address("0.0.0.1"));
+        assertInvalidNetworkMask(ipv4Address("255.255.255.253"));
+        assertInvalidNetworkMask(ipv4Address("255.255.0.255"));
+    }
+
+    @Test
+    public void testGetPrefixMaskAsAddress() {
+        assertEquals("255.255.240.0", getPrefixMaskAsInet4Address(20).getHostAddress());
+        assertEquals("255.0.0.0", getPrefixMaskAsInet4Address(8).getHostAddress());
+        assertEquals("0.0.0.0", getPrefixMaskAsInet4Address(0).getHostAddress());
+        assertEquals("255.255.255.255", getPrefixMaskAsInet4Address(32).getHostAddress());
+    }
+
+    @Test
+    public void testGetBroadcastAddress() {
+        assertEquals("192.168.15.255",
+                getBroadcastAddress(ipv4Address("192.168.0.123"), 20).getHostAddress());
+        assertEquals("192.255.255.255",
+                getBroadcastAddress(ipv4Address("192.168.0.123"), 8).getHostAddress());
+        assertEquals("192.168.0.123",
+                getBroadcastAddress(ipv4Address("192.168.0.123"), 32).getHostAddress());
+        assertEquals("255.255.255.255",
+                getBroadcastAddress(ipv4Address("192.168.0.123"), 0).getHostAddress());
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testGetBroadcastAddress_PrefixTooLarge() {
+        getBroadcastAddress(ipv4Address("192.168.0.123"), 33);
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testGetBroadcastAddress_NegativePrefix() {
+        getBroadcastAddress(ipv4Address("192.168.0.123"), -1);
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testGetPrefixMaskAsAddress_PrefixTooLarge() {
+        getPrefixMaskAsInet4Address(33);
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testGetPrefixMaskAsAddress_NegativePrefix() {
+        getPrefixMaskAsInet4Address(-1);
+    }
+
+    private Inet4Address ipv4Address(String addr) {
+        return (Inet4Address) InetAddresses.parseNumericAddress(addr);
+    }
+}
diff --git a/tests/net/java/android/net/shared/IpConfigurationParcelableUtilTest.java b/tests/net/java/android/net/shared/IpConfigurationParcelableUtilTest.java
index 14df392..fb4d43c 100644
--- a/tests/net/java/android/net/shared/IpConfigurationParcelableUtilTest.java
+++ b/tests/net/java/android/net/shared/IpConfigurationParcelableUtilTest.java
@@ -62,7 +62,7 @@
         mDhcpResults.leaseDuration = 3600;
         mDhcpResults.mtu = 1450;
         // Any added DhcpResults field must be included in equals() to be tested properly
-        assertFieldCountEquals(4, DhcpResults.class);
+        assertFieldCountEquals(8, DhcpResults.class);
     }
 
     @Test
diff --git a/tests/net/java/com/android/server/connectivity/VpnTest.java b/tests/net/java/com/android/server/connectivity/VpnTest.java
index 0b74d87..5b17224 100644
--- a/tests/net/java/com/android/server/connectivity/VpnTest.java
+++ b/tests/net/java/com/android/server/connectivity/VpnTest.java
@@ -246,17 +246,17 @@
         assertFalse(vpn.getLockdown());
 
         // Set always-on without lockdown.
-        assertTrue(vpn.setAlwaysOnPackage(PKGS[1], false));
+        assertTrue(vpn.setAlwaysOnPackage(PKGS[1], false, Collections.emptyList()));
         assertTrue(vpn.getAlwaysOn());
         assertFalse(vpn.getLockdown());
 
         // Set always-on with lockdown.
-        assertTrue(vpn.setAlwaysOnPackage(PKGS[1], true));
+        assertTrue(vpn.setAlwaysOnPackage(PKGS[1], true, Collections.emptyList()));
         assertTrue(vpn.getAlwaysOn());
         assertTrue(vpn.getLockdown());
 
         // Remove always-on configuration.
-        assertTrue(vpn.setAlwaysOnPackage(null, false));
+        assertTrue(vpn.setAlwaysOnPackage(null, false, Collections.emptyList()));
         assertFalse(vpn.getAlwaysOn());
         assertFalse(vpn.getLockdown());
     }
@@ -270,11 +270,11 @@
         assertUnblocked(vpn, user.start + PKG_UIDS[0], user.start + PKG_UIDS[1], user.start + PKG_UIDS[2], user.start + PKG_UIDS[3]);
 
         // Set always-on without lockdown.
-        assertTrue(vpn.setAlwaysOnPackage(PKGS[1], false));
+        assertTrue(vpn.setAlwaysOnPackage(PKGS[1], false, null));
         assertUnblocked(vpn, user.start + PKG_UIDS[0], user.start + PKG_UIDS[1], user.start + PKG_UIDS[2], user.start + PKG_UIDS[3]);
 
         // Set always-on with lockdown.
-        assertTrue(vpn.setAlwaysOnPackage(PKGS[1], true));
+        assertTrue(vpn.setAlwaysOnPackage(PKGS[1], true, null));
         verify(mNetService).setAllowOnlyVpnForUids(eq(true), aryEq(new UidRange[] {
             new UidRange(user.start, user.start + PKG_UIDS[1] - 1),
             new UidRange(user.start + PKG_UIDS[1] + 1, user.stop)
@@ -283,7 +283,7 @@
         assertUnblocked(vpn, user.start + PKG_UIDS[1]);
 
         // Switch to another app.
-        assertTrue(vpn.setAlwaysOnPackage(PKGS[3], true));
+        assertTrue(vpn.setAlwaysOnPackage(PKGS[3], true, null));
         verify(mNetService).setAllowOnlyVpnForUids(eq(false), aryEq(new UidRange[] {
             new UidRange(user.start, user.start + PKG_UIDS[1] - 1),
             new UidRange(user.start + PKG_UIDS[1] + 1, user.stop)
@@ -297,6 +297,87 @@
     }
 
     @Test
+    public void testLockdownWhitelist() throws Exception {
+        final Vpn vpn = createVpn(primaryUser.id);
+        final UidRange user = UidRange.createForUser(primaryUser.id);
+
+        // Set always-on with lockdown and whitelist app PKGS[2] from lockdown.
+        assertTrue(vpn.setAlwaysOnPackage(PKGS[1], true, Collections.singletonList(PKGS[2])));
+        verify(mNetService).setAllowOnlyVpnForUids(eq(true), aryEq(new UidRange[] {
+                new UidRange(user.start, user.start + PKG_UIDS[1] - 1),
+                new UidRange(user.start + PKG_UIDS[2] + 1, user.stop)
+        }));
+        assertBlocked(vpn, user.start + PKG_UIDS[0], user.start + PKG_UIDS[3]);
+        assertUnblocked(vpn, user.start + PKG_UIDS[1], user.start + PKG_UIDS[2]);
+
+        // Change whitelisted app to PKGS[3].
+        assertTrue(vpn.setAlwaysOnPackage(PKGS[1], true, Collections.singletonList(PKGS[3])));
+        verify(mNetService).setAllowOnlyVpnForUids(eq(false), aryEq(new UidRange[] {
+                new UidRange(user.start + PKG_UIDS[2] + 1, user.stop)
+        }));
+        verify(mNetService).setAllowOnlyVpnForUids(eq(true), aryEq(new UidRange[] {
+                new UidRange(user.start + PKG_UIDS[1] + 1, user.start + PKG_UIDS[3] - 1),
+                new UidRange(user.start + PKG_UIDS[3] + 1, user.stop)
+        }));
+        assertBlocked(vpn, user.start + PKG_UIDS[0], user.start + PKG_UIDS[2]);
+        assertUnblocked(vpn, user.start + PKG_UIDS[1], user.start + PKG_UIDS[3]);
+
+        // Change the VPN app.
+        assertTrue(vpn.setAlwaysOnPackage(PKGS[0], true, Collections.singletonList(PKGS[3])));
+        verify(mNetService).setAllowOnlyVpnForUids(eq(false), aryEq(new UidRange[] {
+                new UidRange(user.start, user.start + PKG_UIDS[1] - 1),
+                new UidRange(user.start + PKG_UIDS[1] + 1, user.start + PKG_UIDS[3] - 1)
+        }));
+        verify(mNetService).setAllowOnlyVpnForUids(eq(true), aryEq(new UidRange[] {
+                new UidRange(user.start, user.start + PKG_UIDS[0] - 1),
+                new UidRange(user.start + PKG_UIDS[0] + 1, user.start + PKG_UIDS[3] - 1)
+        }));
+        assertBlocked(vpn, user.start + PKG_UIDS[1], user.start + PKG_UIDS[2]);
+        assertUnblocked(vpn, user.start + PKG_UIDS[0], user.start + PKG_UIDS[3]);
+
+        // Remove the whitelist.
+        assertTrue(vpn.setAlwaysOnPackage(PKGS[0], true, null));
+        verify(mNetService).setAllowOnlyVpnForUids(eq(false), aryEq(new UidRange[] {
+                new UidRange(user.start + PKG_UIDS[0] + 1, user.start + PKG_UIDS[3] - 1),
+                new UidRange(user.start + PKG_UIDS[3] + 1, user.stop)
+        }));
+        verify(mNetService).setAllowOnlyVpnForUids(eq(true), aryEq(new UidRange[] {
+                new UidRange(user.start + PKG_UIDS[0] + 1, user.stop),
+        }));
+        assertBlocked(vpn, user.start + PKG_UIDS[1], user.start + PKG_UIDS[2],
+                user.start + PKG_UIDS[3]);
+        assertUnblocked(vpn, user.start + PKG_UIDS[0]);
+
+        // Add the whitelist.
+        assertTrue(vpn.setAlwaysOnPackage(PKGS[0], true, Collections.singletonList(PKGS[1])));
+        verify(mNetService).setAllowOnlyVpnForUids(eq(false), aryEq(new UidRange[] {
+                new UidRange(user.start + PKG_UIDS[0] + 1, user.stop)
+        }));
+        verify(mNetService).setAllowOnlyVpnForUids(eq(true), aryEq(new UidRange[] {
+                new UidRange(user.start + PKG_UIDS[0] + 1, user.start + PKG_UIDS[1] - 1),
+                new UidRange(user.start + PKG_UIDS[1] + 1, user.stop)
+        }));
+        assertBlocked(vpn, user.start + PKG_UIDS[2], user.start + PKG_UIDS[3]);
+        assertUnblocked(vpn, user.start + PKG_UIDS[0], user.start + PKG_UIDS[1]);
+
+        // Try whitelisting a package with a comma, should be rejected.
+        assertFalse(vpn.setAlwaysOnPackage(PKGS[0], true, Collections.singletonList("a.b,c.d")));
+
+        // Pass a non-existent packages in the whitelist, they (and only they) should be ignored.
+        // Whitelisted package should change from PGKS[1] to PKGS[2].
+        assertTrue(vpn.setAlwaysOnPackage(PKGS[0], true,
+                Arrays.asList("com.foo.app", PKGS[2], "com.bar.app")));
+        verify(mNetService).setAllowOnlyVpnForUids(eq(false), aryEq(new UidRange[]{
+                new UidRange(user.start + PKG_UIDS[0] + 1, user.start + PKG_UIDS[1] - 1),
+                new UidRange(user.start + PKG_UIDS[1] + 1, user.stop)
+        }));
+        verify(mNetService).setAllowOnlyVpnForUids(eq(true), aryEq(new UidRange[]{
+                new UidRange(user.start + PKG_UIDS[0] + 1, user.start + PKG_UIDS[2] - 1),
+                new UidRange(user.start + PKG_UIDS[2] + 1, user.stop)
+        }));
+    }
+
+    @Test
     public void testLockdownAddingAProfile() throws Exception {
         final Vpn vpn = createVpn(primaryUser.id);
         setMockedUsers(primaryUser);
@@ -310,7 +391,7 @@
         final UidRange profile = UidRange.createForUser(tempProfile.id);
 
         // Set lockdown.
-        assertTrue(vpn.setAlwaysOnPackage(PKGS[3], true));
+        assertTrue(vpn.setAlwaysOnPackage(PKGS[3], true, null));
         verify(mNetService).setAllowOnlyVpnForUids(eq(true), aryEq(new UidRange[] {
             new UidRange(user.start, user.start + PKG_UIDS[3] - 1),
             new UidRange(user.start + PKG_UIDS[3] + 1, user.stop)
@@ -436,7 +517,7 @@
                 .cancelAsUser(anyString(), anyInt(), eq(userHandle));
 
         // Start showing a notification for disconnected once always-on.
-        vpn.setAlwaysOnPackage(PKGS[0], false);
+        vpn.setAlwaysOnPackage(PKGS[0], false, null);
         order.verify(mNotificationManager)
                 .notifyAsUser(anyString(), anyInt(), any(), eq(userHandle));
 
@@ -450,7 +531,7 @@
                 .notifyAsUser(anyString(), anyInt(), any(), eq(userHandle));
 
         // Notification should be cleared after unsetting always-on package.
-        vpn.setAlwaysOnPackage(null, false);
+        vpn.setAlwaysOnPackage(null, false, null);
         order.verify(mNotificationManager).cancelAsUser(anyString(), anyInt(), eq(userHandle));
     }
 
@@ -583,7 +664,9 @@
             doAnswer(invocation -> {
                 final String appName = (String) invocation.getArguments()[0];
                 final int userId = (int) invocation.getArguments()[1];
-                return UserHandle.getUid(userId, packages.get(appName));
+                Integer appId = packages.get(appName);
+                if (appId == null) throw new PackageManager.NameNotFoundException(appName);
+                return UserHandle.getUid(userId, appId);
             }).when(mPackageManager).getPackageUidAsUser(anyString(), anyInt());
         } catch (Exception e) {
         }
diff --git a/tools/processors/view_inspector/src/java/android/processor/view/inspector/AnnotationUtils.java b/tools/processors/view_inspector/src/java/android/processor/view/inspector/AnnotationUtils.java
index fc4cd01..2690ee8 100644
--- a/tools/processors/view_inspector/src/java/android/processor/view/inspector/AnnotationUtils.java
+++ b/tools/processors/view_inspector/src/java/android/processor/view/inspector/AnnotationUtils.java
@@ -16,8 +16,12 @@
 
 package android.processor.view.inspector;
 
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
 import java.util.Map;
 import java.util.Optional;
+import java.util.stream.Collectors;
 
 import javax.annotation.processing.ProcessingEnvironment;
 import javax.lang.model.element.AnnotationMirror;
@@ -102,6 +106,83 @@
     }
 
     /**
+     * Get a typed list of values for an annotation array property by name.
+     *
+     * The returned list will be empty if the value was left at the default.
+     *
+     * @param propertyName The name of the property to search for
+     * @param valueClass The expected class of the property value
+     * @param element The element the annotation is on, used for exceptions
+     * @param annotationMirror An annotation mirror to search for the property
+     * @param <T> The type of the value
+     * @return A list containing the requested types
+     */
+    <T> List<T> typedArrayValuesByName(
+            String propertyName,
+            Class<T> valueClass,
+            Element element,
+            AnnotationMirror annotationMirror) {
+        return untypedArrayValuesByName(propertyName, element, annotationMirror)
+                .stream()
+                .map(annotationValue -> {
+                    final Object value = annotationValue.getValue();
+
+                    if (value == null) {
+                        throw new ProcessingException(
+                                "Unexpected null in array.",
+                                element,
+                                annotationMirror,
+                                annotationValue);
+                    }
+
+                    if (valueClass.isAssignableFrom(value.getClass())) {
+                        return valueClass.cast(value);
+                    } else {
+                        throw new ProcessingException(
+                                String.format(
+                                        "Expected array entry to have type %s, but got %s.",
+                                        valueClass.getCanonicalName(),
+                                        value.getClass().getCanonicalName()),
+                                element,
+                                annotationMirror,
+                                annotationValue);
+                    }
+                })
+                .collect(Collectors.toList());
+    }
+
+    /**
+     * Get a list of values for an annotation array property by name.
+     *
+     * @param propertyName The name of the property to search for
+     * @param element The element the annotation is on, used for exceptions
+     * @param annotationMirror An annotation mirror to search for the property
+     * @return A list of annotation values, empty list if none found
+     */
+    List<AnnotationValue> untypedArrayValuesByName(
+            String propertyName,
+            Element element,
+            AnnotationMirror annotationMirror) {
+        return typedValueByName(propertyName, List.class, element, annotationMirror)
+                .map(untypedValues -> {
+                    List<AnnotationValue> typedValues = new ArrayList<>(untypedValues.size());
+
+                    for (Object untypedValue : untypedValues) {
+                        if (untypedValue instanceof AnnotationValue) {
+                            typedValues.add((AnnotationValue) untypedValue);
+                        } else {
+                            throw new ProcessingException(
+                                    "Unable to convert array entry to AnnotationValue",
+                                    element,
+                                    annotationMirror);
+                        }
+                    }
+
+                    return typedValues;
+                }).orElseGet(Collections::emptyList);
+    }
+
+    /**
      * Get the typed value of an annotation property by name.
      *
      * The returned optional will be empty if the value was left at the default, or if the 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 f1ebb87..6f58893 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
@@ -19,7 +19,9 @@
 import com.squareup.javapoet.ClassName;
 
 import java.util.Collection;
+import java.util.Collections;
 import java.util.HashMap;
+import java.util.List;
 import java.util.Map;
 import java.util.Objects;
 import java.util.Optional;
@@ -92,6 +94,8 @@
         private final Type mType;
         private boolean mAttributeIdInferrableFromR = true;
         private int mAttributeId = 0;
+        private List<IntEnumEntry> mIntEnumEntries;
+        private List<IntFlagEntry> mIntFlagEntries;
 
         public Property(String name, String getter, Type type) {
             mName = Objects.requireNonNull(name, "Name must not be null");
@@ -133,6 +137,40 @@
             return mType;
         }
 
+        /**
+         * Get the mapping for an {@code int} enumeration, if present.
+         *
+         * @return A list of mapping entries, empty if absent
+         */
+        public List<IntEnumEntry> getIntEnumEntries() {
+            if (mIntEnumEntries != null) {
+                return mIntEnumEntries;
+            } else {
+                return Collections.emptyList();
+            }
+        }
+
+        public void setIntEnumEntries(List<IntEnumEntry> intEnumEntries) {
+            mIntEnumEntries = intEnumEntries;
+        }
+
+        /**
+         * Get the mapping of {@code int} flags, if present.
+         *
+         * @return A list of mapping entries, empty if absent
+         */
+        public List<IntFlagEntry> getIntFlagEntries() {
+            if (mIntFlagEntries != null) {
+                return mIntFlagEntries;
+            } else {
+                return Collections.emptyList();
+            }
+        }
+
+        public void setIntFlagEntries(List<IntFlagEntry> intFlagEntries) {
+            mIntFlagEntries = intFlagEntries;
+        }
+
         public enum Type {
             /** Primitive or boxed {@code boolean} */
             BOOLEAN,
@@ -181,6 +219,7 @@
              * An enumeration packed into an {@code int}.
              *
              * @see android.view.inspector.IntEnumMapping
+             * @see IntEnumEntry
              */
             INT_ENUM,
 
@@ -188,8 +227,74 @@
              * Non-exclusive or partially-exclusive flags packed into an {@code int}.
              *
              * @see android.view.inspector.IntFlagMapping
+             * @see IntFlagEntry
              */
             INT_FLAG
         }
     }
+
+    /**
+     * Model one entry in a int enum mapping.
+     *
+     * @see android.view.inspector.IntEnumMapping
+     */
+    public static final class IntEnumEntry {
+        private final String mName;
+        private final int mValue;
+
+        public IntEnumEntry(String name, int value) {
+            mName = Objects.requireNonNull(name, "Name must not be null");
+            mValue = value;
+        }
+
+        public String getName() {
+            return mName;
+        }
+
+        public int getValue() {
+            return mValue;
+        }
+    }
+
+    /**
+     * Model one entry in an int flag mapping.
+     *
+     * @see android.view.inspector.IntFlagMapping
+     */
+    public static final class IntFlagEntry {
+        private final String mName;
+        private final int mTarget;
+        private final int mMask;
+
+        public IntFlagEntry(String name, int target, int mask) {
+            mName = Objects.requireNonNull(name, "Name must not be null");
+            mTarget = target;
+            mMask = mask;
+        }
+
+        public IntFlagEntry(String name, int target) {
+            this(name, target, target);
+        }
+
+        /**
+         * Determine if this entry has a bitmask.
+         *
+         * @return True if the bitmask and target are different, false otherwise
+         */
+        public boolean hasMask() {
+            return mTarget != mMask;
+        }
+
+        public String getName() {
+            return mName;
+        }
+
+        public int getTarget() {
+            return mTarget;
+        }
+
+        public int getMask() {
+            return mMask;
+        }
+    }
 }
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 f666be7..42ae890 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
@@ -16,13 +16,19 @@
 
 package android.processor.view.inspector;
 
+import android.processor.view.inspector.InspectableClassModel.IntEnumEntry;
+import android.processor.view.inspector.InspectableClassModel.IntFlagEntry;
 import android.processor.view.inspector.InspectableClassModel.Property;
 
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Optional;
 import java.util.Set;
 import java.util.regex.Pattern;
 
 import javax.annotation.processing.ProcessingEnvironment;
 import javax.lang.model.element.AnnotationMirror;
+import javax.lang.model.element.AnnotationValue;
 import javax.lang.model.element.Element;
 import javax.lang.model.element.ElementKind;
 import javax.lang.model.element.ExecutableElement;
@@ -63,6 +69,7 @@
 
     /**
      * Set of android and androidx annotation qualified names for colors packed into {@code long}.
+     *
      * @see android.annotation.ColorLong
      */
     private static final String[] COLOR_LONG_ANNOTATION_NAMES = {
@@ -71,7 +78,7 @@
 
     /**
      * @param annotationQualifiedName The qualified name of the annotation to process
-     * @param processingEnv The processing environment from the parent processor
+     * @param processingEnv           The processing environment from the parent processor
      */
     public InspectablePropertyProcessor(
             String annotationQualifiedName,
@@ -109,8 +116,8 @@
      * Check that an element is shaped like a getter.
      *
      * @param element An element that hopefully represents a getter
-     * @throws ProcessingException if the element isn't a getter
      * @return An {@link ExecutableElement} that represents a getter method.
+     * @throws ProcessingException if the element isn't a getter
      */
     private ExecutableElement ensureGetter(Element element) {
         if (element.getKind() != ElementKind.METHOD) {
@@ -144,7 +151,7 @@
             throw new ProcessingException(
                     String.format(
                             "Expected a getter method to take no parameters, "
-                            + "but got %d parameters.",
+                                    + "but got %d parameters.",
                             method.getParameters().size()),
                     element);
         }
@@ -167,10 +174,10 @@
     /**
      * Build a {@link Property} from a getter and an inspectable property annotation.
      *
-     * @param getter An element representing the getter to build from
+     * @param getter     An element representing the getter to build from
      * @param annotation A mirror of an inspectable property-shaped annotation
-     * @throws ProcessingException If the supplied data is invalid and a property cannot be modeled
      * @return A property for the getter and annotation
+     * @throws ProcessingException If the supplied data is invalid and a property cannot be modeled
      */
     private Property buildProperty(ExecutableElement getter, AnnotationMirror annotation) {
         final String name = mAnnotationUtils
@@ -190,16 +197,25 @@
                 .typedValueByName("attributeId", Integer.class, getter, annotation)
                 .ifPresent(property::setAttributeId);
 
+        switch (property.getType()) {
+            case INT_ENUM:
+                property.setIntEnumEntries(processEnumMapping(getter, annotation));
+                break;
+            case INT_FLAG:
+                property.setIntFlagEntries(processFlagMapping(getter, annotation));
+                break;
+        }
+
         return property;
     }
 
     /**
      * Determine the property type from the annotation, return type, or context clues.
      *
-     * @param getter An element representing the getter to build from
+     * @param getter     An element representing the getter to build from
      * @param annotation A mirror of an inspectable property-shaped annotation
      * @return The resolved property type
-     * @throws ProcessingException If the property type cannot be resolved
+     * @throws ProcessingException If the property type cannot be resolved or is invalid
      * @see android.view.inspector.InspectableProperty#valueType()
      */
     private Property.Type determinePropertyType(
@@ -213,10 +229,62 @@
 
         final Property.Type returnType = convertReturnTypeToPropertyType(getter);
 
+        final boolean hasColor = hasColorAnnotation(getter);
+        final Optional<AnnotationValue> enumMapping =
+                mAnnotationUtils.valueByName("enumMapping", annotation);
+        final Optional<AnnotationValue> flagMapping =
+                mAnnotationUtils.valueByName("flagMapping", annotation);
+
+        if (returnType != Property.Type.INT) {
+            enumMapping.ifPresent(value -> {
+                throw new ProcessingException(
+                        String.format(
+                                "Can only use enumMapping on int types, got %s.",
+                                returnType.toString().toLowerCase()),
+                        getter,
+                        annotation,
+                        value);
+            });
+            flagMapping.ifPresent(value -> {
+                throw new ProcessingException(
+                        String.format(
+                                "Can only use flagMapping on int types, got %s.",
+                                returnType.toString().toLowerCase()),
+                        getter,
+                        annotation,
+                        value);
+            });
+        }
+
         switch (valueType) {
             case "INFERRED":
-                if (hasColorAnnotation(getter)) {
+                if (hasColor) {
+                    enumMapping.ifPresent(value -> {
+                        throw new ProcessingException(
+                                "Cannot use enumMapping on a color type.",
+                                getter,
+                                annotation,
+                                value);
+                    });
+                    flagMapping.ifPresent(value -> {
+                        throw new ProcessingException(
+                                "Cannot use flagMapping on a color type.",
+                                getter,
+                                annotation,
+                                value);
+                    });
                     return Property.Type.COLOR;
+                } else if (enumMapping.isPresent()) {
+                    flagMapping.ifPresent(value -> {
+                        throw new ProcessingException(
+                                "Cannot use flagMapping and enumMapping simultaneously.",
+                                getter,
+                                annotation,
+                                value);
+                    });
+                    return Property.Type.INT_ENUM;
+                } else if (flagMapping.isPresent()) {
+                    return Property.Type.INT_FLAG;
                 } else {
                     return returnType;
                 }
@@ -235,17 +303,14 @@
                                 annotation);
                 }
             case "GRAVITY":
-                if (returnType == Property.Type.INT) {
-                    return Property.Type.GRAVITY;
-                } else {
-                    throw new ProcessingException(
-                            String.format("Gravity must be an integer, got %s", returnType),
-                            getter,
-                            annotation);
-                }
+                requirePackedIntToReturnInt("Gravity", returnType, getter, annotation);
+                return Property.Type.GRAVITY;
             case "INT_ENUM":
+                requirePackedIntToReturnInt("IntEnum", returnType, getter, annotation);
+                return Property.Type.INT_ENUM;
             case "INT_FLAG":
-                throw new ProcessingException("Not implemented", getter, annotation);
+                requirePackedIntToReturnInt("IntFlag", returnType, getter, annotation);
+                return Property.Type.INT_FLAG;
             default:
                 throw new ProcessingException(
                         String.format("Unknown value type enumeration value: %s", valueType),
@@ -258,8 +323,8 @@
      * Get a property type from the return type of a getter.
      *
      * @param getter The getter to extract the return type of
-     * @throws ProcessingException If the return type is not a primitive or an object
      * @return The property type returned by the getter
+     * @throws ProcessingException If the return type is not a primitive or an object
      */
     private Property.Type convertReturnTypeToPropertyType(ExecutableElement getter) {
         final TypeMirror returnType = getter.getReturnType();
@@ -295,6 +360,31 @@
     }
 
     /**
+     * Require that a value type packed into an integer be on a getter that returns an int.
+     *
+     * @param typeName   The name of the type to use in the exception
+     * @param returnType The return type of the getter to check
+     * @param getter     The getter, to use in the exception
+     * @param annotation The annotation, to use in the exception
+     * @throws ProcessingException If the return type is not an int
+     */
+    private static void requirePackedIntToReturnInt(
+            String typeName,
+            Property.Type returnType,
+            ExecutableElement getter,
+            AnnotationMirror annotation) {
+        if (returnType != Property.Type.INT) {
+            throw new ProcessingException(
+                    String.format(
+                            "%s can only be defined on a method that returns int, got %s.",
+                            typeName,
+                            returnType.toString().toLowerCase()),
+                    getter,
+                    annotation);
+        }
+    }
+
+    /**
      * Determine if a getter is annotated with color annotation matching its return type.
      *
      * Note that an {@code int} return value annotated with {@link android.annotation.ColorLong} is
@@ -303,7 +393,6 @@
      *
      * @param getter The getter to query
      * @return True if the getter has a color annotation, false otherwise
-     *
      */
     private boolean hasColorAnnotation(ExecutableElement getter) {
         switch (unboxType(getter.getReturnType())) {
@@ -353,6 +442,117 @@
     }
 
     /**
+     * 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 IntEnumEntry} objects. Further validation should be handled elsewhere
+     *
+     * @see android.view.inspector.IntEnumMapping
+     * @see android.view.inspector.InspectableProperty#enumMapping()
+     * @param getter The getter of the property, used for exceptions
+     * @param annotation The {@link android.view.inspector.InspectableProperty} annotation to
+     *                   extract enum mapping values from.
+     * @return A list of int enum entries, in the order specified in source
+     * @throws ProcessingException if mapping doesn't exist or is invalid
+     */
+    private List<IntEnumEntry> processEnumMapping(
+            ExecutableElement getter,
+            AnnotationMirror annotation) {
+        List<AnnotationMirror> enumAnnotations = mAnnotationUtils.typedArrayValuesByName(
+                "enumMapping", AnnotationMirror.class, getter, annotation);
+        List<IntEnumEntry> enumEntries = new ArrayList<>(enumAnnotations.size());
+
+        if (enumAnnotations.isEmpty()) {
+            throw new ProcessingException(
+                    "Encountered an empty array for enumMapping", getter, annotation);
+        }
+
+        for (AnnotationMirror enumAnnotation : enumAnnotations) {
+            final String name = mAnnotationUtils.typedValueByName(
+                    "name", String.class, getter, enumAnnotation)
+                    .orElseThrow(() -> {
+                        throw new ProcessingException(
+                                "Name is required for @EnumMap",
+                                getter,
+                                enumAnnotation);
+                    });
+
+            final int value = mAnnotationUtils.typedValueByName(
+                    "value", Integer.class, getter, enumAnnotation)
+                    .orElseThrow(() -> {
+                        throw new ProcessingException(
+                                "Value is required for @EnumMap",
+                                getter,
+                                enumAnnotation);
+                    });
+
+            enumEntries.add(new IntEnumEntry(name, value));
+        }
+
+        return enumEntries;
+    }
+
+    /**
+     * 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 IntFlagEntry} objects. Further validation should be handled elsewhere
+     *
+     * @see android.view.inspector.IntFlagMapping
+     * @see android.view.inspector.InspectableProperty#flagMapping()
+     * @param getter The getter of the property, used for exceptions
+     * @param annotation The {@link android.view.inspector.InspectableProperty} annotation to
+     *                   extract flag mapping values from.
+     * @return A list of int flags entries, in the order specified in source
+     * @throws ProcessingException if mapping doesn't exist or is invalid
+     */
+    private List<IntFlagEntry> processFlagMapping(
+            ExecutableElement getter,
+            AnnotationMirror annotation) {
+        List<AnnotationMirror> flagAnnotations = mAnnotationUtils.typedArrayValuesByName(
+                "flagMapping", AnnotationMirror.class, getter, annotation);
+        List<IntFlagEntry> flagEntries = new ArrayList<>(flagAnnotations.size());
+
+        if (flagAnnotations.isEmpty()) {
+            throw new ProcessingException(
+                    "Encountered an empty array for flagMapping", getter, annotation);
+        }
+
+        for (AnnotationMirror flagAnnotation : flagAnnotations) {
+            final String name = mAnnotationUtils.typedValueByName(
+                    "name", String.class, getter, flagAnnotation)
+                    .orElseThrow(() -> {
+                        throw new ProcessingException(
+                                "Name is required for @FlagMap",
+                                getter,
+                                flagAnnotation);
+                    });
+
+            final int target = mAnnotationUtils.typedValueByName(
+                    "target", Integer.class, getter, flagAnnotation)
+                    .orElseThrow(() -> {
+                        throw new ProcessingException(
+                                "Target is required for @FlagMap",
+                                getter,
+                                flagAnnotation);
+                    });
+
+            final Optional<Integer> mask = mAnnotationUtils.typedValueByName(
+                    "mask", Integer.class, getter, flagAnnotation);
+
+            if (mask.isPresent()) {
+                flagEntries.add(new IntFlagEntry(name, target, mask.get()));
+            } else {
+                flagEntries.add(new IntFlagEntry(name, target));
+            }
+        }
+
+        return flagEntries;
+    }
+
+    /**
      * Determine if a {@link TypeMirror} is a boxed or unboxed boolean.
      *
      * @param type The type mirror to check
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 dd4d8f5..7b04645 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
@@ -16,6 +16,8 @@
 
 package android.processor.view.inspector;
 
+import android.processor.view.inspector.InspectableClassModel.IntEnumEntry;
+import android.processor.view.inspector.InspectableClassModel.IntFlagEntry;
 import android.processor.view.inspector.InspectableClassModel.Property;
 
 import com.squareup.javapoet.ClassName;
@@ -69,6 +71,18 @@
             "android.view.inspector", "PropertyReader");
 
     /**
+     * The class name of {@link android.view.inspector.IntEnumMapping}.
+     */
+    private static final ClassName INT_ENUM_MAPPING = ClassName.get(
+            "android.view.inspector", "IntEnumMapping");
+
+    /**
+     * The class name of {@link android.view.inspector.IntFlagMapping}.
+     */
+    private static final ClassName INT_FLAG_MAPPING = ClassName.get(
+            "android.view.inspector", "IntFlagMapping");
+
+    /**
      * The {@code mPropertiesMapped} field.
      */
     private static final FieldSpec M_PROPERTIES_MAPPED = FieldSpec
@@ -248,13 +262,13 @@
         final MethodSpec.Builder builder =  MethodSpec.methodBuilder("readProperties")
                 .addAnnotation(Override.class)
                 .addModifiers(Modifier.PUBLIC)
-                .addParameter(model.getClassName(), "inspectable")
+                .addParameter(model.getClassName(), "node")
                 .addParameter(PROPERTY_READER, "propertyReader")
                 .addCode(generatePropertyMapInitializationCheck());
 
         for (PropertyIdField propertyIdField : propertyIdFields) {
             builder.addStatement(
-                    "propertyReader.read$L($N, inspectable.$L())",
+                    "propertyReader.read$L($N, node.$L())",
                     methodSuffixForPropertyType(propertyIdField.mProperty.getType()),
                     propertyIdField.mFieldSpec,
                     propertyIdField.mProperty.getGetter());
@@ -286,21 +300,22 @@
             if (property.getAttributeId() == ID_NULL) {
                 builder.add("$L", ID_NULL);
             } else {
-                builder.add("$L", String.format("0x%08x", property.getAttributeId()));
+                builder.add("$L", hexLiteral(property.getAttributeId()));
             }
         }
 
         switch (property.getType()) {
             case INT_ENUM:
-                throw new RuntimeException("IntEnumMapping generation not implemented");
+                builder.add(",$W");
+                builder.add(generateIntEnumMappingBuilder(property.getIntEnumEntries()));
+                break;
             case INT_FLAG:
-                throw new RuntimeException("IntFlagMapping generation not implemented");
-            default:
-                builder.add(")");
+                builder.add(",$W");
+                builder.add(generateIntFlagMappingBuilder(property.getIntFlagEntries()));
                 break;
         }
 
-        return builder.build();
+        return builder.add(")").build();
     }
 
     /**
@@ -327,6 +342,56 @@
     }
 
     /**
+     * Generate an invocation of {@link android.view.inspector.IntEnumMapping.Builder}.
+     *
+     * <pre>
+     *      new IntEnumMapping.Builder()
+     *          .addValue("ONE", 1)
+     *          .build()
+     * </pre>
+     *
+     * @return A codeblock containing the an int enum mapping builder
+     */
+    private CodeBlock generateIntEnumMappingBuilder(List<IntEnumEntry> intEnumEntries) {
+        final ArrayList<IntEnumEntry> sortedEntries = new ArrayList<>(intEnumEntries);
+        sortedEntries.sort(Comparator.comparing(IntEnumEntry::getValue));
+
+        final CodeBlock.Builder builder = CodeBlock.builder()
+                .add("new $T()$>", INT_ENUM_MAPPING.nestedClass("Builder"));
+
+        for (IntEnumEntry entry : sortedEntries) {
+            builder.add("\n.addValue($S, $L)", entry.getName(), entry.getValue());
+        }
+
+        return builder.add("\n.build()$<").build();
+    }
+
+    private CodeBlock generateIntFlagMappingBuilder(List<IntFlagEntry> intFlagEntries) {
+        final ArrayList<IntFlagEntry> sortedEntries = new ArrayList<>(intFlagEntries);
+        sortedEntries.sort(Comparator.comparing(IntFlagEntry::getName));
+
+        final CodeBlock.Builder builder = CodeBlock.builder()
+                .add("new $T()$>", INT_FLAG_MAPPING.nestedClass("Builder"));
+
+        for (IntFlagEntry entry : sortedEntries) {
+            if (entry.hasMask()) {
+                builder.add(
+                        "\n.addFlag($S, $L, $L)",
+                        entry.getName(),
+                        hexLiteral(entry.getTarget()),
+                        hexLiteral(entry.getMask()));
+            } else {
+                builder.add(
+                        "\n.addFlag($S, $L)",
+                        entry.getName(),
+                        hexLiteral(entry.getTarget()));
+            }
+        }
+
+        return builder.add("\n.build()$<").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
@@ -385,6 +450,10 @@
         }
     }
 
+    private static String hexLiteral(int value) {
+        return String.format("0x%08x", value);
+    }
+
     /**
      * Value class that holds a {@link Property} and a {@link FieldSpec} for that property.
      */
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 455f5b0..01d9430 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
@@ -32,6 +32,7 @@
 import javax.lang.model.SourceVersion;
 import javax.lang.model.element.Element;
 import javax.lang.model.element.ElementKind;
+import javax.lang.model.element.Modifier;
 import javax.lang.model.element.TypeElement;
 
 
@@ -118,6 +119,12 @@
                 break;
             }
 
+            final Set<Modifier> classModifiers = classElement.get().getModifiers();
+
+            if (classModifiers.contains(Modifier.PRIVATE)) {
+                fail("Enclosing class cannot be private", element);
+            }
+
             final InspectableClassModel model = modelMap.computeIfAbsent(
                     classElement.get().getQualifiedName().toString(),
                     k -> new InspectableClassModel(ClassName.get(classElement.get())));
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 b0775dc..f6d8bb0 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
@@ -16,11 +16,13 @@
 
 package android.processor.view.inspector;
 
-import android.processor.view.inspector.InspectableClassModel.Property;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.fail;
 
-import static junit.framework.Assert.assertEquals;
-import static junit.framework.Assert.assertNotNull;
-import static junit.framework.Assert.fail;
+import android.processor.view.inspector.InspectableClassModel.IntEnumEntry;
+import android.processor.view.inspector.InspectableClassModel.IntFlagEntry;
+import android.processor.view.inspector.InspectableClassModel.Property;
 
 import com.google.common.base.Charsets;
 import com.google.common.io.Resources;
@@ -31,6 +33,7 @@
 
 import java.io.IOException;
 import java.net.URL;
+import java.util.Arrays;
 import java.util.Optional;
 
 /**
@@ -40,7 +43,7 @@
     private static final String RESOURCE_PATH_TEMPLATE =
             "android/processor/view/inspector/InspectionCompanionGeneratorTest/%s.java.txt";
     private static final ClassName TEST_CLASS_NAME =
-            ClassName.get("com.android.inspectable", "TestInspectable");
+            ClassName.get("com.android.node", "TestNode");
     private InspectableClassModel mModel;
     private InspectionCompanionGenerator mGenerator;
 
@@ -59,7 +62,7 @@
     @Test
     public void testNestedClass() {
         mModel = new InspectableClassModel(
-                ClassName.get("com.android.inspectable", "Outer", "Inner"));
+                ClassName.get("com.android.node", "Outer", "Inner"));
         assertGeneratedFileEquals("NestedClass");
     }
 
@@ -105,6 +108,42 @@
         assertGeneratedFileEquals("SuppliedAttributeId");
     }
 
+    @Test
+    public void testIntEnum() {
+        final Property property = new Property(
+                "intEnumProperty",
+                "getIntEnumProperty",
+                Property.Type.INT_ENUM);
+
+        property.setIntEnumEntries(Arrays.asList(
+                new IntEnumEntry("THREE", 3),
+                new IntEnumEntry("TWO", 2),
+                new IntEnumEntry("ONE", 1)));
+
+        mModel.putProperty(property);
+
+        assertGeneratedFileEquals("IntEnum");
+    }
+
+    @Test
+    public void testIntFlag() {
+        final Property property = new Property(
+                "intFlag",
+                "getIntFlag",
+                Property.Type.INT_FLAG);
+
+        property.setAttributeIdInferrableFromR(false);
+        property.setIntFlagEntries(Arrays.asList(
+                new IntFlagEntry("TURBO", 0x1, 0x3),
+                new IntFlagEntry("OVERDRIVE", 0x2, 0x3),
+                new IntFlagEntry("WARP", 0x4)
+        ));
+
+        mModel.putProperty(property);
+
+        assertGeneratedFileEquals("IntFlag");
+    }
+
     private Property addProperty(String name, String getter, Property.Type type) {
         final Property property = new Property(name, getter, type);
         mModel.putProperty(property);
diff --git a/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/IntEnum.java.txt b/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/IntEnum.java.txt
new file mode 100644
index 0000000..764aa8b
--- /dev/null
+++ b/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/IntEnum.java.txt
@@ -0,0 +1,45 @@
+package com.android.node;
+
+import android.R;
+import android.view.inspector.InspectionCompanion;
+import android.view.inspector.IntEnumMapping;
+import android.view.inspector.PropertyMapper;
+import android.view.inspector.PropertyReader;
+import java.lang.Override;
+
+/**
+ * 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> {
+    /**
+     * Set by {@link #mapProperties(PropertyMapper)} once properties have been mapped.
+     */
+    private boolean mPropertiesMapped = false;
+
+    /**
+     * Property ID of {@code intEnumProperty}.
+     */
+    private int mIntEnumPropertyId;
+
+    @Override
+    public void mapProperties(PropertyMapper propertyMapper) {
+        mIntEnumPropertyId = propertyMapper.mapIntEnum("intEnumProperty", R.attr.intEnumProperty,
+                new IntEnumMapping.Builder()
+                    .addValue("ONE", 1)
+                    .addValue("TWO", 2)
+                    .addValue("THREE", 3)
+                    .build());
+        mPropertiesMapped = true;
+    }
+
+    @Override
+    public void readProperties(TestNode node, PropertyReader propertyReader) {
+        if (!mPropertiesMapped) {
+            throw new InspectionCompanion.UninitializedPropertyMapException();
+        }
+        propertyReader.readIntEnum(mIntEnumPropertyId, node.getIntEnumProperty());
+    }
+}
diff --git a/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/IntFlag.java.txt b/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/IntFlag.java.txt
new file mode 100644
index 0000000..75f2813
--- /dev/null
+++ b/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/IntFlag.java.txt
@@ -0,0 +1,43 @@
+package com.android.node;
+
+import android.view.inspector.InspectionCompanion;
+import android.view.inspector.IntFlagMapping;
+import android.view.inspector.PropertyMapper;
+import android.view.inspector.PropertyReader;
+import java.lang.Override;
+
+/**
+ * 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> {
+    /**
+     * Set by {@link #mapProperties(PropertyMapper)} once properties have been mapped.
+     */
+    private boolean mPropertiesMapped = false;
+
+    /**
+     * Property ID of {@code intFlag}.
+     */
+    private int mIntFlagId;
+
+    @Override
+    public void mapProperties(PropertyMapper propertyMapper) {
+        mIntFlagId = propertyMapper.mapIntFlag("intFlag", 0, new IntFlagMapping.Builder()
+                    .addFlag("OVERDRIVE", 0x00000002, 0x00000003)
+                    .addFlag("TURBO", 0x00000001, 0x00000003)
+                    .addFlag("WARP", 0x00000004)
+                    .build());
+        mPropertiesMapped = true;
+    }
+
+    @Override
+    public void readProperties(TestNode node, PropertyReader propertyReader) {
+        if (!mPropertiesMapped) {
+            throw new InspectionCompanion.UninitializedPropertyMapException();
+        }
+        propertyReader.readIntFlag(mIntFlagId, node.getIntFlag());
+    }
+}
diff --git a/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/NestedClass.java.txt b/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/NestedClass.java.txt
index 2fc242c..0cac462 100644
--- a/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/NestedClass.java.txt
+++ b/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/NestedClass.java.txt
@@ -1,4 +1,4 @@
-package com.android.inspectable;
+package com.android.node;
 
 import android.view.inspector.InspectionCompanion;
 import android.view.inspector.PropertyMapper;
@@ -23,7 +23,7 @@
     }
 
     @Override
-    public void readProperties(Outer.Inner inspectable, PropertyReader propertyReader) {
+    public void readProperties(Outer.Inner node, PropertyReader propertyReader) {
         if (!mPropertiesMapped) {
             throw new InspectionCompanion.UninitializedPropertyMapException();
         }
diff --git a/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/NoAttributeId.java.txt b/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/NoAttributeId.java.txt
index 23d0f78..ce0f867 100644
--- a/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/NoAttributeId.java.txt
+++ b/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/NoAttributeId.java.txt
@@ -1,4 +1,4 @@
-package com.android.inspectable;
+package com.android.node;
 
 import android.view.inspector.InspectionCompanion;
 import android.view.inspector.PropertyMapper;
@@ -6,12 +6,12 @@
 import java.lang.Override;
 
 /**
- * Inspection companion for {@link TestInspectable}.
+ * 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 TestInspectable$$InspectionCompanion implements InspectionCompanion<TestInspectable> {
+public final class TestNode$$InspectionCompanion implements InspectionCompanion<TestNode> {
     /**
      * Set by {@link #mapProperties(PropertyMapper)} once properties have been mapped.
      */
@@ -29,10 +29,10 @@
     }
 
     @Override
-    public void readProperties(TestInspectable inspectable, PropertyReader propertyReader) {
+    public void readProperties(TestNode node, PropertyReader propertyReader) {
         if (!mPropertiesMapped) {
             throw new InspectionCompanion.UninitializedPropertyMapException();
         }
-        propertyReader.readInt(mNoAttributePropertyId, inspectable.getNoAttributeProperty());
+        propertyReader.readInt(mNoAttributePropertyId, node.getNoAttributeProperty());
     }
 }
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
index 1142548..f7357fe 100644
--- 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
@@ -1,4 +1,4 @@
-package com.android.inspectable;
+package com.android.node;
 
 import android.view.inspector.InspectionCompanion;
 import android.view.inspector.PropertyMapper;
@@ -7,12 +7,12 @@
 import java.lang.String;
 
 /**
- * Inspection companion for {@link TestInspectable}.
+ * 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 TestInspectable$$InspectionCompanion implements InspectionCompanion<TestInspectable> {
+public final class TestNode$$InspectionCompanion implements InspectionCompanion<TestNode> {
     /**
      * Set by {@link #mapProperties(PropertyMapper)} once properties have been mapped.
      */
@@ -24,7 +24,7 @@
     }
 
     @Override
-    public void readProperties(TestInspectable inspectable, PropertyReader propertyReader) {
+    public void readProperties(TestNode node, PropertyReader propertyReader) {
         if (!mPropertiesMapped) {
             throw new InspectionCompanion.UninitializedPropertyMapException();
         }
diff --git a/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/SimpleProperties.java.txt b/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/SimpleProperties.java.txt
index 57eb080..dfc1bce 100644
--- a/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/SimpleProperties.java.txt
+++ b/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/SimpleProperties.java.txt
@@ -1,4 +1,4 @@
-package com.android.inspectable;
+package com.android.node;
 
 import android.R;
 import android.view.inspector.InspectionCompanion;
@@ -7,12 +7,12 @@
 import java.lang.Override;
 
 /**
- * Inspection companion for {@link TestInspectable}.
+ * 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 TestInspectable$$InspectionCompanion implements InspectionCompanion<TestInspectable> {
+public final class TestNode$$InspectionCompanion implements InspectionCompanion<TestNode> {
     /**
      * Set by {@link #mapProperties(PropertyMapper)} once properties have been mapped.
      */
@@ -90,20 +90,20 @@
     }
 
     @Override
-    public void readProperties(TestInspectable inspectable, PropertyReader propertyReader) {
+    public void readProperties(TestNode node, PropertyReader propertyReader) {
         if (!mPropertiesMapped) {
             throw new InspectionCompanion.UninitializedPropertyMapException();
         }
-        propertyReader.readBoolean(mBooleanId, inspectable.getBoolean());
-        propertyReader.readByte(mByteId, inspectable.getByte());
-        propertyReader.readChar(mCharId, inspectable.getChar());
-        propertyReader.readColor(mColorId, inspectable.getColor());
-        propertyReader.readDouble(mDoubleId, inspectable.getDouble());
-        propertyReader.readFloat(mFloatId, inspectable.getFloat());
-        propertyReader.readGravity(mGravityId, inspectable.getGravity());
-        propertyReader.readInt(mIntId, inspectable.getInt());
-        propertyReader.readLong(mLongId, inspectable.getLong());
-        propertyReader.readObject(mObjectId, inspectable.getObject());
-        propertyReader.readShort(mShortId, inspectable.getShort());
+        propertyReader.readBoolean(mBooleanId, node.getBoolean());
+        propertyReader.readByte(mByteId, node.getByte());
+        propertyReader.readChar(mCharId, node.getChar());
+        propertyReader.readColor(mColorId, node.getColor());
+        propertyReader.readDouble(mDoubleId, node.getDouble());
+        propertyReader.readFloat(mFloatId, node.getFloat());
+        propertyReader.readGravity(mGravityId, node.getGravity());
+        propertyReader.readInt(mIntId, node.getInt());
+        propertyReader.readLong(mLongId, node.getLong());
+        propertyReader.readObject(mObjectId, node.getObject());
+        propertyReader.readShort(mShortId, node.getShort());
     }
 }
diff --git a/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/SuppliedAttributeId.java.txt b/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/SuppliedAttributeId.java.txt
index 6b6ce21..d72cdd5 100644
--- a/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/SuppliedAttributeId.java.txt
+++ b/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/SuppliedAttributeId.java.txt
@@ -1,4 +1,4 @@
-package com.android.inspectable;
+package com.android.node;
 
 import android.view.inspector.InspectionCompanion;
 import android.view.inspector.PropertyMapper;
@@ -6,12 +6,12 @@
 import java.lang.Override;
 
 /**
- * Inspection companion for {@link TestInspectable}.
+ * 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 TestInspectable$$InspectionCompanion implements InspectionCompanion<TestInspectable> {
+public final class TestNode$$InspectionCompanion implements InspectionCompanion<TestNode> {
     /**
      * Set by {@link #mapProperties(PropertyMapper)} once properties have been mapped.
      */
@@ -30,10 +30,10 @@
     }
 
     @Override
-    public void readProperties(TestInspectable inspectable, PropertyReader propertyReader) {
+    public void readProperties(TestNode node, PropertyReader propertyReader) {
         if (!mPropertiesMapped) {
             throw new InspectionCompanion.UninitializedPropertyMapException();
         }
-        propertyReader.readInt(mSuppliedAttributePropertyId, inspectable.getSuppliedAttributeProperty());
+        propertyReader.readInt(mSuppliedAttributePropertyId, node.getSuppliedAttributeProperty());
     }
 }
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index 0668239..e5733ed 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -1221,7 +1221,6 @@
      * @param scanResults a list of scanResult that represents the BSSID
      * @return List that consists of {@link WifiConfiguration} and corresponding scanResults per
      * network type({@link #PASSPOINT_HOME_NETWORK} and {@link #PASSPOINT_ROAMING_NETWORK}).
-     * @throws UnsupportedOperationException if Passpoint is not enabled on the device.
      * @hide
      */
     @SystemApi
@@ -1264,7 +1263,6 @@
      *
      * @param scanResults a list of ScanResult
      * @return Map that consists {@link OsuProvider} and a list of matching {@link ScanResult}
-     * @throws UnsupportedOperationException if Passpoint is not enabled on the device.
      * @hide
      */
     @SystemApi
@@ -1291,7 +1289,6 @@
      *
      * @param osuProviders a set of {@link OsuProvider}
      * @return Map that consists of {@link OsuProvider} and matching {@link PasspointConfiguration}.
-     * @throws UnsupportedOperationException if Passpoint is not enabled on the device.
      * @hide
      */
     @SystemApi
@@ -1720,8 +1717,8 @@
      * FQDN, the new configuration will replace the existing configuration.
      *
      * @param config The Passpoint configuration to be added
-     * @throws IllegalArgumentException if configuration is invalid
-     * @throws UnsupportedOperationException if Passpoint is not enabled on the device.
+     * @throws IllegalArgumentException if configuration is invalid or Passpoint is not enabled on
+     *                                  the device.
      */
     public void addOrUpdatePasspointConfiguration(PasspointConfiguration config) {
         try {
@@ -1737,8 +1734,8 @@
      * Remove the Passpoint configuration identified by its FQDN (Fully Qualified Domain Name).
      *
      * @param fqdn The FQDN of the Passpoint configuration to be removed
-     * @throws IllegalArgumentException if no configuration is associated with the given FQDN.
-     * @throws UnsupportedOperationException if Passpoint is not enabled on the device.
+     * @throws IllegalArgumentException if no configuration is associated with the given FQDN or
+     *                                  Passpoint is not enabled on the device.
      * @deprecated This is no longer supported.
      */
     @Deprecated
@@ -1762,7 +1759,6 @@
      * An empty list will be returned when no configurations are installed.
      *
      * @return A list of {@link PasspointConfiguration}
-     * @throws UnsupportedOperationException if Passpoint is not enabled on the device.
      * @deprecated This is no longer supported.
      */
     @Deprecated